Event loops秒懂
Event loops秒懂
简介
JS是一种单线程脚本语言,为什么要设计成单线程?
举例说明,假设JS是多线程脚本语言,A线程修改了DOM,B线程删除了DOM,一旦B线程先执行完,DOM被删除了,A线程就会报错,为了避免类似这种问题,JS被设计为单线程
单线程的问题是一次只能做一件事,要做第二件事,必须等第一件事先做完。假如有个需求是每5分钟更新一次数据,用setInterval去计时,那么这个页面JS永远无法做其他事了,线程一直被setInterval占用着。为了让JS可以同时执行多个任务,引入了Event loops(事件循环)机制
Event loops分为2种队列,task队列、microtask队列,业界一般把tasks队列称为宏任务,microtask翻译过来叫微任务。
task队列和microtask队列执行顺序是怎样的?
代码刚开始执行时,整体代码就是一个task,立即执行这个task,在执行过程中
- 遇到setTimeout、setInterval、I/O、setImmediate(Nodejs环境)就往task队列里push
- 遇到Promise.then/catch/finally、MutationObserver、process.nextTick(Nodejs环境)就往microtask队列里push
每执行完一个task,就会查看microtask队列里有没有待执行的任务,如果有,则按先进先出的原则依次执行其中的任务,执行完了再回到task队列,取下一个task执行;如果没有,就直接执行下一个task,以此类推,这就是Event loops
案例
按照以上规则,思考以下代码输出顺序
// 先自己思考一下输出顺序
console.log('script start');
setTimeout(function () {
console.log('timeout');
}, 0);
Promise.resolve().then(function () {
console.log('promise');
}).then(function () {
console.log('then');
});
console.log('script end');
分析:
- 整体代码做为第一个task,从上到下开始执行
- 输出
script start - 遇到
setTimeout(),push到task队列,等待执行 - 遇到
Promise第一个then(),push到microtask队列,等待执行 - 输出
script end - 第一个task执行完成,查看microtask队列,有任务,开始执行
- 输出
promise,遇到第二个then(),push到microtask队列 - 输出刚刚push的
then - microtask队列执行完成,取下一个task执行
- 输出
timeout
输出顺序为:script start -> script end -> promise -> then -> timeout
升级,return Promise
将上面例子的Promise升级了一下,假设Promise.then内部又有Promise,怎么分析?
Promise.resolve().then(function () {
console.log('promise');
return new Promise((resolve, reject) => {
console.log('inner promise');
resolve();
}).then(() => {
console.log('inner then1');
}).then(() => {
console.log('inner then2');
})
}).then(function () {
console.log('then');
});
分析:
- 整体代码为第一个task,从上到下开始执行
- 遇到第一个then,push到microtask队列
- 第一个task执行完成,查看microtask队列,有任务,开始执行
- 输出
promise - 进入内部new Promise,输出
inner promise - 遇到内部new Promise第一个then,push到microtask队列
- 输出刚刚push的
inner then1 - 遇到内部new Promise第二个then,push到microtask队列
- 输出刚刚push的
inner then2 - 内部new Promise执行完,外部promise第一个then拿到返回值,继续往下,遇到它的第二个then,push到microtask队列
- 输出刚刚push的
then
输出顺序为:promise -> inner promise -> inner then1 -> inner then2 -> then
注意:then链式调用时,如果前面的then方法return了一个新Promise对象,后面的then会等待这个新Promise对象状态发生变化后,才会执行,换句话说,两个then的执行由异步变成同步了,如果把return去掉呢?
变化,无return Promise
Promise.resolve().then(function () {
console.log('promise');
new Promise((resolve, reject) => {
console.log('inner promise');
resolve();
}).then(() => {
console.log('inner then1');
}).then(() => {
console.log('inner then2');
})
}).then(function () {
console.log('then');
});
分析:
- 整体代码为第一个task,从上到下开始执行
- 遇到第一个then,push到microtask队列
- 第一个task执行完成,查看microtask队列,有任务,开始执行
- 输出
promise - 进入内部new Promise,输出
inner promise - 遇到内部new Promise第一个then,push到microtask队列,前6步跟上面一样
- 此时,外部Promise对象的第一个then里的同步代码已经执行完了,接着执行它的第二个then,push到microtask队列
- 继续执行microtask,输出
inner then1 - 到了内部new Promise的第二个then,push到microtask队列
- 继续执行microtask,输出
then - 最后输出
inner then2
输出顺序为:promise -> inner promise -> inner then1 -> then -> inner then2
总结:return去掉之后,前面的then执行完同步代码就会跳到下一个then
思考
最后思考一个问题,下面这个错误能被catch捕获到吗?为什么?
new Promise(function (resolve, reject) {
setTimeout(function () {
throw new Error('test')
}, 0)
resolve('ok');
}).catch(err => {
console.error(err);
});
熟悉了Event loops,回答这个问题就很容易:不能捕获到。因为错误在setTimeout内部抛出,setTimeout和.catch并不在同一个task执行,抛出错误的时候,catch已经执行完了。
觉得不错,点个star吧Github
Event loops秒懂的更多相关文章
- 协程系列之Event Loops
Event Loops 事件循环 事件是由程序的一部分在特定条件下发出的消息,循环是在某种条件下完成并执行某个程序直到它完成的构造,因此,事件循环是一个循环,它允许用户订阅事件传输并注册处理程序/回调 ...
- queueMicrotask & EventLoop & macrotask & microtask
queueMicrotask https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/queueMicro ...
- [转]How WebKit’s Event Model Works
原文:https://homes.cs.washington.edu/~burg/projects/timelapse/articles/webkit-event-implementation/ Fi ...
- event & signals & threads
The Event Systemhttp://doc.qt.io/qt-4.8/eventsandfilters.html Each thread can have its own event loo ...
- nodejs(五)同步异步--BLOCKING THE EVENT LOOP
1.BLOCKING THE EVENT LOOP Node and JavaScript runtimes in general are single-threaded event loops. O ...
- 从event loop规范探究javaScript异步及浏览器更新渲染时机
异步的思考 event loops隐藏得比较深,很多人对它很陌生.但提起异步,相信每个人都知道.异步背后的“靠山”就是event loops.这里的异步准确的说应该叫浏览器的event loops或者 ...
- 浏览器组成、线程及event loop
浏览器组成 User interface: a. Every part of the browser display, except the window. b. The address bar, b ...
- 事件轮询 event loop
Understanding the node.js event loop The first basic thesis of node.js is that I/O is expensive: So ...
- How an Event Enters a Cocoa Application
How an Event Enters a Cocoa Application An event is a low-level record of a user action that is usua ...
随机推荐
- 公式化学习requests(第一卷)
个人来讲我不是很喜欢REQURST这个第三方模块,一点不好用不如URLLIB,但身为技术人员,模块你可以不用但是你得会,就像生活质量我这个东西我不用但是我得有 先拿百度做个案例: 看下代码 结果为: ...
- 用ES6和fetch封装网络请求
导读: fetch: 这个方法是ES2017中新增的特性,这个特性出来后给人一种传统ajax已死的感觉,其实它的作用是替代浏览器原生的XMLHttpRequest异步请求,我们在日常的开发中,基本不会 ...
- VS自身的单元测试方法DEMO
///用来修饰测试类 [TestClass()] public class Program { private TestContext testContextInstance; /// <sum ...
- 机器学习入门教程-k-近邻
k-近邻算法原理 像之前提到的那样,机器学习的一个要点就是分类,对于分类来说有许多不同的算法,所谓的物以聚类,分以群分.我们非常的清楚,一个地域的人群,不管在生活习惯,还是在习俗上都是非常相似的,也就 ...
- Bootstrap插件及其应用方法网址
全局CCS样式 https://v3.bootcss.com/css/#type-lists 组件 https://v3.bootcss.com/components/#pagination Boot ...
- react和vue
react整体的思路就是函数式,所以推崇纯组件,数据不可变,单向数据流,当然需要双向的地方也可以做到,比如结合redux-form,而vue是基于可变数据的,支持双向绑定.react组件的扩展一般是通 ...
- 4K手机能拯救索尼手机吗?
智能手机屏幕分辨率究竟达到多少才是极限,一直是业内争论不休的问题.从低分辨率一路走来,直到iPhone 4搭载视网膜屏,业内才有了一个较为统一的认知:屏幕起码要在合适距离下看不到文字.图像虚影,才称得 ...
- web端手机方向传感器闲谈
因为工作需要,这段时间接触的手机传感器比较多.总体来说,市场上的传感器表现参差不齐.IPhone在传感器表现方面卓越,而安卓由于什么机型都有,则显得差强人意. 首先还是说说怎么在web端调用手机传感器 ...
- Elasticsearch,Filebeat,Kibana部署,添加图表及elastalert报警
服务端安装 Elasticsearch和Kibana(需要安装openjdk1.8以上) 安装方法:https://www.elastic.co以Ubuntu为例: wget -qO - https: ...
- Hihocoder1456 Rikka with Lattice
众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:勇太有一个$n times m$的点阵,他想要从这$n times m$个点中选出三个点 ${A,B,C}$,满足 ...