javascript的event loop事件循环

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

感觉还挺有意思的,

写个博客以供分享

先看看这个面试题目:

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

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 QueueEvent Loop

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

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

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

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


setTimeout

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

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

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

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

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


宏任务和微任务

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

微任务:promise

宏任务:setTimeout、setInterval、setImmediate

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

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

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

以上。

javascript的event loop事件循环的更多相关文章

  1. node.js中对Event Loop事件循环的理解

    javascript是单线程的,所以任务的执行都需要排队,任务分为两种,一种是同步任务,一种是异步任务. 同步任务是进入主线程上排队执行的任务,上一个任务执行完了,下一个任务才会执行. 异步任务是不进 ...

  2. 为什么JS是单线程?JS中的Event Loop(事件循环)?JS如何实现异步?setimeout?

    https://segmentfault.com/a/1190000012806637 https://www.jianshu.com/p/93d756db8c81 首先,请牢记2点: (1) JS是 ...

  3. Event Loop事件循环,GET!

    JS中比较让人头疼的问题之一要算异步事件了,比如我们经常要等后台返回数据后进行dom操作,又比如我们要设置一个定时器完成特定的要求.在这些同步与异步事件里,异步事件肯定是在同步事件之后的,但是异步事件 ...

  4. 进程,线程,Event Loop(事件循环),Web Worker

    线程,是程序执行流的最小单位.线程可与同属一个进程的其他线程共享所拥有的全部资源,同一进程中的多个线程之间可以并发执行.线程有就绪,阻塞,运行三种基本状态. 阮一峰大神针对进程和线程的类比,很是形象: ...

  5. 浅谈 Event loop (事件循环)

    从Event Loop谈JS的运行机制 先来理解一个概念: JS分为同步任务和异步任务 同步任务都在主线程上执行,形成一个执行栈 Execute Content Stack 主线程之外,事件触发线程管 ...

  6. js event loop事件循环

    浏览器环境 以下两段代码是等价的.req对事件的回调设置,实际上就是当前主线程任务队列的任务. var req = new XMLHttpRequest(); req.open('GET', url) ...

  7. JavaScript event loop事件循环 macrotask与microtask

    macrotask  姑且称为宏任务,在很多上下文也被简称为task.例如: setTimeout, setInterval, setImmediate, I/O, UI rendering. mic ...

  8. Javascript并发模型和事件循环

    Javascript并发模型和事件循环 JavaScript的"并发模型"是基于事件循环的,这个并发模型有别于Java的多线程, javascript的并发是单线程的. Javas ...

  9. JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧

    原文地址:How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding wi ...

随机推荐

  1. 第十二届GOPS全球运维大会2019深圳站即将开幕

    第十二届 GOPS 全球运维大会深圳站 会议召开时间:2019年4月12日-13日 会议召开地点:深圳圣淘沙酒店(翡翠店) 会议主办单位:高效运维社区 票务合作伙伴:活动家 会议报名地址:https: ...

  2. 从Win32程序中的主函数中获取命令行参数

    在标准C或者Win32控制台程序的main函数中,它们都有两个参数:"argc" 和 "argv",如下所示: int main(int argc, char ...

  3. php .htaccess 伪静态

    # #以下是网站伪静态正则 # RewriteEngine On RewriteRule ^index.html$ index.php RewriteRule ^about.html$ about.p ...

  4. 第九篇——Struts2的拦截器

    拦截器: Struts2大多数核心功能都是通过拦截器实现的,每个拦截器完成某项功能: 拦截器方法在Action执行之前或之后执行. 工作原理: 拦截器的执行过程是一个递归的过程 action请求--& ...

  5. Atlassian JavaScript load error(配置Atlassian的时候报无法加载script文件)

    等我弄好的时候,发现报错的图已经成为历史了,所以就没有截图了. Atlassian JavaScript load error We tried to load scripts but somethi ...

  6. myBatis学习之路1-基本功能实现

    myBatis也是一个持久型框架,相较于hibernate来说,算是轻量级的. 1.配置mybatis环境 相关jar下载地址:mybatis+mysalJAR包 2.新建一个java project ...

  7. Sql Server性能定位及改善

    使用SQL Server做为后台数据库的应用程序,当程序操作起来很慢的时候,可能是数据库操作被某个进程Block住了,可以使用以下语句查询目前正在运行的进程 select request_sessio ...

  8. wait(), notify(), notifyAll()等方法介绍

    在Object.java中,定义了wait(), notify()和notifyAll()等接口.wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁.而not ...

  9. Python sqlalchemy orm 常用操作

    增add # 创建表1 # 注:高级封装 import sqlalchemy # 调用链接数据库 from sqlalchemy import create_engine # 调用基类Base fro ...

  10. RESTful API 设计指南-阮一峰

    作者: 阮一峰 日期: 2014年5月22日 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......). 因此,必须有一种统一的机制 ...