追踪执行顺序

问题描述 投票:0回答:1

我是 JS 新手,正在尝试弄清楚代码具有微任务时的执行顺序。我知道其背后的理论,当堆栈为“空”时(即,当其上只有全局上下文时),微任务被从队列推送到调用堆栈。 例如,在全局上下文中,我们有两个连续的循环:

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);
};

这是我查看执行顺序的方式:

  1. Promise 构造函数内的执行器函数调用
    resolve()
    并立即结算 Promise。
  2. 执行循环。
  3. then()
    被唤起,它的上下文放在调用堆栈上(在全局上下文之上)
  4. then()
    内的回调已在浏览器环境中的某个位置注册。
  5. then
    上下文从堆栈中弹出。
  6. 执行另一个循环,因为来自
    then()
    的回调仅被注册,尚未进入队列(或者它立即进入队列?)
  7. 现在循环已完成并且调用堆栈为空,事件循环从队列中拾取回调并将其扔到调用堆栈并执行(我知道情况并非如此,回调将在最后打印,但我不知道为什么)
  8. 执行最后一个循环

到第7步,回调执行的所有条件都满足了: a) 堆栈上没有任何内容 b) 没有同步代码正在运行 c) 回调正在队列中等待

如果循环之间有很多机会执行,为什么回调会坐在队列中直到执行最终循环?


编辑以解决斯科特·马库斯的评论

整个问题的灵感来自以下代码的意外行为(嗯,至少对我来说是意外的):

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')
),这正是我在执行
await之前所看到的情况
异步函数外部的语句。 如果运行上面的代码,您将得到以下输出:

enter image description here

如果我将

await
语句包装在异步函数中,如下所示:

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');

...输出会有所不同(正是我所期望的):

enter image description here

我已经尝试找出为什么顶级

await
会表现出这种行为 11 个小时了,但我仍然没有找到答案。如果您有机会对此有所了解,我将不胜感激。

javascript
1个回答
0
投票

for循环执行前、执行后和执行过程中是否都满足堆栈为空的条件?

不。全局执行上下文仍在堆栈上。整个代码运行完成,之后堆栈变空,异步任务才能运行。

© www.soinside.com 2019 - 2024. All rights reserved.