LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

JavaScript 事件循环:写在前面的代码,为什么反而后执行?

zhenglin
2026年10月14日 15:5 本文热度 160

JavaScript 事件循环机制

学习 JavaScript 异步执行时,常会碰到这几个问题:

“setTimeout 的延迟设为 0,为什么还不能马上执行?”

“Promise.then 和定时器,谁先执行?”

“await 等待结果时,会不会把整个脚本卡住?”

这些问题都与事件循环(Event Loop)有关。代码的执行顺序,不只取决于写在哪里,还取决于它在什么时候、以什么任务进入队列。

一、单线程与任务队列

JavaScript 在主线程上依次执行代码。它能够操作 DOM,如果多个线程同时修改页面,就可能产生冲突;引入锁又会增加协调成本。

执行脚本时,同步代码直接运行。定时器到时、异步操作完成后,相应回调再等待调度。这里主要涉及两类任务:

  • 宏任务:整段 script、定时器回调等。


  • 微任务:Promise.then 的回调、await 之后恢复执行的代码等。


定时器的等待不会占住主线程,但它的回调也不会在计时结束时立刻打断当前代码。

二、事件循环的执行顺序

  1. 执行当前宏任务,包括其中的同步代码。


  2. 清空微任务队列,执行期间新增的微任务也要继续处理。


  3. 浏览器根据需要进行页面渲染。


  4. 执行下一个宏任务,重复上述过程。


每个宏任务结束后,都要先清空微任务队列,再执行下一个宏任务。

主线程上的 JavaScript 执行和页面渲染不能同时进行。因此,当前代码执行时间过长,页面渲染也会被推迟。

三、Promise 与定时器

console.log(1);


new Promise((resolve) => {

  console.log(2);

  resolve()

}).then(() => {

  console.log(3);

  setTimeout(() => {

    console.log(4);

  }, 0)

})


setTimeout(() => {

  console.log(5);

}, 1000)


console.log(6);

输出顺序:

1

2

6

3

4

5

执行过程:

  1. 同步执行整段脚本,输出 1、2、6。Promise 构造器中的回调也是同步执行的。


  2. 当前脚本结束,执行 then 微任务,输出 3,并注册一个 0ms 定时器。


  3. 在这个例子中,0ms 定时器先满足执行条件,输出 4;1000ms 定时器随后输出 5。


两个定时器分别计时,并不是先写的就一定先执行。延迟为 0 也不表示立即执行:回调仍要等当前任务和微任务处理完,才有机会运行。


四、嵌套任务的执行顺序

定时器回调内部,也可能产生新的微任务和宏任务:

console.log(1);


setTimeout(() => {

    console.log(2);


    new Promise((resolve) => {

        console.log(3);

        resolve()

    }).then(() => {

        console.log(4);

        setTimeout(() => {

            console.log(6);

        }, 0)

    })


    setTimeout(() => {

        console.log(5);

    }, 0)

}, 1000)


console.log(6);

输出顺序:

1

6

2

3

4

5

6

  1. 整段脚本先输出 1、6。这里的第一个 6 来自末尾的同步代码。


  2. 外层定时器执行,输出 2、3,安排 then 微任务,并注册输出 5 的定时器。


  3. 外层定时器回调结束,先执行微任务,输出 4,再注册输出 6 的定时器。


  4. 两个内部定时器的延迟都是 0,输出 5 的先注册,因此先输出 5,再输出 6。


微任务检查并不只发生在最初的 script 结束时,定时器回调结束后也一样。


五、async / await

5.1 async 的返回值

函数加上 async 后,调用结果总是一个 Promise,即使函数没有显式 return 也是如此。

async 可以单独使用,不一定要写 await;在函数体内使用 await 时,该函数需要声明为 async。加上 async 也不意味着函数里的代码全都异步执行:调用函数后,遇到 await 之前的代码仍然同步执行。


5.2 await 的执行过程

对于 await 后面的函数调用,可以分两步看:

  1. 先执行调用:函数中的同步代码立即执行,不会因为前面有 await 就被推迟。


  2. 再等待结果:暂停当前 async 函数的后续执行。如果返回的是 Promise,就等待它完成,再通过微任务继续执行 await 之后的代码。


由于上述机制,await 后面紧跟的表达式(即 await xxx 中的 xxx)可以按同步代码理解:先执行、先求值;await 语句之后的代码,则在结果就绪后通过微任务恢复执行。

这与 then 回调有相似之处:等待结果就绪后,后续逻辑通过微任务执行。等待期间,函数外部的同步代码会继续运行。


5.3 await 与函数返回值

函数内部有定时器,并不代表 await 就会等到定时器结束:

function A() {

  setTimeout(() => {

    console.log('a');

  }, 1000)

}

function B() {

  console.log('b');

}


async function fn() {

  await A()

  await B()

}

fn()

输出顺序:

b

a

A() 注册定时器后就执行结束,返回值是 undefined。await 可以等待这个普通值,后续代码仍会通过微任务恢复,于是 B() 先输出 b;约一秒后,定时器回调才输出 a。

要等待某个异步操作完成,函数需要返回一个能表示该操作完成的 Promise。 await 等待的是函数的返回结果,不会自动等待函数内部另外启动的定时器。

5.4 完整执行顺序

console.log('script start');

async function async1() {

  await async2()

  console.log('async1 end');

}

async function async2() {

  console.log('async2 end');

}

async1()

setTimeout(() => {

  console.log('setTimeout');

}, 0)

new Promise((resolve, reject) => {

  console.log('promise');

  resolve()

})

  .then(() => {

    console.log('then1');

  })

  .then(() => {

    console.log('then2');

  });

console.log('script end');

​输出顺序:

script start

async2 end

promise

script end

async1 end

then1

then2

setTimeout

  • 输出 script start,调用 async1。执行到 await async2() 时,先调用 async2,同步输出 async2 end。

  • async2 没有写 return,但它是 async 函数,因此返回一个已完成的 Promise。async1 暂停,async1 end 等待微任务阶段再输出。

  • 外部脚本继续执行:注册定时器,执行 Promise 构造器中的回调,输出 promise,最后输出 script end。

  • 同步代码结束,开始清空微任务队列。先恢复 async1,输出 async1 end,再输出 then1。随后 then2 回调进入微任务队列,也在这一阶段执行。

  • 微任务队列清空后,定时器回调执行,输出 setTimeout。

阅读原文:点击这里​


该文章在 2026/10/14 15:05:15 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-2  粤公网安备44030602007207号