深入解析 JavaScript 异步执行顺序:从同步到微任务与宏任务

作者:异步漫步时间:2026-10-25 12:56:27浏览:314

本文详细解析 JavaScript 异步代码的执行顺序,涵盖同步代码优先、微任务(如 Promise)与宏任务(如 setTimeout)的队列机制,以及 Node.js 中 process.nextTick 的特殊优先级。通过多个包含 async/await 和 Promise 链式调用的代码示例,逐步演示事件循环(Event Loop)如何处理任务队列,帮助开发者准确预测复杂异步场景下的输出结果。

  • JavaScript 引擎在执行代码时,遵循“先同步,后异步”的基本执行顺序。
  • 在异步任务中,任务队列的执行顺序遵循特定规则:优先执行微任务(microtask)队列,随后再执行宏任务(macrotask)队列。
  • 调用 Promise 对象中的 resolve 或 reject 方法会将其回调加入微任务队列,而 setTimeout 等定时器函数则属于宏任务队列。

需要注意的是,上述所有任务均基于队列机制运行,遵循先进先出(FIFO)的原则。

常见的微任务包括 process.nextTick、Promise 的回调以及 MutationObserver。

常见的宏任务包括 script(整体代码块)、setTimeout、setInterval、setImmediate、I/O 操作以及 UI 渲染。

在 Node.js 环境中,process.nextTick 的优先级高于 Promise。可以简单理解为:在宏任务执行结束后,会先执行微任务队列中的 nextTick 部分,然后才执行微任务中的 Promise 部分。

javascript事件机制

javascript事件机制

题目1:

console.log('script start') 
async function async1() {
  await async2()
  console.log('async1 end')
}
async function async2() {
  console.log('async2 end')
}
async1()
 
setTimeout(function() {
  console.log('setTimeout')
}, 0)
 
new Promise(resolve => {
  console.log('Promise')
  resolve()
})
.then(function() {
  console.log('promise1')
})
.then(function() {
  console.log('promise2')
})
 
console.log('script end')

执行结果?

分析:

首先执行 同步代码:

  • 1. 首先执行 console.log('script start')
  • 2. 执行 async1() 的时候,马上执行了 async2函数:console.log('async2 end')
  • 3. 顺序执行 new Promise()中的同步函数:console.log('Promise')
  • 4. 最后执行 console.log('script end')。

上面是同步执行的代码,然后看剩下的异步执行的代码:

首先,setTimeout是 宏观任务,排除到最后,剩下微观任务:

async function async1() {
  await async2()
  console.log('async1 end')
}
new Promise(resolve => {
  resolve()
})
.then(function() {
  console.log('promise1')
})
.then(function() {
  console.log('promise2')
})
  • 5. 然后根据先入先出的对列方式,先执行await async2() 后面阻碍的函数console.log('async1 end')
  • 6. 执行promise的resolve函数
new Promise(resolve => {
  resolve()
})

也就是接下来的两个then:console.log('promise1') ----console.log('promise2') ;

  • 7. 最后执行的是 setTimeout函数console.log('setTimeout') ;

综上所述,以上代码执行的顺序是:

1.script start >> 2.async2 end >> 3.Promise >> 4.script end >> 5.async1 end >> 6.promise1 >> 7.promise2 >> 8.setTimeout

题目2:

(function() {
 
    setTimeout(() => {
        console.log(0);
    });
 
    new Promise(resolve => {
        console.log(1);
 
        setTimeout(() => {
            resolve();
            Promise.resolve().then(() => console.log(2));
            console.log(3);
        });
 
        Promise.resolve().then(() => console.log(4));
 
    }).then(() => {
        console.log(5);
        Promise.resolve().then(() => console.log(8));
        setTimeout(() => console.log(6));
    });
 
    console.log(7);
 
})();
  • 1. 同样先执行同步代码,且先把setTimeout去掉:
new Promise(resolve => {
      console.log(1);
      Promise.resolve().then(() => console.log(4)); //微观任务
  }).then(() => {                  //then函数是执行对应的 resolve 的时候才执行的
      console.log(5);
      Promise.resolve().then(() => console.log(8));//微观任务
 }); console.log(7);

可以看出先执行:console.log(1);console.log(7);

  • 2. 执行微任务Promise.resolve().then(() => console.log(4));

代码变成了:

(function() {
  setTimeout(() => {
      console.log(0);
  });
  new Promise(resolve => {
      setTimeout(() => {
          resolve();
          Promise.resolve().then(() => console.log(2));
          console.log(3);
      });
  }).then(() => {
      console.log(5);
      Promise.resolve().then(() => console.log(8)); //这句是多加的
      setTimeout(() => console.log(6));
  });
})();

只剩下宏观任务(微观任务在宏观任务里,也就是宏观任务外面不在有微观任务了)

  • 3. 执行console.log(0);
  • 4.再执行 new Promise 中的 setTimeout,先执行里面的同步函数:console.log(3)
  • 5. 再执行上面的 resolve,对应的是下面的then函数:
then(() => {
      console.log(5);
      Promise.resolve().then(() => console.log(8)); //这句是多加的
      setTimeout(() => console.log(6));
 }

所以先执行console.log(5);

剩下的都是微观任务和宏观任务,先看微观任务:

new Promise(resolve => {
     resolve();
     Promise.resolve().then(() => console.log(2));
 }).then(() => {
     Promise.resolve().then(() => console.log(8));
     setTimeout(() => console.log(6));
 });

所以根据队列中的微观任务顺序先执行:console.log(2),在执行then中的console.log(8);

最后再执行 console.log(6)

综上所述,结果为

1/7/4/0/3/5/2/8/6

题目3:

(function() {
    setTimeout(() => {
        console.log(0);
    });
 
    new Promise(resolve => {
 
        console.log(1);
         
        setTimeout(() => {
            resolve();
            Promise.resolve().then(() => {
                console.log(2);
                setTimeout(() => console.log(3));
                Promise.resolve().then(() => console.log(4));
            });
        });
 
        Promise.resolve().then(() => console.log(5));
 
    }).then(() => {
 
        console.log(6);
        Promise.resolve().then(() => console.log(7));
        setTimeout(() => console.log(8));
 
    });
 
    console.log(9);
})();

解释如下:【同步>异步;微任务>宏任务】第一步:打印出1、9;如图

javascript事件机制

图a

由图a中的任务队列可知: 第二步: 执行微任务3,打印出5; 第三步:执行宏任务1,打印出0, 第四步:开始执行宏任务2;如图:

javascript事件机制

图b

第五步:由图b中的任务队列可知, 执行微任务4,打印出6,如图:

javascript事件机制

图c

第六步:由图c中的任务队列可知, 执行微任务5,打印出2;如图

javascript事件机制

图d

由图d的任务队列可知, 第七步:执行微任务6,打印出7; 第八步:执行微任务9,打印出4; 第九步:执行宏任务7,打印出8; 第十步:执行宏任务8,打印出3;

即答案是:

1-9-5-0-6-2-7-4-8-3

到此这篇关于JS异步执行顺序的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章