一个关于回调的问题

来源:互联网 发布:淘宝加盟诈骗案进展 编辑:程序博客网 时间:2024/06/05 06:35

今天看到一道题蛮有意思的。题目是这样的:

setTimeout(function() {  console.log(1)}, 0);new Promise(function executor(resolve) {  console.log(2);  for( var i=0 ; i<10000 ; i++ ) {    i == 9999 && resolve();  }  console.log(3);}).then(function() {  console.log(4);});console.log(5);

这段代码的输出是什么?
一开始我没细想,以为是2,3,5,1,4,然后我随手就在chrome的console中运行了一下,发现结果是2,3,5,4,1
略微惊讶,,但是随即我想到setTimeout函数好像有个不成文的规定,当time为0时会延迟4ms运行(现在似乎已经写进了标准),这样一想,好像是该是这个结果哦。。
但是我发现了个小问题:
console中的结果
这个console中的结果有个undefined。
一般来讲,这个undefined应该是我这段代码运行完了的返回值啊。。
那么它应该出现在4前面啊!为什么出现在1前面了呢??
带着这个疑问我去搜索了下,发现我不知道的还有蛮多。。。

这个事情要从Event Loop说起。
我们都知道JavaScript是单线程的(虽然web worker能进行多线程的计算),它有个经典的Event Loop事件模型,而实际上就当前的这个程序来说,可以看做有两个任务队列。一个叫macro-task,另一个叫micro-task。根据Promises/A+规范:

  • macro-task包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering
  • micro-task包括:process.nextTick, Promises(这里指浏览器实现的原生 Promise), Object.observe(已废弃), MutationObserver

也就是说,浏览器运行这段程序的时候,经历了以下几个步骤:

  1. 将这段代码放到一个macro-task任务队列中,然后执行
  2. 执行到setTimeout,将这个setTimeout放到了当前的这个macro-task中,然后继续执行任务
  3. 执行到了promise,执行promise中的代码,输出2和3,将then回调放入micro-task,然后继续执行
  4. 输出5,至此执行完了macro-task中的第一个任务,然后执行micro-task中的全部任务,输出了4
  5. 至此,这段代码执行完毕,输出返回值undefined
  6. 执行macro-task中的下一个任务,输出1.

所以才看到了那样的结果。

更多内容请参考:知乎问题

0 0