微任务和宏任务

3 篇文章 0 订阅

事件循环

micro task 和 macro task 表示异步任务的两种分类。

js语言为单线程,同一个时间只能做一件事,为了防止主线程的不阻塞,Event Loop 的方案应用而生。

Event Loop 包含两类:一类是基于 Browsing Context,一种是基于 Worker。二者的运行是独立的,也就是说,每一个 JavaScript 运行的"线程环境"都有一个独立的 Event Loop,每一个 Web Worker 也有一个独立的 Event Loop。

任务队列

同步任务在函数调用栈内执行,异步任务则需要借助任务队列,一个线程中调用栈只有一个,但任务队列可以有多个;

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的关键步骤如下:

  • 在此次 tick 中选择最先进入队列的任务(oldest task),如果有则执行(一次)
  • 检查是否存在 Microtasks,如果存在则不停地执行,直至清空 Microtasks Queue
  • 更新 render
  • 主线程重复执行上述步骤

宏任务

setTimeout、setInterval、Ajax、DOM事件等

微任务

Promise、async / await等

运行机制

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理步骤如下:

  • 执行一个宏任务(栈中没有就从事件队列中获取)
  • 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 当前微任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  • 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

如图:

一、什么是微任务?什么是宏任务?

  • 微任务:Promise、async / await 等
  • 宏任务:setTimeout、setInterval、Ajax、DOM事件等
  • 微任务执行时机早于宏任务(具体原因下面会说到)

二、event loop 和 DOM 渲染?

js 是单线程的,js 的执行和 DOM 渲染共用一个线程,所以 js 执行需要留一些时机给 DOM 渲染。

执行顺序:

1、执行同步代码,执行完毕调用栈清空,

2、触发微任务

3、尝试 DOM 渲染(有内容更新就渲染,无更新忽略)

4、触发 event loop,执行宏任务

三、微任务、宏任务和 DOM 渲染的关系

        先后顺序:微任务 ---> DOM渲染 ---> 宏任务

三、微任务、宏任务和 DOM 渲染,在 event loop 的过程

微任务:DOM 渲染前触发

宏任务:DOM 渲染后触发

const span = $('<span>这是添加的元素</span>')
$('#content').append(span);

// 微任务
Promise.resolve().then(() => {
  alert('Promise then'); // 1  DOM 渲染了吗? --否
})

// 宏任务
setTimeout(() => {
  alert('setTimeout'); // 2  DOM 渲染了吗? --是
})

为什么微任务执行更早?

微任务和宏任务的队列是分开的,微任务是 ES6 语法规定的,宏任务是浏览器规定的,在 ES6 规范里是没有 setTimeout、onclick事件、ajax方法等,所以它们存放的地址是不一样的。

Promise 放在微任务队列里(micro task queue),它不经过 Web API,因为 Promise 是 ES 规范,不是 W3C 规范。

下面举个例子,也是常见的面试题目

async function async1() {
  console.log('async1 start'); // 2
  await async2();
  // await 后面都是异步  -- 微任务1 
  console.log('async1 end'); // 6
}

async function async2() {
  console.log('async2'); // 3
}

console.log('script start'); // 1

// 异步 -- 宏任务1
setTimeout(() => {
  console.log('setTimeout'); // 8
}, 0)

async1();

// Promise 初始化时候的代码 立即执行
new Promise((resolve) => {
  console.log('Promise1'); // 4
  resolve();
}).then(() => { // 异步 -- 微任务2
  console.log('Promise2'); // 7
})

console.log('script end'); // 5
/**
 * 到此所有的同步代码执行完毕(call stack 被清空),开始异步 触发 event loop
 * 执行微任务
 * 尝试 DOM 渲染
 * 执行宏任务
 *
 * 打印顺序:
 * script start
 * async1 start
 * async2
 * Promise1
 * script end
 * async1 end
 * Promise2
 * setTimeout
 */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值