这部分内容源于知乎上的一个发问。
setTimeout(function(){console.log(4)},0);
new Promise(function(resolve){
console.log(1)
for( var i=0 ; i<10000 ; i++ ){
i==9999 && resolve()
}
console.log(2)
}).then(function(){
console.log(5)
});
console.log(3);
// 1
// 2
// 3
// 5
// 4
之前我们说过then
要领增加的回调函数都是异步实行的,所以根据我们一般的认知,效果应该是12345
,由于4
是先增加到异步行列,而5
在今后增加到异步行列。
知乎的题目也有何幻大神细致的解说。这里我就简朴的说一下吧。
我们都晓得javascript
是单线程的,也就是说,一个时间只能做一件事。所以,一切的使命都要根据肯定的递次列队,然后一个一个实行。假如一切的使命都是同步的,那就没有什么题目,代码根据夙昔到后的递次顺次实行就能够了,但我们现实工作历程当中,不免会有一些操纵须要异步实行——比方事宜,比方ajax,比方setTimeout
。
所以,浏览器会保护一个使命行列(task queue
),使命行列是先进先出的,也就是说,先进入使命行列的会先实行。当主线程使命实行终了,就会检察使命行列中有没有新使命,假如有,则把第一个使命放到主线程中实行,以此轮回往复,这个历程也就是Event loops
。
我之前也一直都认为浏览器中只要一个使命行列,看到这个题目后才晓得。本来浏览器中的使命行列不止一个,且优先级也差别。基本上能够分为以下两种:
macro-task
: script(团体代码), setTimeout, setInterval, setImmediate, I/O, UI renderingmicro-task
: process.nextTick, 原生Promise, Object.observe, MutationObserver
我们看到原生Promise
和setTimeout
离别属于micro-task
和macro-task
。我们之前说的异步使命行列,指的是macro-task
。而micro-task
的实行递次,与之差别。
在实行完主线程上的一切使命时,会先去检察micro-task
行列中有没有使命,假如有,则顺次实行micro-task
行列中的一切使命,今后才去检察macro-task
行列。每次拿到macro-task
行列上使命并实行今后,都会去搜检micro-task
行列,以此轮回。所以上面题目中效果是12354
就很明了了。
我们看一个例子,并细致诠释它的实行流程。
console.log('script1');
setTimeout(function() {
console.log('setTimeout1');
}, 300);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script2');
setTimeout(function() {
console.log('setTimeout2');
Promise.resolve().then(function() {
console.log('promise3');
})
}, 0);
// script1
// script2
// promise1
// promise2
// setTimeout2
// promise3
// setTimeout1
效果如代码中解释所示。详细实行步骤以下:
①代码从上到下实行,先打印出script1
。
②实行到第一个setTimeout
时,发明300ms后把函数增加到macro-task
行列中。
③实行Promise
时,顺次把输出promise1
和promise2
的使命增加到micro-task
行列。
④打印script2
。
⑤实行第二个setTimeout
时由于设置的是0ms,所以马上(实在浏览器有起码4ms的限定)增加到macro-task
行列中。
⑥主线程实行终了则搜检micro-task
行列并实行,输出promise1
和promise2
。
⑦然后搜检macro-task
行列,输出setTimeout2
,并把输出promise3
的使命增加到micro-task
行列。
⑧再次搜检micro-task
行列并实行,输出promise3
。
⑨末了搜检macro-task
行列,输出setTimeout1
,由于它是300ms后增加到macro-task
行列,所今后输出。
范例中的流程是这个模样,然则差别的浏览器中,现实输出的效果可能会不相同。以上是最新版本的chrome中测试效果。
末了,引荐一篇外国朋友的博客,我就是看了这篇文章才完整弄清楚的,内里内容讲的迥殊细致。