event loop整理
宏任务和微任务
让我们从浏览器加载 script 说起,当浏览器加载完 script 之后,不考虑 script 标签的 defer 属性,script 将被立即执行。这时,我们就创建了一个宏任务。
在我们加载的代码中,可能有 click 事件的监听,也可能会发出网络请求。当这些操作触发我们埋下的回调函数后,相应的回调函数都会作为新的宏任务执行。
当然,在我们的宏任务的代码中,也可能会用到 Promise,MutationObserver 这些 api,他们的回调函数(或者 then 函数)都会在本轮宏任务结束之后,渲染进程工作之前执行,它们被称为微任务。
整个过程如下:
宏任务 => 微任务 => 渲染 => 宏任务 => 微任务 => 渲染 ...
这个循环往复的 过程在页面生命周期内一直存在,被称为 event loop。
一个例子
了解了什么是宏任务和微任务之后,我们来看一个经典的例子:
Promise.resolve().then(() => console.log('promise1 resolved')); // 1
Promise.resolve().then(() => console.log('promise2 resolved')); // 2
setTimeout(() => {
console.log('set timeout3') // 7
Promise.resolve().then(() => console.log('inner promise3 resolved')); // 8
}, 0);
setTimeout(() => console.log('set timeout1'), 0); // 9
setTimeout(() => console.log('set timeout2'), 0); // 10
Promise.resolve().then(() => console.log('promise4 resolved')); // 3
Promise.resolve().then(() => {
console.log('promise5 resolved') // 4
Promise.resolve().then(() => console.log('inner promise6 resolved')); // 6
});
Promise.resolve().then(() => console.log('promise7 resolved')); // 5
解释上面的执行顺序:
- 每一个 setTimeout 都会放到下一轮宏任务中触发。
- 本轮微任务中产生的新的微任务,会被加到队尾,仍然在本轮微任务队列中执行完毕。解释了 inner promise6 resolved 在 promise7 resolved 后面
- 宏任务中产生的微任务,会在该轮宏任务结束之后,统一在微任务队列中执行,解释了 inner promise3 resolved 在 set timeout3 后面
于是得到下面的图,紫色代表宏任务,黄色代表微任务。

