一、浏览器的内核是多线程的,它们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:javascript引擎线程,GUI渲染线程,浏览器事件触发线程。
1. javascript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。
2. GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
3. 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。(当线程中没有执行任何同步代码的前提下才会执行异步代码)
看下这段代码,setTimeout是异步线程,需要等待js引擎处理完同步代码(while语句)之后才会执行,while语句直接是个死循环,js引擎没有空闲,不会执行下面的alert,也不会插入setTimeout。所以即使这个时候你把setTimeout的时间改成0,他还是不会执行。看下实例:
setTimeout(function(){ console.log(123); var s = new Date(); var n = s.getTime(); console.log(n); },0)
for (var i = 0; i < 50; i++) { console.log(new Date().getTime()); };
执行结果如下:
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596750 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
1387784596765 VM257:9
undefined
123 VM257:3
1387784596765
也就是说即使setTimeout为0,他也是等js引擎的代码执行完之后才会插入到js引擎线程的最后执行。
在看一下如果有多个异步插入线程的情况:
setTimeout(function(){
console.log(1);
var s = new Date();
var n = s.getMilliseconds();
var t = s.getTime();
console.log(n);
console.log(t);
console.log(1);
},1000)
setTimeout(function(){
console.log(2);
var s = new Date();
var n = s.getMilliseconds();
var t = s.getTime();
console.log(n);
console.log(t);
console.log(2);
},500)
setTimeout(function(){
console.log(3);
var s = new Date();
var n = s.getMilliseconds();
var t = s.getTime();
console.log(n);
console.log(t);
console.log(3);
},0)
for (var i = 0; i < 1000; i++) {
if(i == 0){
console.log(new Date().getTime());
}
console.log(new Date().getMilliseconds());
if(i == 999){
console.log(new Date().getTime());
}
};
1387793158633 VM655:31
43633 VM655:33
125648 VM655:33
135664 VM655:33
314679 VM655:33
293695 VM655:33
90711 VM655:33
1387793158711 VM655:35
undefined
3 VM655:21
711 VM655:25
1387793158711 VM655:26
3 VM655:27
2 VM655:12
132 VM655:16
1387793159132 VM655:17
2 VM655:18
1 VM655:3
631 VM655:7
1387793159631 VM655:8
1 VM655:9
1387793158711-1387793158633
78
1387793158633+500
1387793159133
1387793158633+1000
1387793159633
在for循环中执行了1000次打印,时间到1387793158711,setTimeout时间为0的开始执行,过了498毫秒,setTimeout为500的开始执行,再过998毫秒,setTimeout为1000的开始执行。为什么会差2毫秒,我也没搞懂。