我是JS的新手,正在try 弄清楚当代码具有微任务时的执行顺序.我知道它背后的理论,即当堆栈为"空"时(即当它上只有全局上下文时),微任务会从队列推送到调用堆栈. 例如,在全球环境中,我们有两个连续的循环:
for(let i = 0; i<1000; i++){
console.log(i);
};
for(let i = 0; i<1000; i++){
console.log(i);
};
在执行for循环之前、之后和期间,是否满足了堆栈为空的条件?如果是,如果到那时它已在队列中并且调用栈为空,为什么下面代码中的微任务(res)=> { console.log(res)}
在最后两个循环之间没有执行?
const promise = new Promise(function(resolve, _){
resolve('microtask2');
});
for(let i = 0; i<1000; i++){
console.log(i);
};
promise.then((res)=> {
console.log(res);
)};
for(let i = 0; i<1000; i++){
console.log(i);
};
for(let i = 0; i<1000; i++){
console.log(i);
};
以下是我对执行顺序的看法:
- promise的构造函数中的执行者函数调用
resolve()
并立即结算promise. - 执行循环.
- 调用
then()
,将其上下文放入调用堆栈(在全局上下文之上) -
then()
内的回调在浏览器环境中的某个地方注册. -
then
上下文从堆栈中弹出. - 执行另一个循环,因为来自
then()
的回调仅注册并且尚未进入队列(或者它是否立即进入队列?) - 既然循环已经完成并且调用堆栈为is empty,事件循环从队列中拾取回调,将其扔到调用堆栈并执行(我知道情况并非如此,回调将最后打印,但我不知道为什么)
- 执行最后一个循环
通过步骤7,执行回调的所有条件都得到满足: a)堆栈上没有任何内容 b)没有同步代码正在运行 c)回调正在队列中等待
如果循环之间有很多机会可以执行,为什么回调会留在队列中,直到执行最后一个循环?
Edited to address Scott Marcus' commentary
整个问题的灵感来自以下代码的意外行为(嗯,至少对我来说是意外的):
const timer = setTimeout(function(){
console.log('set timeout');
}, 0);
new Promise(function(resolve, _){
try{
resolve('microtask1');
}
catch(err){
console.error(`caught an ${err}`);
}
}).then((res)=>{
console.log(res);
});
console.log('synchronous code 1');
const result = await fetch(`https://jsonplaceholder.typicode.com/photos`);
console.log('synchronous code 2');
一开始,我认为只有在文件中的最后一行同步代码被执行(在本例中是console.log('synchronous code 2')
)后才会执行micro-/macrotasks,而这正是我所看到的,直到我在Inbox函数外执行了await
声明.
如果运行上面的代码,您将得到以下输出:
如果我将await
声明包装在一个像这样的Deliverc函数中:
let result;
const timer = setTimeout(function(){
console.log('set timeout');
}, 0);
new Promise(function(resolve, _){
try{
resolve('microtask1');
}
catch(err){
console.error(`caught an ${err}`);
}
}).then((res)=>{
console.log(res);
});
console.log('synchronous code 1');
(async function(){
result = await fetch(`https://jsonplaceholder.typicode.com/photos`);
})();
console.log('synchronous code 2');
...输出将会有所不同(正是我所期望的):
11个小时以来,我一直在试图弄清楚为什么顶级await
人表现出这种行为,但我仍然远未找到答案.如果您有机会对此有所了解,我将不胜感激.