观察可以发现,在第一个宏任务中,除了创建 setTimeout 和 Promise 之外,是没执行什么同步代码的,现在我们在原先的代码最后再加一行:
...
Promise.resolve().then(() => console.log('promise7 resolved')); // 5
new Promise((reslove) => console.log('promise instance'));
此时,尽管代码被加在最后一行,promise instance 却会第一个打印出来,因为 new Promise 中传入的函数是立即执行的。也就是说在第一轮宏任务中执行的。
microtask 是會在每一輪 event loop 進行渲染之前會被觸發
且只要在 microtask queue 裡面還有東西的話,就會一直執行下去
直到整個 microtask queue 變成空的為止
也就是說在 microtask 執行的時候,又觸發 queue 新的 microtask 的話
這個新的 microtask 也是會在此輪 task 執行完之前執行,不會留到下一輪 task
Vue 的 nextTick
我们再看下宏任务,微任务,渲染的流程
浏览器的 eventloop 是宏任务(dom 更新)=> 微任务 => 渲染,而 Vue 的 DOM 操作是在宏任务中进行的。这就解释了为什么 Vue 在完成本轮 DOM 更新之后,$nextTick 在本轮的微任务中执行回调函数,就可以确保拿到最新 DOM,尽管此时页面还没有将最新的 DOM 渲染到浏览器上。打开开发者工具,依次执行下面代码可以证明这一点:
// 模拟上一轮更新状态
document.body.style.background = 'yellow';
接下来模拟执行本轮更新操作:
document.body.style.background = 'red';
Promise.resolve().then(() =>{
let start = Date.now();
while(Date.now() - start < 3000) {
console.log(document.body.style.background) // 由于 while 循环,这里拿到的 background 已经是最新的 red,但是页面显示还是黄色
}
});
// 微任务执行结束之后,页面变成红色
上面的例子说明,在微任务中就可以拿到 Vue 本轮更新的DOM,而此时页面渲染的未必是最新的DOM。本文完。
参考资料:
https://yu-jack.github.io/2020/02/03/javascript-runtime-event-loop-browser/
https://juejin.im/post/6844903919789801486#heading-4
https://blog.insiderattack.net/javascript-event-loop-vs-node-js-event-loop-aea2b1b85f5c
event loop整理的更多相关文章
- javascript运行模式:并发模型 与Event Loop
看了阮一峰老师的JavaScript 运行机制详解:再谈Event Loop和[朴灵评注]的文章,查阅网上相关资料,把自己对javascript运行模式和EVENT loop的理解整理下,不一定对,日 ...
- 浏览器与Node的事件循环(Event Loop)有何区别?
前言 本文我们将会介绍 JS 实现异步的原理,并且了解了在浏览器和 Node 中 Event Loop 其实是不相同的. 一.线程与进程 1. 概念 我们经常说 JS 是单线程执行的,指的是一个进程里 ...
- js的事件循环(Event Loop)
(本文从掘金小册整理) 首先介绍一下几个概念 进程与线程 相信大家经常会听到 JS 是单线程执行的,但是你是否疑惑过什么是线程? 讲到线程,那么肯定也得说一下进程.本质上来说,两个名词都是 CPU 工 ...
- Node.js event loop 和 JS 浏览器环境下的事件循环的区别
Node.js event loop 和 JS 浏览器环境下的事件循环的区别: 1.线程与进程: JS 是单线程执行的,指的是一个进程里只有一个主线程,那到底什么是线程?什么是进程? 进程是 CPU ...
- [转]Event loop——浏览器和Node区别
最近对Event loop比较感兴趣,所以了解了一下.但是发现整个Event loop尽管有很多篇文章,但是没有一篇可以看完就对它所有内容都了解的文章.大部分的文章都只阐述了浏览器或者Node二者之一 ...
- Atitit 解决Unhandled event loop exception错误的办法
Atitit 解决Unhandled event loop exception错误的办法 查看workspace/.metadata/.log org.eclipse.swt.SWTError: No ...
- [译]Node.js - Event Loop
介绍 在读这篇博客之前,我强列建议先阅读我的前两篇文章: Getting Started With Node.js Node.js - Modules 在这篇文章中,我们将学习 Node.js 中的事 ...
- Eclipse经常报Unhandled event loop exception的原因
在公司的电脑上,Eclipse经常报Unhandled event loop exception 错误,非常频繁,通过搜索发现是因为电脑上安装了百度杀毒导致的.... 无语 另外 teamviewer ...
- Node.js 事件循环(Event Loop)介绍
Node.js 事件循环(Event Loop)介绍 JavaScript是一种单线程运行但又绝不会阻塞的语言,其实现非阻塞的关键是“事件循环”和“回调机制”.Node.js在JavaScript的基 ...
随机推荐
- 解决 error MSB4057: 该项目中不存在目标“_CopyWebApplication” 问题
在使用MSBuild 编译项目的时候报错: 解决办法: 在Web项目中,使用Nuget添加引用 MSBuild.Microsoft.VisualStudio.Web.targets 即可.
- Codeforces Round #667 (Div. 3) B. Minimum Product (贪心,数学)
题意:给你\(a\)和\(b\)两个数,每次操作可以是任意一个数\(-1\),最多操作\(n\),并且\(a\ge x\),\(b\ge y\),求操作后\(a*b\)的最小值. 题解:观察样例并且在 ...
- Codeforces Round #663 (Div. 2) C. Cyclic Permutations (构造,图?)
题意:对于某个序列,若\(1\le i\le n\),\(1\le j\le i\)且\(p_j>p_i\),或者\(1\le i\le n\),\(i<j \le n\)且\(p_j&g ...
- Ubuntu Live CD联网修复
此模式下可以联网修复ubuntu系统下绝大多数问题.进入LIVE CD模式,打开终端执行以下命令: #此处/dev/sda1为ubuntu根分区,工作中根据实际分区情况更改 sudo mount /d ...
- DCL 数据控制语言
目录 授予权限(GRANT) 回收权限(REVOTE) 授予权限(GRANT) # 语法 mysql> help grant; Name: 'GRANT' Description: Syntax ...
- Linux虚拟机封装成模板
对安装在VMware上的CentOS7.X进行封装,是为了后续的实验环境需要,可以批量去生成Linux系统.通过虚拟机模版来创建一台CentOS系统,跟原来机器一样,去掉了唯一性,而通过克隆出来的虚拟 ...
- HEXO添加置顶功能
使用库:参考 http://wangwlj.com/2018/01/09/blog_pin_post/ 目前已经有修改后支持置顶的仓库,可以直接用以下命令安装.(cmd 到博客根目录,nmp运行) $ ...
- 重新上手c语言的一些坑
c语言结构体不能声明函数,放几个函数指针倒是没问题 c语言结构体不能在声明时初始化 声明两个指针 int *a,*b; 或者typedef int* int_P int_P a,b; typedef要 ...
- CSS multi colors circle
CSS multi colors circle <!DOCTYPE html> <html lang="zh-Hans"> <head> < ...
- ASCII Art
ASCII Art https://npms.io/search?q=ASCII art ASCII Art Text to ASCII Art Generator (TAAG) http://pat ...