javascript中的event loop事件循环详解


Posted in Javascript onDecember 14, 2018

前言

javascript是单线程的语言,也就是说,同一个时间只能做一件事。而这个单线程的特性,与它的用途有关,作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质

这是今天一个朋友发给我的一个面试题,

感觉还挺有意思的,

写个博客以供分享

先看看这个面试题目:

观察下面的代码,写出输出结果

console.log('0')
setTimeout(function () {
 console.log('1');
});

new Promise(function(resolve,reject){
 console.log('2')
 resolve(3)
}).then(function(val){
 console.log(val)
})
console.log(4)

输出结果: “0” “2” 4 3 “1”

今天主要是分析为什么输出结果是这样的?这就和 javascript 的执行机制密切相关了.

Event Queue 和 Event Loop

javascript 是一门单线程的语言, 这就意味着在执行代码的时候, 都只有一个主线程来处理所有的任务.

我们都知道 javascript 包括同步代码和异步代码, 那么 javascript 是怎么处理这两种情况的呢?

  • 同步和异步任务分别进入不同的执行 场所, 同步的进入主线程,异步的进入 Event Table 并注册函数
  • 当指定的事情完成时, Event Table 会将这个函数(回调函数)移入 Event Queue
  • 主线程内的任务执行完毕为空, 会去 Event Queue 读取对应的函数,进入主线程执行
  • 上述过程会不断重复, 也就是常说的 Event Loop(事件循环)

这里我们引进了 Event Queue 事件队列这一概念. 所有异步操作的回调都会进入到这里. 然后等到主线程空闲, 就会从这里调取回调执行.

setTimeout

setTimeout 相信大家都有使用过, 可以延时执行并且是异步执行的.

但是有时候我们得到的结果往往是代码实际执行的时间比我们想要延时执行的时间要久。这又是为什么呢?

这就和我们之前所说的 Event Loop 有关了, 我们可以来具体看下 setTimeout 的执行步骤:

setTimeout(function () {
asyncFn()
}, 1000);

syncFn()
  • asyncFn 将异步执行函数放在 Event Table, 并且开始计时
  • 开始执行 syncFn, 但是 syncFn 可能需要处理的内容很多, 执行时间超过 1 秒, 但是计时还在继续
  • 计时到达 1 秒, setTimeout 延时完成, asyncFn 进入 Event Queue 事件队列, 但是主线程还在执行, 所以只能等待
  • syncFn 执行完成, 此时 asyncFn 从事件队列中进入主线程执行

所以有时候会出现代码实际执行时间比延时时间长的情况。

宏任务和微任务

之前我们说过异步任务会进入到事件队列中, 不同类型的任务会进入到不同的队列中, 比如宏任务会进入到宏任务队列中, 微任务会进入到微任务队列中.

我们只要记住 当当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行

这时候我们就可以解释一开始的代码执行结果了:

  • 主线程执行按顺序代码
  • 遇到 setTimeout, 回调进入到宏任务队列上
  • 遇到 Promise, 立即执行, then 函数进入到微任务队列
  • 同步代码执行结束, 主线程检查是否存在微任务, 发现 then, 执行
  • 微任务执行完毕, 再去查找宏任务 setTimeout, 执行
  • setTimeout 执行结束, 检查是否存在微任务, 不存在, 结束.

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
用javascript实现在小方框中浏览大图的代码
Aug 14 Javascript
js cookies 常见网页木马挂马代码 24小时只加载一次
Apr 13 Javascript
使用js判断数组中是否包含某一元素(类似于php中的in_array())
Dec 12 Javascript
js如何判断用户是否是用微信浏览器
Jun 05 Javascript
js实现的标题栏新消息闪烁提示效果
Jun 06 Javascript
Angularjs自定义指令实现三级联动 选择地理位置
Feb 13 Javascript
vue.js绑定事件监听器示例【基于v-on事件绑定】
Jul 07 Javascript
vue组件命名和props命名代码详解
Sep 01 Javascript
详解element-ui中表单验证的三种方式
Sep 18 Javascript
JavaScript实现简单的图片切换功能(实例代码)
Apr 10 Javascript
vue实现淘宝购物车功能
Apr 20 Javascript
vue如何实现关闭对话框后刷新列表
Apr 08 Vue.js
如何在Vue中使用CleaveJS格式化你的输入内容
Dec 14 #Javascript
webpack配置proxyTable时pathRewrite无效的解决方法
Dec 13 #Javascript
node.js学习笔记之koa框架和简单爬虫练习
Dec 13 #Javascript
浅谈vuex actions和mutation的异曲同工
Dec 13 #Javascript
webpack3里使用uglifyjs压缩js时打包报错的解决
Dec 13 #Javascript
javascript对HTML字符转义与反转义
Dec 13 #Javascript
Web安全之XSS攻击与防御小结
Dec 13 #Javascript
You might like
PHP字符转义相关函数小结(php下的转义字符串)
2007/04/12 PHP
深入理解用mysql_fetch_row()以数组的形式返回查询结果
2013/06/05 PHP
zend Framework中的Layout(模块化得布局)详解
2013/06/28 PHP
详解php设置session(过期、失效、有效期)
2015/11/12 PHP
PHP处理二进制数据的实现方法
2016/06/13 PHP
CI框架数据库查询缓存优化的方法
2016/11/21 PHP
BOOM vs RR BO5 第四场 2.14
2021/03/10 DOTA
IE8下关于querySelectorAll()的问题
2010/05/13 Javascript
jquery触发a标签跳转事件示例代码
2013/07/21 Javascript
window.navigate 与 window.location.href 的使用区别介绍
2013/09/21 Javascript
javascript匿名函数实例分析
2014/11/18 Javascript
Javascript中Date类型和Math类型详解
2016/02/27 Javascript
基于JS实现textarea中获取动态剩余字数的方法
2016/05/25 Javascript
JS递归遍历对象获得Value值方法技巧
2016/06/14 Javascript
js替换字符串中所有指定的字符(实现代码)
2016/08/17 Javascript
JS实现简易刻度时钟示例代码
2017/03/11 Javascript
Vue.js实战之Vuex的入门教程
2017/04/01 Javascript
基于jQuery实现图片推拉门动画效果的两种方法
2017/08/26 jQuery
详解PHP后期静态绑定分析与应用
2018/03/21 Javascript
jQuery easyui datagird编辑行删除行功能的实现代码
2018/09/20 jQuery
vue cli 3.0 搭建项目的图文教程
2019/05/17 Javascript
一步一步实现Vue的响应式(对象观测)
2019/09/02 Javascript
Nuxt.js实现一个SSR的前端博客的示例代码
2019/09/06 Javascript
Vue computed 计算属性代码实例
2020/04/22 Javascript
文章或博客自动生成章节目录索引(支持三级)的实现代码
2020/05/10 Javascript
node.js文件的复制、创建文件夹等相关操作
2021/02/05 Javascript
通过python将大量文件按修改时间分类的方法
2018/10/17 Python
pycharm恢复默认设置或者是替换pycharm的解释器实例
2018/10/29 Python
通过python连接Linux命令行代码实例
2020/02/18 Python
印尼综合在线预订网站:Tiket.com(机票、酒店、火车、租车和娱乐)
2018/10/11 全球购物
绝对经典成功的大学生推荐信
2013/11/08 职场文书
幼儿园教师奖惩制度
2014/02/01 职场文书
2014年人事部工作总结
2014/12/03 职场文书
奖金申请报告模板
2015/05/15 职场文书
志愿者工作心得体会
2016/01/15 职场文书
react 项目中引入图片的几种方式
2021/06/02 Javascript