理解javascript的单线程的理念对于javascript学习,以及掌握其中的一些设计机制非常重要,比如回调、定时器。对于后续学习nodejs也有很大的帮助。
通过先demo,后总结的形式,使得javascript的单线程更易于明白。
1 var a = 1; //全局变量a
2 function test(){
3 var a=2; //test中变量a
4 settimeout(function(){
5 alert(a); //输出test中变量a
6 a=3; //修改test中变量a
7 },3000);
8 a=4; //修改test中变量a
9 settimeout(function(){
10 alert(a); //输出test中变量a
11 a=5; //修改test中变量a
12 },1000);
13 alert(a); //输出test中变量a
14 }
15 test(); //执行test函数
16 alert(a); //输出全局变量a
//运行结果:4 1 4 5
/* 结果解析:先输出test()运行结果4,然后输出之后一行代码的1,然后1000ms之后输出test()中的变量a=4,最后3000ms之后输出test()中的变量a=5 */
/*
运行机制:
1. javascript是单线程,从上往下依次执行
2. settimeout异步方法存放在任务队列中,js主线程执行完成之后,才会取任务队列中的任务到js主线程中执行!
-> 先执行15行,然后执行16行
-> 执行15行,调用test()方法
-> 调用test()方法,先创建一个a变量,然后将第一个settimeout放到settimeout对应的线程中执行(启动定时器timer),第8行,修改test中变量a为4,然后将第二个settimeout添加到settimeout对应的线程队列中执行,执行13行,输出test中变量a,此时为4;然后执行16行,输出全局变量a,此时为1.
-> 1000ms之后,将第二个settimeout的回调函数,添加到js任务队列中,3000ms后将第一个settimeout的回调函数,添加到js任务队列中。
-> js主线程执行完成之后,会执行任务队列的事件,第二个settimeout优先进入任务队列,所以优先执行,执行第10行,输出test中的变量a,值为4,然后di11行,将test中的变量a修改为5;2000ms之后第一个settimeout进入任务队列,此时js主线程栈为空,所以将其添加到js主线程进行执行,第5行,输出test中的变量a,此时变量的值为5,第6行修改test变量a为3.
*/
由此延伸以下代码:
var a = 1;
var date = +new date(); // 小技巧:通过"+"转换为整数
function test(){
var a=2;
settimeout(function(){
console.log(a+'--'+ (new date()-date));
a=3;
},3000);
a=4;
a=5;
},1000);
console.log(a+'--'+ (new date()-date));
}
while(new date-date <1000){
test();
console.log(a+'--'+ (new date()-date));
//执行结果:4-1000 1-1001 4-2000 5-4001
结合以下博客,整理一些重要概念:
<a href="http://www.ruanyifeng.com/blog/2014/10/event-loop.html">http://www.ruanyifeng.com/blog/2014/10/event-loop.html</a>
<a href="http://www.cnblogs.com/mainz/p/3552717.html">http://www.cnblogs.com/mainz/p/3552717.html</a>
1、作为脚本语言,javascript主要功能是与用户互动,以及操作dom。假定javascript同时有两个线程,一个线程在某个dom节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
->so: javascript就是单线程。
2、javascript的任务分成两种:同步任务和异步任务。同步任务:在主线程上排队执行的任务,只有上一个任务执行完成了,才会执行下一个任务。异步任务:不进入主线程,而进入“任务队列”的任务,只有“任务队列”通知主线程,某个任务队列可以执行了,等主线程执行完成,任务队列才会进入主线程执行。
-> so:只要主线程空了,就会去读“任务队列”,这就是javascript的运行机制。
3、主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个事件又叫“事件循环”(event loop)。
html5规定settimeout()的第二个参数的最小值(最短间隔),不得低于4ms,如果低于4ms就会自动增加。在此之前,老版本浏览的都将最短时间设置为10ms。另外,对于那些dom变动(尤其是设计页面重新渲染的部分),通常不会立即执行,而是每16ms执行一次。这是使用requestanimationframe()的效果要好于settimeout()。
4、需要注意的是:settimeout只是将事件插入“事件队列”,必须等到前面代码(执行栈)执行完,主线程才会去执行他指定的回调函数。如果当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在settimeout()指定的是时间执行。
javascript是单线程,单线程就意味着所有任务需要排队。然后会将所有任务分成两类:同步任务和异步任务!同步任务:在主线程上执行的任务,只有前一个任务执行完成,才会执行后一个!异步任务:不进入主线程、而进入“任务队列”的任务。
js是单线程的,但是浏览器是多线程的!浏览器是事件驱动的!
js运行在浏览器中,是单线程的,每个window一个js线程,但是浏览器不是单线程。可能有多个如下线程:
javascript引擎线程、界面渲染线程、浏览器事件触发线程、http请求线程。
settimeout可以改变,js执行顺序。比如:我们想要输出hello world,world必须在hello之后输出,不管我们代码的顺序怎么样都输出同样的效果,这个时候就可以借助settimeout。
//代码一
var date = +new date();
console.log('hello',new date()-date);
settimeout(function(){
console.log('world',new date()-date);
},500);
//代码二:
//以上两个代码运行结果一样,结果都是:先输出hello ,然后500ms之后输出world![实际运行:501ms]
浏览器中定时器也是一个线程!
javscript是单线程的,ajax请求确实是异步的!原因是ajax请求的时候,是在浏览器的http请求线程中执行的,执行之后的回调函数会放到javascript线程中执行!
summary:
javascript是单线程的,浏览器是多线程的,浏览器的线程包括:js引擎线程、界面渲染线程、浏览器事件线程、http请求线程。不过不同的浏览器提供的线程是有区别的。一般js引擎线程和界面渲染线程是互斥的,两个线程不能同时执行,否则,就会出现界面渲染线程和js线程修改同一个dom样式的矛盾问题!
作者:reya滴水心
来源:51cto