js的宏任务和微任务之道

宏任务

页面中的大部分任务都是在主线程上执行的,这些任务主要:

  • 渲染事件(如DOM,计算布局,绘制)
  • 用户交互事件(如鼠标点击,滚动页面,放大缩小)
  • JavaScript脚本执行事件
  • 网络请求完成,文件读写完成事件

为了协调这些任务有条不紊地在主线程上执行,页面进程引入了消息队列和事件循环机制,渲染进程内部会维护多个消息队列,比如延迟队列和普通的消息队列。然后主线程采用一个for循环,不断的从任务队列中取出任务并执行任务。这些消息队列中的任务称为宏任务。保存待执行的宏任务的队列称为宏队列。

消息队列中的任务是通过事件循环机制来执行的,而在WHATWG规范定义消息队列宏任务的大致流程:

  • 先从多个消息队列中选出一个最老的任务,这个任务称为oldestTask
  • 然后循环系统记录任务开始执行的时间,并把这个oldestTask设置为当前正在执行的任务
  • 当任务执行完成之后,删除当前正在执行的任务,并从对应的消息队列中删除掉这个oldestTask
  • 最后统计执行完成的时长等信息

每个宏任务都关联着一个微任务队列,微任务队列既是存放微任务的队列。当Javascript执行一段脚本时,V8引擎会为其创建一个全局执行上下文,在创建全局上下文的同时,V8引擎也会在内部同时创建一个微任务队列。

微任务

微任务就是一个需要异步执行的函数,执行的时机是在主函数执行结束之后,当前宏任务执行结束之前。

微任务产生的方式:

  • 使用MutationObserver监控某个DOM节点,然后再通过JavaScript来修改这个节点,或者为这个节点添加,删除部分子节点,当DOM节点发生变化时,就会产生DOM变化记录的微任务。
  • 使用Promise,当调用Promise.resolve()或者Promise.reject()的时候,也会产生微任务。

通过DOM节点变化产生的微任务和Promise产生的微任务都会被保存到微任务队列中。

微任务执行的时间:
通常情况下,在当前宏任务中的JavaScript快执行完成时,也就是JavaScript引擎准备退出全局上下文并清空调用栈时,JavaScript引擎会检查全局执行上下文中的微任务队列。然后按照顺序执行队列中的微任务。WHATWG把执行微任务的时间点成为检查点

如果在执行微任务队列中的任务,产生了新的微任务,同样会将该微任务添加队列中,V8引擎一直循环执行任务中的任务,直到队列为空才算执行结束。也就是说在执行微任务过程中产生的新的微任务并不会推迟到下个宏任务中才执行,而是在当前的宏任务中继续执行。

宏任务和微任务之间的联系

  • 微任务和宏任务是绑定的,每个宏任务在执行时,会创建自己的微任务队列
  • 微任务的执行时长会影响到当前宏任务的时长。比如一个宏任务在执行过程中,产生了100个微任务,执行每个宏任务的时间是10ms,那么宏任务因微任务的执行让其执行时间延长了1s
  • 在一个宏任务中,分别创建一个用于回调的宏任务和微任务,无论什么情况下,微任务都早于宏任务的执行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 JavaScript 中,事件循环(Event Loop)是一个非常重要的概念。事件循环是一种机制,用于执行异步任务,以保证 JavaScript 在单线程的情况下能够处理多个任务。 在事件循环中,我们通常将任务分为任务(macro task)和任务(micro task)两类。 任务是由浏览器或 Node.js 的 API 提供的异步任务,例如 setTimeout、setInterval、requestAnimationFrame、I/O 操作等。这些任务会被添加到任务队列(task queue)中,当主线程执行完当前任务后,会从队列中取出一个任务执行,直到队列为空。 任务则是在当前任务执行结束后立即执行的异步任务,例如 Promise 的回调函数、MutationObserver 的回调函数等。这些任务会被添加到任务队列(microtask queue)中,当主线程执行完当前任务后,会从任务队列中按顺序取出所有任务执行,直到队列为空。 需要注意的是,任务的执行优先级高于任务,也就是说,在执行任务过程中,如果有任务需要执行,会先执行完所有任务,然后再执行下一个任务。 下面是一个示例代码,用于演示任务任务的执行顺序: ```javascript console.log('start'); setTimeout(() => { console.log('setTimeout'); }, 0); Promise.resolve().then(() => { console.log('Promise'); }); console.log('end'); ``` 上述代码中,先执行同步代码,输出 `start` 和 `end`,然后将 `setTimeout` 函数添加到任务队列中,并将 Promise 的回调函数添加到任务队列中。最后,按顺序取出任务队列中的任务,输出 `Promise`,再取出任务队列中的任务,输出 `setTimeout`。 输出结果如下: ``` start end Promise setTimeout ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值