2017-09-23 48 views
0

我很好奇Event Loop和Promise之间的关系。
该演示揭示了这个问题。我期望p1 fulfilled出现在中间, ,因为他们排列任务到相同的任务队列,并逐一执行。 事件循环和Promise之间的关系

var p1 = new Promise(function(resolve, reject){ 
    resolve(1) 
}) 
setTimeout(function(){ 
    console.log("will be executed at the top of the next Event Loop") 
},0) 
p1.then(function(value){ 
    console.log("p1 fulfilled") 
}) 
setTimeout(function(){ 
    console.log("will be executed at the bottom of the next Event Loop") 
},0) 

控制台的结果是:

p1 fulfilled 
will be executed at the top of the next Event Loop 
will be executed at the bottom of the next Event Loop 

The visualized effect显示promise.then的回调没有去到事件循环的任务队列。这是正确的?

【注:现在的问题是不一样的Promise vs setTimeout,因为它更注重事件循环和承诺之间的关系】

+0

你可以想像,在当前[蜱]的端部(https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/#处理的第二任务队列process-nexttick)即在正常任务队列中的任何事物之前。 – SpiderPig

+1

'setTimeout'也有一个最小延迟。 – zzzzBov

+0

_“我预计'p1 fulfilled'出现在中间。”_你为什么期待这样的结果? – guest271314

回答

2

每个事件循环都有一个microtask队列和一个macrotask队列。

微任务是最初在微任务队列中排队而不是任务队列的任务。请参阅https://www.w3.org/TR/html51/webappapis.html#microtask-queue

有两种microtasks的:

  • 孤回调microtasks,如Promise
  • 和化合物microtasks,如Object.observeMutationObserverprocess.nextTick在Node.js的
中的NodeJS

而宏任务队列主要包含setTimeoutsetIntervalsetImmediate,​​,I/O

在事件循环,这两个任务队列将分两步执行:

  1. 首先,检查是否有宏任务(称之为X)在老宏任务队列中;
  2. 如果X存在且正在运行,请等待下一步完成;否则,立即进入下一步;
  3. 其次,运行microtask队列的所有microtask;
  4. 当运行微任务时,我们仍然可以在队列中添加更多的微操作,这些任务也将运行。

在您的例子:

  1. 首先,你的承诺初始化new Promiseresolve是同步的;
  2. 然后将一个setTimeout宏任务同步添加到macrotask队列;
  3. 然后将microtask promise.then(function(){})同步添加到microtask队列中,这个任务会立即运行,因为Promise的初始化和解析是同步的,这个任务在任何macrotask之前运行;所以,console.log中的p1 fulfilled;
  4. 然后将第二个macrotask setTimeout添加到macrotask队列;
  5. 此事件循环结束后,运行两个macrotasks;

此代码:

setTimeout(function(){ 
    console.log("will be executed at the top of the next Event Loop") 
},0) 
var p1 = new Promise(function(resolve, reject){ 
    setTimeout(function(){resolve(1)},0) 
}); 
setTimeout(function(){ 
    console.log("will be executed at the bottom of the next Event Loop") 
},0) 
for (var i = 0; i < 100; i++) { 
    (function(j){ 
     p1.then(function(value){ 
      console.log("promise then - " + j) 
     }); 
    })(i) 
} 

输出顺序:

will be executed at the top of the next Event Loop 
promise then - 0 
promise then - 1 
promise then - 2 
... 
promise then - 99 
will be executed at the bottom of the next Event Loop 
  1. 首先添加三个宏任务setTimeout到宏任务队列,以及一个microtask promise.then()到microtask队列;
  2. 运行macrotask;
  3. 如果条件true运行所有microtasks,但它是false,所以请转到下一步;
  4. 运行第二个macrotask;
  5. 检查承诺是否解决,条件是否成立,然后运行所有的microtasks;
  6. 继续运行其他macrotasks;
+0

你说'X'会先检查,但是,在步骤2中的'setTimeout'宏任务'X'?为什么不先执行它? – PageYe

+0

因为你的承诺初始化和解析是同步的,所以当在第一步中检查旧的macrotask队列中是否存在一个macrotask(称为X)时,它将返回false。只有在同步代码之后,才会调用'setTimeout'宏任务。 – JiangangXiong

+0

由于w3.org对macrotask队列没有任何说明,macrotask队列和任务队列之间有什么区别?从概念上讲,微任务队列是一种任务队列,还是完全不同? – PageYe

0

承诺将不会被调用,除非堆栈明确的应用程序代码按照博士Axel Rauschmayer here

...... Promises/A +规范要求 后者的执行方式总是被使用。它通过以下 requirement(2.2.4)为当时()方法指出这样:

onFulfilled或onRejected不能调用,直到执行 上下文堆栈仅包含平台的代码。

必须注意的是非常重要的:

这意味着,你的代码可以依靠运行至完成语义(如 在第1部分解释)和链接承诺不会饿死其他 任务的处理时间。

+0

我不明白这是如何回答这个问题。在OP的例子中,'then'子句**被**调用,而有未决的'setTimeout'任务,假设这些任务被认为是“应用程序代码”或“平台代码”,我不知道定义 - 他们的意思是什么? – 2017-09-23 05:00:14

相关问题