网站首页 全球最实用的IT互联网站!

人工智能P2P分享Wind搜索发布信息网站地图标签大全

当前位置:诺佳网 > 软件工程 > 前端开发 > JavaScript >

Web前端入门第 68 问:JavaScript 事件循环机制中的

时间:2025-06-23 09:47

人气:

作者:admin

标签:

导读:JS 是单线程语言。这句话对不对? 按照目前的情况来看,JS 自从支持了 Web Worker 之后,就不再是单线程语言了,但 Worker 的工作线程与主线程有区别,在 Worker 的工作线程中无法直接操作...

JS 是单线程语言。这句话对不对?

按照目前的情况来看,JS 自从支持了 Web Worker 之后,就不再是单线程语言了,但 Worker 的工作线程与主线程有区别,在 Worker 的工作线程中无法直接操作 DOM、window 对象或大多数浏览器 API(如 localStorage),Worker 的全局对象也不再是 window 对象,而是 self。

Worker 中的事件循环与主线程相互独立,互不影响,但执行顺序还是得遵循 JS 的语法规则。

宏任务

宏任务表示执行时间较长的任务,在每次时间循环时只会执行一个宏任务,执行完毕后处理微任务队列,所有微任务都执行完毕后进入下一个宏任务。

JS 常见宏任务类型:

  1. 定时器任务:setTimeout / setInterval
  2. DOM 事件回调(如 click、scroll)
  3. I/O 操作(如文件读取、网络请求)
  4. 浏览器用于执行动画的方法 requestAnimationFrame ,执行时机与渲染相关
  5. Node.js 环境的 setImmediate
  6. script 标签内主线程的同步代码(整体作为一个宏任务)

微任务

微任务表示更轻量的异步任务,当宏任务执行完毕之后立即执行。

JS 常见微任务类型:

  1. Promise.then() / Promise.catch() / Promise.finally()
  2. 浏览器监听 DOM 变化的 API 对象,比如:MutationObserver
  3. 手动添加微任务API方法:queueMicrotask()
  4. nodejs 中的 process.nextTick()

代码解析

看这么一段代码:

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

分析代码:

(function() {
  console.log(1) // 同步任务
  setTimeout(() => { console.log(2); });
  queueMicrotask(() => console.log(3))
  new Promise(resolve => {
    console.log(4); // 同步任务
    setTimeout(() => { // 宏任务
      resolve(); // 宏任务的同步任务
      console.log(5); // 宏任务中的同步任务
    }, 0);
    Promise.resolve().then(() => console.log(6)); // 微任务
    console.log(7); // 同步任务
  }).then(() => { // 微任务
    console.log(8); // 微任务中的同步任务
    Promise.resolve().then(() => console.log(9)); // 微任务中的微任务
  });
  console.log(10); // 同步任务
})();

第一轮

首先同步代码的宏任务优先级最高,不管微任务还是宏任务,同步代码都会先执行。

所以上面代码会优先执行:

console.log(1)
console.log(4);
console.log(7);
console.log(10);

接着开始处理微任务:

queueMicrotask(() => console.log(3))
Promise.resolve().then(() => console.log(6));

微任务处理完,开始执行下一轮宏任务。

第二轮

这一轮中的宏任务只有一个 setTimeout,执行完之后由于没有微任务队列,所以直接执行下一轮宏任务。

setTimeout(() => { console.log(2); });

第三轮

这一轮的宏任务中有同步代码。

setTimeout(() => { // 宏任务
  resolve(); // 宏任务的同步任务
  console.log(5); // 宏任务中的同步任务
}, 0);

在执行完 resolve() 之后,会将 Promise.then 的回调函数放入微任务队列中,所以在宏任务执行完之后会开始微任务:

then(() => { // 微任务
  console.log(8); // 微任务中的同步任务
  Promise.resolve().then(() => console.log(9)); // 微任务中的微任务
})

最终的打印顺序

1
4
7
10
3
6
2
5
8
9

执行流程图

JS 代码逐行执行,在遇到宏任务时,整个代码块丢到宏任务队列,在遇到微任务时,将微任务丢到本次事件循环中的微任务队列,本次事件循环执行完之后,再执行微任务队列中的任务,微任务执行完之后开始下一个宏任务执行。

JS 代码执行机制:

宏任务执行机制:

写在最后

JS 中的代码执行流程永远都是事件循环机制,这是 JS 的任务调度核心,理解事件循环机制,才能在开发中游刃有余~~

 

文章首发于微信公众号【前端路引】,欢迎 微信扫一扫 查看更多文章。

本文来自博客园,作者:前端路引,转载请注明原文链接:https://www.cnblogs.com/linx/p/18943769

 

温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信