废话不多说,我们先来看几个例子:

1.

setTimeout(function(){console.log(1);}, 0); console.log(2);

result:  2 1
 
2.
  console.log(100); setTimeout(function(){console.log(200);},0); console.log(300); 
result:  100 300 200
 
3.

 function foo(){
console.log('first');
setTimeout((function(){console.log('second')}),0);
}
for(var i=0; i<10; i++){
foo();
}

result:  先全部输出first,然后全部输出second

4.

console.log(10); setTimeout(function(){console.log(20);},0); while(true){console.log(30);}

result:  执行的结果是10 30 , 然后浏览器假死,20永远不会被打印出来

5.
 console.log(10);
setTimeout(function(){while(true){console.log(30);}},0);
setTimeout(function(){console.log(20);},10);
console.log(40);

result:  执行的结果: 10,40,30, 然后浏览器假死,20永远不会被打印出来

看完上面的几个例子后,是不是觉得,我天,666. 长见识了!!!

其实,这里展现的就是javascript的单线程机制。JavaScript语言的一大特点就是单线程,换句话说就是,同一个时间只能做一件事。那么,JavaScript为啥不能有多个线程呢?这样能提高效率啊。JavaScript作为浏览器脚本语言,它的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,如果JavaScript同时有了两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,那么这时浏览器到底应该以哪个线程为准?所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

javascript中的所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

"任务队列"是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。主线程的读取过程基本上是自动的,只要执行栈一清空,"任务队列"上第一位的事件就自动进入主线程。

浏览器中很多行为是异步的,例如:鼠标点击事件、窗口大小拖拉事件、定时器触发事件、XMLHttpRequest完成回调等。当一个异步事件发生的时候,它就进入事件队列。例如,浏览器当前正在忙于处理onclick事件,这时另外一个事件发生了(如:window onSize),这个异步事件就被放入"任务队列"等待处理,只有前面的处理完毕了,空闲了才会执行这个事件。setTimeout也是一样,当调用的时候,js引擎会启动定时器timer,大约xxms以后执行xxx,当定时器时间到,该任务才会进入主线程等待处理(浏览器不忙的时候才会真正执行)。

setTimeout(fn,0),它的的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。这里有一点值得注意的地方是,setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。

那么,setTimeout(fn,0)到底有什么用呢?

它的神奇之处是改变了代码流程,把fn的执行放到了等待当前的代码执行完毕再执行。所以我们常把它用来改变代码执行的顺序。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

下面看一个web worker多线程的例子:

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<p>Fibonacci数列是比较经典的数学规律,它以递归的方法定义:</p>
<p>F0 = 0</p>
<p>F1 = 1</p>
<p>Fn = F(n-1) + F(n-2) (n>=2, n属于整数)</p> <script type="text/javascript">
window.onload = function(){
var worker = new Worker('fibonacci.js');
worker.postMessage(40);
var timer = (new Date()).valueOf();
console.log('开始计算:n=40','当前时间:'+timer);
worker.onmessage = function(e){
var timer2 = (new Date()).valueOf();
console.log('计算结果:'+ e.data+' 计算完成时间:'+timer2+"计算用时:"+(timer2 - timer));
}; setTimeout(function(){
console.log('由于js的单线程机制,本来由于浏览器假死,定时器函数在计算数列时不会执行,' +
'但这里用了workers多线程,前面计算fibonacci数列浏览器并没有假死,' +
'所以定时器函数在计算数列时执行了,但还是在主线程代码执行完成之后',
'当前执行时间:'+(new Date()).valueOf());
}); // js主线程
console.log("我在计算数列的时候执行了","当前时间:"+(new Date()).valueOf());
}; </script>
</body>
</html>
fibonacci.js:
 /**
* Created by jessietang on 12/8/2016.
*/
//此线程用来计算fibonacci数列
var fibonacci = function(n){
return n<2 ? n : arguments.callee(n-1) + arguments.callee(n-2);
};
onmessage = function(e){
var n = parseInt(e.data,10);
postMessage(fibonacci(n));
};

输出结果:

开始计算:n=40 当前时间:1481191712748
我在计算数列的时候执行了 当前时间:1481191712749
由于js的单线程机制,本来本来由于浏览器假死,定时器函数在计算数列时不会执行,但这里用了workers多线程,前面计算fibonacci数列浏览器并没有假死,所以定时器函数在计算数列时执行了,但还是在主线程代码执行完成之后 当前执行时间:1481191712770
计算结果:102334155 计算完成时间:1481191724690计算用时:11942
相信看完输出结果就大致明白了。
 
