事件循环和Promise有什么关系
What is the relationship between event loop and Promise
很好奇Event Loop和Promise的关系
该演示暴露了这个问题。我预计 p1 fulfilled
出现在中间, 因为它们将任务排队到同一个任务队列并一个一个执行。
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
的回调没有进入事件循环的任务队列。是吗?
【注意:问题与不同,因为它更侧重于Event Loop和Promise之间的关系】
根据 Axel Rauschmayer 博士 here.
,除非堆栈中没有应用程序代码,否则不会调用 Promises
... the Promises/A+ specification demands
that the latter mode of execution be always used. It states so via the
following requirement (2.2.4) for the then() method:
onFulfilled or onRejected must not be called until the execution
context stack contains only platform code.
重要提示:
That means that you code can rely on run-to-completion semantics (as
explained in part 1) and that chaining promises won’t starve other
tasks of processing time.
每个事件循环都有一个微任务队列和一个宏任务队列。
microtask 是原本要在microtask 队列而不是task 队列中排队的任务。参考https://www.w3.org/TR/html51/webappapis.html#microtask-queue.
有两种微任务:
- 单独回调微任务,如
Promise
,
- 和复合微任务,例如 Node.js 中的
Object.observe
、MutationObserver
和 process.nextTick
。
而宏任务队列主要有Nodejs中的setTimeout
、setInterval
、setImmediate
、requestAnimationFrame
、I/O
在一个事件循环中,这两个任务队列会运行分两步:
- 首先,检查旧的宏任务队列中是否有宏任务(称之为X);
- 如果X存在,并且是运行ning,等待它完成下一步;否则,立即进入下一步;
- 其次,运行微任务队列的所有微任务;
- 当运行微任务时,我们仍然可以在队列中添加更多的微任务,这些任务也会运行。
在你的例子中:
- 首先,您的 Promise 初始化
new Promise
和 resolve
是同步的;
- 然后同步添加一个
setTimeout
个macroTask到macrotask队列中;
- 然后同步添加微任务
promise.then(function(){})
到微任务队列,这个任务会运行立即,因为Promise初始化和解析是同步的,这个任务运行在任何宏任务之前;所以,console.log p1 fulfilled
;
- 然后将第二个宏任务
setTimeout
添加到宏任务队列;
- 此事件循环结束后,运行 两个宏任务;
对于此代码:
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
- 首先将三个宏任务
setTimeout
添加到宏任务队列,将一个微任务promise.then()
添加到微任务队列;
- 运行 一个宏任务;
- 如果条件为真运行所有微任务,但为假,则进行下一步;
- 运行第二个宏任务;
- 检查promise是否解决,条件为真,则运行所有微任务;
- 继续 运行 其他宏任务;
很好奇Event Loop和Promise的关系
该演示暴露了这个问题。我预计 p1 fulfilled
出现在中间, 因为它们将任务排队到同一个任务队列并一个一个执行。
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
的回调没有进入事件循环的任务队列。是吗?
【注意:问题与
根据 Axel Rauschmayer 博士 here.
,除非堆栈中没有应用程序代码,否则不会调用 Promises... the Promises/A+ specification demands that the latter mode of execution be always used. It states so via the following requirement (2.2.4) for the then() method:
onFulfilled or onRejected must not be called until the execution context stack contains only platform code.
重要提示:
That means that you code can rely on run-to-completion semantics (as explained in part 1) and that chaining promises won’t starve other tasks of processing time.
每个事件循环都有一个微任务队列和一个宏任务队列。
microtask 是原本要在microtask 队列而不是task 队列中排队的任务。参考https://www.w3.org/TR/html51/webappapis.html#microtask-queue.
有两种微任务:
- 单独回调微任务,如
Promise
, - 和复合微任务,例如 Node.js 中的
Object.observe
、MutationObserver
和process.nextTick
。
而宏任务队列主要有Nodejs中的setTimeout
、setInterval
、setImmediate
、requestAnimationFrame
、I/O
在一个事件循环中,这两个任务队列会运行分两步:
- 首先,检查旧的宏任务队列中是否有宏任务(称之为X);
- 如果X存在,并且是运行ning,等待它完成下一步;否则,立即进入下一步;
- 其次,运行微任务队列的所有微任务;
- 当运行微任务时,我们仍然可以在队列中添加更多的微任务,这些任务也会运行。
在你的例子中:
- 首先,您的 Promise 初始化
new Promise
和resolve
是同步的; - 然后同步添加一个
setTimeout
个macroTask到macrotask队列中; - 然后同步添加微任务
promise.then(function(){})
到微任务队列,这个任务会运行立即,因为Promise初始化和解析是同步的,这个任务运行在任何宏任务之前;所以,console.logp1 fulfilled
; - 然后将第二个宏任务
setTimeout
添加到宏任务队列; - 此事件循环结束后,运行 两个宏任务;
对于此代码:
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
- 首先将三个宏任务
setTimeout
添加到宏任务队列,将一个微任务promise.then()
添加到微任务队列; - 运行 一个宏任务;
- 如果条件为真运行所有微任务,但为假,则进行下一步;
- 运行第二个宏任务;
- 检查promise是否解决,条件为真,则运行所有微任务;
- 继续 运行 其他宏任务;