JavaScript 事件循环机制

Stella981
• 阅读 599

javascript是一门单线程的非阻塞的脚本语言。单线程意味着javascript在执行代码的任何时候,都只有一个主线程来处理所有的任务。

那么javascript引擎是如何实现这一点的呢?

因为事件循环(event loop)。先上图:

JavaScript 事件循环机制

图片解读:

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

简单例子

我们来一个简单的例子来说明下:

console.log('1');
setTimeout(() => {
    console.log('2');
}, 0)
console.log('3');
复制代码

上面的代码将输出下面的结果:

1
3
2
复制代码

因为setTimeout是一个异步的任务,所以会在最后才执行。

那么,我们来个复杂点的例子:

复杂例子

 console.log('1');
 setTimeout(() => {
     console.log('2')
 }, 1000);
 new Promise((resolve, reject) => {
     setTimeout(() => {
         console.log('3');
     }, 0);
     console.log('4');
     resolve();
     console.log('5');
 }).then(() => {
     console.log('6');
 });
 console.log('7');
复制代码

上面的代码输出的结果是:

1
4
5
7
6
3
2
复制代码

看到这代码的时候是不是有些蒙圈?在我们揭开谜底之前,先来了解下微任务和宏任务

微任务和宏任务

微任务和宏任务都是异步的任务,他们都属于队列,主要区别是它们的执行顺序--微任务会比宏任务先执行。

宏任务包含有:setTimeout, setInterval, setImmediate, I/O, UI rendering

微任务包含有:process.nextTick, promise.then, MutationObserver

嗯~回到上面的代码,如下:

 console.log('1');
 setTimeout(() => {
     console.log('2')
 }, 1000);
 new Promise((resolve, reject) => {
     setTimeout(() => {
         console.log('3');
     }, 0);
     console.log('4');
     resolve();
     console.log('5');
 }).then(() => {
     console.log('6');
 });
 console.log('7');
复制代码

在执行到new Promise的时候会立马新建一个promise对象并立即执行。所以会输出 1,4,5,而then则会在Event Table中注册成回调函数并放在微任务队列中,而两个setTimeout(输出3)和setTimeout(输出2,1s后完成的啊)会被先后注册成回调函数并放在宏任务队列中。

理解了上面的一些原理之后,我们再来练下手...

console.log(1)
process.nextTick(() => {
  console.log(8)
  setTimeout(() => {
    console.log(9)
  })
})
setTimeout(() => {
  console.log(2)
  new Promise(() => {
    console.log(11)
  })
})
let promise = new Promise((resolve,reject) => {
  setTimeout(() => {
    console.log(10)
  })
  resolve()
  console.log(4)
})
fn()
console.log(3)
promise.then(() => {
  console.log(12)
})
function fn(){
  console.log(6)
}
复制代码

得到的结果是:

1
4
6
3
8
12
2
11
10
9
复制代码

客官可以画下图整理下思路,然后代码运行验证一下啊💨

参考&后话

文章首发javascript事件循环机制,更多的内容,请戳我的博客进行了解,能留个star就更好了💨

.markdown-body pre,.markdown-body pre>code.hljs{color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:700}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:teal}.hljs-doctag,.hljs-string{color:#d14}.hljs-section,.hljs-selector-id,.hljs-title{color:#900;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-link,.hljs-regexp{color:#009926}.hljs-bullet,.hljs-symbol{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

本文同步分享在 博客“Jimmy”(JueJin)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Javascript并发模型和事件循环
JavaScript的"并发模型"是基于事件循环的,这个并发模型有别于Java的多线程,javascript的并发是单线程的。Javascript中有个重要一块,EventLoop,能把单线程的JavaScript使出多线程的感觉。"EventLoop是一个程序结构,用于等待和发送消息和事件。(aprogrammingconst
Stella981 Stella981
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Easter79 Easter79
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这