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

事件循环、宏任务、微任务的关系如图所示:

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

遇到Promisenew 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中,记为process2new 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执行机制相关推荐

  1. android子线程没有运行完,android假如主线程依赖子线程A的执行结果,如何让A执行完成,之后主线程再往下执行呢?...

    /* String ObjectResult="原先的结果"; //使用VOLLY框架(与问题无关) JsonObjectRequest jsonObjectRequest = n ...

  2. android广播怎样运行在子线程,android假如主线程依赖子线程A的执行结果,如何让A执行完成,之后主线程再往下执行呢?...

    抛开你这段代码不看,单根据你的标题来回答: android假如主线程依赖子线程A的执行结果,如何让A执行完成,之后主线程再往下执行呢? 需要在子线程执行完成的地方,通过主线程的Handler发送一条消 ...

  3. var和function谁先优先执行_浅谈JavaScript 的执行顺序

    JavaScript是一种描述型脚本语言,它不同于java或C#等编译性语言,它不需要进行编译成中间语言,而是由浏览器进行动态地解析与执行.如果你不能理解javaScript语言的运行机制,或者简单地 ...

  4. 面试官:如何让主线程等待所有的子线程执行结束之后再执行

    java 主线程等待所有子线程执行完毕在执行,在工作总往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完后再把那段逻辑的处理结果进行汇总(比如用户下单一个产品,后台会做一系列的处理,为了提高 ...

  5. 面试官:如何让主线程等待所有的子线程执行结束之后再执行?我懵了

    使用Thread的join方法 package com.qcy.testThreadFinish;/*** @author qcy* @create 2020/09/09 17:05:23*/ pub ...

  6. 深入理解JavaScript执行上下文与作用域链

    文章目录 前言 一.执行上下文 1.类型 2.生命周期 2.1.创建变量对象 2.2.this绑定 2.3.创建作用域链 总结 前言 只有理解了执行上下文与作用域链,才能更好地理解JavaScript ...

  7. shell中执行某条语句失败能不能重复执行_如何理解Mysql中的事务隔离级别?

    要说清楚Mysql中的事务隔离级别,我们先从事务的定义说起.事务,是一个或一组sql语句组成的一个执行单元,这个执行单元要么全部执行,要么全部不执行.整个单独单元作为一个不可分割的整体,如果单元中某条 ...

  8. JavaScript可否多线程? 深入理解JavaScript定时机制

    JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如 setTimeout( ...

  9. 深入理解JavaScript定时机制

    容易欺骗别人感情的JavaScript定时器 本文地址: http://www.laruence.com/2009/09/23/1089.html 转载文章 JavaScript的setTimeout ...

最新文章

  1. 我常用的那些linux命令
  2. 2019最后一期—宏基因组分析技术研讨会
  3. vc mysql控件_VC++使用ActiveX控件连接和操作数据库
  4. 【OFDM】基于simulink的OFDM系统仿真
  5. 从Http它被连接到WebSocket
  6. 廖雪峰python2.7教程_Python 2.7教程
  7. 拓扑排序(Topological Sorting)
  8. c 运算符##_C#程序演示关系运算符的示例
  9. semantic ui中文文档_Vuetify-广受欢迎的Material风格的开源UI框架
  10. SARscape操作:Sentinel-1 SLC影像镶嵌、裁切
  11. linux配置命令route,linux路由配置命令route学习
  12. 使用TreeMap对要签名做排序ASCII码排序
  13. 自顶向下与自底向上编程思想的对比
  14. git clone之报错git@gitee.com: Permission denied (publickey).fatal: Could not read from remote repositor
  15. 欢迎高校选修云创大数据免费在线直播课!
  16. 书香云集Pc版书籍导出
  17. 灰色关联分析法无量纲处理方法
  18. 你明白什么是会签?工作流+会签应用
  19. 年薪50万+的90后程序员都经历了什么?
  20. 算法题--第几个幸运数

热门文章

  1. TikTok 与 Oracle 的交易将开创两个危险的先例
  2. 编程语言“鄙视链” +1?亚马逊力捧 Rust,Go 技术负责人连发 14 条推特抵制“拉踩”
  3. 仅用一年时间,蓝巨人 IBM 如何开发出首台个人计算机?
  4. .NET 开源的免费午餐结束了?
  5. Python 被爆大 Bug,攻击者可远程代码执行漏洞!
  6. CSDN学院全面改版啦!这次真的“搞大”了!
  7. 蚂蚁上市员工人均一套大 House,阿里程序员身价和这匹配吗?
  8. 手持“六脉神剑”、横跨软硬领域,揭晓英特尔构筑智慧云基石宝典!
  9. 比尔·盖茨退出微软董事会,回顾盖茨与微软的传奇故事
  10. 标贝科技推出「留声机」TTS方案,高还原、个性化声效提升交互意愿