说明:此篇博客借鉴了阮一峰老师的这篇博客的一些理论:http://www.ruanyifeng.com/blog/2014/10/event-loop.html。个人理解,纯属瞎玩儿,欢迎提出不同意见一起讨论

我理解的javascript单线程机制的更多相关文章

  1. 从setTimeout谈JavaScript运行机制

    从setTimeout说起 众所周知,JavaScript是单线程的编程,什么是单线程,就是说同一时间JavaScript只能执行一段代码,如果这段代码要执行很长时间,那么之后的代码只能尽情地等待它执 ...

  2. JavaScript运行机制与setTimeout

    前段时间,老板交给了我一个任务:通过setTimeout来延后网站某些复杂资源的请求.正好借此机会,将JavaScript运行机制和setTimeout重新认真思考一遍,并将我对它们的理解整理如下. ...

  3. 浏览器UI多线程及JavaScript单线程运行机制的理解

    在上一篇博客中,我对jQuery的队列(queue)机制和动画(animate)机制做了一个深入的解析,在animate的实现机制其核心是依靠queue来完成的,其中在jQuery的链式调用部分,之前 ...

  4. 我想这次我真的理解了 JavaScript 的单线程机制

    今天面试的时候被问到一个问题,是关于 JS 异步的.当时我脑海中闪过了一个单线程的概念,但却没有把真正的原理阐述清楚.所以回来特意重新回顾了前面单线程和异步相关的一些知识点. 虽然之前学习的时候也接触 ...

  5. 深入理解JavaScript运行机制

    深入理解JavaScript运行机制 前言 本文是写作在给团队新人培训之际,所以其实本文的受众是对JavaScript的运行机制不了解或了解起来有困难的小伙伴.也就是说,其实真正的原理和本文阐述的并不 ...

  6. JavaScript可否多线程? 深入理解JavaScript定时机制

    JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如 setTimeout( ...

  7. 深入理解JavaScript定时机制和定时器注意问题

    容易欺骗别人感情的JavaScript定时器 JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不 ...

  8. 阅读《深入理解JavaScript定时机制》

    鸟哥的这篇<深入理解JavaScript定时机制>从javascript线程角度分析了setTimeout和setInterval两个定时触发器的实现原理. 看完的体验就是主要要记住两点: ...

  9. Javascript引擎单线程机制及setTimeout执行原理说明

    setTimeout用法在实际项目中还是会时常遇到.比如浏览器会聪明的等到一个函数堆栈结束后才改变DOM,如果再这个函数堆栈中把页面背景先从白色设为红色,再设回白色,那么浏览器会认为DOM没有发生任何 ...

随机推荐

  1. SpringMVC11文件上传

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  2. codevs 1689 搭建高塔

    /*机智sort二维转一维*/ #include<iostream> #include<cstdio> #include<cstring> #include< ...

  3. HDU5289

    题意:求解存在最大差值小于给定K值的所有区间段. 输入: T(测试数据) n(数组个数)K(给定区间值的范围) ai...(数组值) 输出: ss(所有满足符合条件的区间段) 思路:二分+ST算法,首 ...

  4. VS2008试用版到期解决办法

    在Windows 7下,VS2008试用版无法正常升级到正式版.原因是维护页面的注册码输入框和升级按钮被隐藏.通过本补丁,可让注册码输入框和升级按钮恢复正常显示 点击此处下载补丁 1.安装完90天试用 ...

  5. 用js给html设置style

    [html] view plaincopyprint? 原贴地址:<a href="http://heichong.iteye.com/blog/860698">htt ...

  6. 四、分离T4引擎

         在前几篇文章中,我使用大量的篇幅来介绍T4在VisualStudio中如何使用.虽然在一定程度上可以提高我们的工作效率,但并没有实质上的改变.不过从另一方面来说,我们确实了解到了T4的强大. ...

  7. Android客户端采用Http 协议Post方式请求与服务端进行数据交互(转)

    http://blog.csdn.net/javanian/article/details/8194265

  8. Python sys.path.append

    python sys.path.append 对于模块和自己写的程序不在同一个目录下,可以把模块的路径通过sys.path.append(路径)添加到程序中. 在程序开头加上: import syss ...

  9. MYSQL主从不同步延迟原理

    1. MySQL数据库主从同步延迟原理.   要说延时原理,得从mysql的数据库主从复制原理说起,mysql的主从复制都是单线程的操作,   主库对所有DDL和DML产生binlog,binlog是 ...

  10. location对象位置操作,进行跳转

    location位置操作,进行跳转 location.assign("http://www.baidu.com") 跳转,打开新的url 等价于,将location.href或wi ...