在主线程执行_深入理解JavaScript执行机制
![](/assets/blank.gif)
1、预备知识
- JavaScript是一门单线程语言。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
- 所有任务可以分为两种,一种是同步任务,另一种是异步任务。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程,而进入"任务队列"的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
- 异步执行的运行机制如下: (1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。 (2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。 (3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。 (4)主线程不断重复上面的第三步。
2、什么是事件循环(event-loop)
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。
具体的解释说明如下:
1、选择当前要执行的宏任务队列,选择一个最先进入任务队列的宏任务,如果没有宏任务可以选择,则会跳转至microtask的执行步骤。
2、将事件循环的当前运行宏任务设置为已选择的宏任务。
3、运行宏任务。
4、将事件循环的当前运行任务设置为null。
5、将运行完的宏任务从宏任务队列中移除。
6、microtasks步骤:进入microtask检查点。
7、更新界面渲染。
8、返回第一步。
3、什么是宏任务、微任务
简单理解
宏任务包括script(整体代码)、I/O、setTimeout、setInterval、setImmediate(Node)、requestAnimationFrame(Chrome)
微任务包括process.nextTick(Node)、MutationObserver(Chrome)、Promise
事件循环、宏任务、微任务的关系如图所示:
![](/assets/blank.gif)
4、Event-loop的工作机制
两道例题:
(1)运行环境(Chrome浏览器)
console.log('script start');setTimeout(function () {console.log('setTimeout---0');
}, 0);setTimeout(function () {console.log('setTimeout---200');setTimeout(function () {console.log('inner-setTimeout---0');});Promise.resolve().then(function () {console.log('promise5');});
}, 200);Promise.resolve().then(function () {console.log('promise1');
}).then(function () {console.log('promise2');
});
Promise.resolve().then(function () {console.log('promise3');
});
console.log('script end');
解释:
1、首先顺序执行完主进程上的同步任务,第一句和最后一句,输出script start、script end
2、接着遇到setTimeout 0,它的作用是在 0ms 后将回调函数放到宏任务队列中(这个任务在下一次的事件循环中执行)。
3、接着遇到setTimeout 200,它的作用是在 200ms 后将回调函数放到宏任务队列中(这个任务在下一次的事件循环中执行)。
4、同步任务执行完之后,首先检查微任务队列,即 microtask队列, 发现此队列不为空,执行第一个promise的then回调,输出 'promise1',然后执行第二个promise的then回调,输出'promise3',由于第一个promise的.then()的返回依然是promise,所以第二个.then()会放到microtask队列继续执行,输出 'promise2';
5、此时microtask队列为空,进入下一个事件循环,检查宏任务队列,发现有 setTimeout的回调函数,立即执行回调函数输出 'setTimeout---0',检查microtask 队列,队列为空,进入下一次事件循环。
6、检查宏任务队列,发现有 setTimeout的回调函数,立即执行回调函数输出'setTimeout---200'。
7、接着遇到setTimeout 0,它的作用是在 0ms 后将回调函数放到宏任务队列中,检查微任务队列,即 microtask 队列, 发现此队列不为空,执行promise的then回调,输出'promise5'。
8、此时microtask队列为空,进入下一个事件循环,检查宏任务队列,发现有 setTimeout 的回调函数,立即执行回调函数输出,输出'inner-setTimeout---0'.代码执行结束。
最终输出结果如下(Chrome 版本号:81.0.4044.138)
script start
script end
promise1
promise3
promise2
setTimeout---0
setTimeout---200
promise5
inner-setTimeout---0
(2)运行环境(Node.js)
console.log('1');setTimeout(function() {console.log('2');process.nextTick(function() {console.log('3');})new Promise(function(resolve) {console.log('4');resolve();}).then(function() {console.log('5')})
})
process.nextTick(function() {console.log('6');
})
new Promise(function(resolve) {console.log('7');resolve();
}).then(function() {console.log('8')
})setTimeout(function() {console.log('9');process.nextTick(function() {console.log('10');})new Promise(function(resolve) {console.log('11');resolve();}).then(function() {console.log('12')})
})
第一轮事件循环:
- 整体script代码作为第一个宏任务进入主线程,遇到
console.log
,输出1。 - 遇到
setTimeout
,其回调函数被分发到宏任务Event Queue中。我们暂且记为setTimeout1
。 - 遇到
process.nextTick()
,其回调函数被分发到微任务Event Queue中。我们记为process1
。
遇到Promise
,new Promise
直接执行,输出7。then
被分发到微任务Event Queue中。我们记为then1
。
- 又遇到了
setTimeout
,其回调函数被分发到宏任务Event Queue中,我们记为setTimeout2
。
现在的任务队列情况如下
宏任务:setTimeout1、setTimeout2
微任务:process1、then1
现在执行微任务,输出6、8。至此,第一轮事件循环结束!输出1、7、6、8
第二轮事件循环:
从setTimeout1宏任务开始,输出2,接下来遇到了process.nextTick()
,同样将其分发到微任务Event Queue中,记为process2
。new Promise
立即执行输出4,then
也分发到微任务Event Queue中,记为then2
。
此时的任务队列情况如下
宏任务:setTimeout2
微任务:process2、then2
现在执行微任务,输出3、5。至此,第二轮事件循环结束!输出2、4、3、5
第三轮事件循环:
只剩setTimeout2了,执行,直接输出9,将process.nextTick()
分发到微任务Event Queue中。记为process3
,直接执行new Promise
,输出11,将then
分发到微任务Event Queue中,记为then3
此时的任务队列情况如下
宏任务:无
微任务:process3、then3
现在执行微任务,输出9、11、10、12。至此,第三轮事件循环结束!
完整的输出结果如下:(Nodejs版本号 v12.16.1)
1,7,6,8,2,4,3,5,9,11,10,12
5、参考资料
https://juejin.im/post/59e85eebf265da430d571f89
https://segmentfault.com/a/1190000018181334
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
在主线程执行_深入理解JavaScript执行机制相关推荐
- android子线程没有运行完,android假如主线程依赖子线程A的执行结果,如何让A执行完成,之后主线程再往下执行呢?...
/* String ObjectResult="原先的结果"; //使用VOLLY框架(与问题无关) JsonObjectRequest jsonObjectRequest = n ...
- android广播怎样运行在子线程,android假如主线程依赖子线程A的执行结果,如何让A执行完成,之后主线程再往下执行呢?...
抛开你这段代码不看,单根据你的标题来回答: android假如主线程依赖子线程A的执行结果,如何让A执行完成,之后主线程再往下执行呢? 需要在子线程执行完成的地方,通过主线程的Handler发送一条消 ...
- var和function谁先优先执行_浅谈JavaScript 的执行顺序
JavaScript是一种描述型脚本语言,它不同于java或C#等编译性语言,它不需要进行编译成中间语言,而是由浏览器进行动态地解析与执行.如果你不能理解javaScript语言的运行机制,或者简单地 ...
- 面试官:如何让主线程等待所有的子线程执行结束之后再执行
java 主线程等待所有子线程执行完毕在执行,在工作总往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完后再把那段逻辑的处理结果进行汇总(比如用户下单一个产品,后台会做一系列的处理,为了提高 ...
- 面试官:如何让主线程等待所有的子线程执行结束之后再执行?我懵了
使用Thread的join方法 package com.qcy.testThreadFinish;/*** @author qcy* @create 2020/09/09 17:05:23*/ pub ...
- 深入理解JavaScript执行上下文与作用域链
文章目录 前言 一.执行上下文 1.类型 2.生命周期 2.1.创建变量对象 2.2.this绑定 2.3.创建作用域链 总结 前言 只有理解了执行上下文与作用域链,才能更好地理解JavaScript ...
- shell中执行某条语句失败能不能重复执行_如何理解Mysql中的事务隔离级别?
要说清楚Mysql中的事务隔离级别,我们先从事务的定义说起.事务,是一个或一组sql语句组成的一个执行单元,这个执行单元要么全部执行,要么全部不执行.整个单独单元作为一个不可分割的整体,如果单元中某条 ...
- JavaScript可否多线程? 深入理解JavaScript定时机制
JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如 setTimeout( ...
- 深入理解JavaScript定时机制
容易欺骗别人感情的JavaScript定时器 本文地址: http://www.laruence.com/2009/09/23/1089.html 转载文章 JavaScript的setTimeout ...
最新文章
- 我常用的那些linux命令
- 2019最后一期—宏基因组分析技术研讨会
- vc mysql控件_VC++使用ActiveX控件连接和操作数据库
- 【OFDM】基于simulink的OFDM系统仿真
- 从Http它被连接到WebSocket
- 廖雪峰python2.7教程_Python 2.7教程
- 拓扑排序(Topological Sorting)
- c 运算符##_C#程序演示关系运算符的示例
- semantic ui中文文档_Vuetify-广受欢迎的Material风格的开源UI框架
- SARscape操作:Sentinel-1 SLC影像镶嵌、裁切
- linux配置命令route,linux路由配置命令route学习
- 使用TreeMap对要签名做排序ASCII码排序
- 自顶向下与自底向上编程思想的对比
- git clone之报错git@gitee.com: Permission denied (publickey).fatal: Could not read from remote repositor
- 欢迎高校选修云创大数据免费在线直播课!
- 书香云集Pc版书籍导出
- 灰色关联分析法无量纲处理方法
- 你明白什么是会签?工作流+会签应用
- 年薪50万+的90后程序员都经历了什么?
- 算法题--第几个幸运数
热门文章
- TikTok 与 Oracle 的交易将开创两个危险的先例
- 编程语言“鄙视链” +1?亚马逊力捧 Rust,Go 技术负责人连发 14 条推特抵制“拉踩”
- 仅用一年时间,蓝巨人 IBM 如何开发出首台个人计算机?
- .NET 开源的免费午餐结束了?
- Python 被爆大 Bug,攻击者可远程代码执行漏洞!
- CSDN学院全面改版啦!这次真的“搞大”了!
- 蚂蚁上市员工人均一套大 House,阿里程序员身价和这匹配吗?
- 手持“六脉神剑”、横跨软硬领域,揭晓英特尔构筑智慧云基石宝典!
- 比尔·盖茨退出微软董事会,回顾盖茨与微软的传奇故事
- 标贝科技推出「留声机」TTS方案,高还原、个性化声效提升交互意愿