JavaScript同步、异步及事件循环

同步、异步

JS是单线程的,每次只能做一件事情。像以下这种情况,代码会按顺序执行,这个就叫同步。

1console.log(1); 2console.log(2); 3console.log(3);

以下代码会输出2、3、1,像这种不按顺序执行的,或者说代码执行中间有时间间隙的,叫异步。

1setTimeout(() => { 2 console.log(1); 3}, 0); 4console.log(2); 5console.log(3);

事件循环

一个浏览器通常有以下几个常驻的线程:

  • 渲染引擎线程:该线程负责页面的渲染
  • JS引擎线程:负责JS的解析和执行
  • 定时触发器线程:处理定时事件,比如setTimeout, setInterval
  • 事件触发线程:处理DOM事件
  • 异步http请求线程:处理http请求

渲染线程和JS引擎线程是不能同时进行的。也就是说在执行代码时,渲染会挂起;渲染DOM时,代码也不会执行。
虽然JS是单线程,但是浏览器是多线程的,在遇到像setTimeout、DOM事件、ajax等这种任务时,会转交给浏览器的其他工作线程(上面提到的几个线程)执行,执行完之后将回调函数放入到任务队列。

在JS运行环境里,除了主线程外,还有任务队列。

1// eventLoop是一个用作队列的数组 2// (先进,先出) 3var eventLoop = [ ]; 4var event; 5// “永远”执行 6while (true) { 7 // 一次tick 8 if (eventLoop.length > 0) { 9 // 拿到队列中的下一个事件 10 event = eventLoop.shift(); 11 // 现在,执行下一个事件 12 event(); 13 } 14}

我们可以用上面的代码来想像一下JS的执行情况。

JS主线程,就像是一个while循环,会一直执行下去。在这期间,每次都会查看任务队列有没有需要执行的任务(回调函数)。在执行完一个任务之后,会继续下一个循环,直到任务队列所有任务都执行完为止。

microtask(微任务)、macrotask(宏任务)

任务队列又分微任务队列和宏任务队列

微任务

  • Promise
  • MutationObserver
  • Object.observe()(已废弃)

宏任务

  • setTimeout
  • setInterval
  • setImmediate
  • IO
  • UI rendering(DOM event)

执行过程

  1. 在JS执行完同步任务之后,会开始执行微任务队列
  2. 在将所有的微任务执行完之后,会开始执行宏任务队列
  3. 在执行完一个宏任务之后,跳出来,重新开始下一个循环(从1开始执行)

也就是说执行微任务队列 会将队列中的所有微任务执行完 而执行宏任务队列 每次只执行一个宏任务 然后重新开始下一个循环
我们可以看看以下代码

1setTimeout(() => { 2 console.log(3) 3 new Promise((resolve, reject) => { 4 console.log(5) 5 resolve() 6 }).then(console.log(6)) 7}, 0) 8 9setTimeout(() => { 10 console.log(4) 11}, 0) 12 13new Promise((resolve, reject) => { 14 console.log(1) 15 resolve() 16}).then(console.log(2))

输出是1 2 3 5 6 4

我们来分析一下代码的执行过程

  1. 前面的两个setTimeout都是宏任务,所以现在宏任务队列有2个任务
  2. Promise里面的代码是同步任务,所以现在会马上执行 输出1
  3. Promise的then是微任务,所以现在微任务队列有1个任务
  4. 在执行完同步任务之后,开始执行微任务,也就是console.log(2), 输出2
  5. 在执行完微任务之后,会执行宏任务,第一个宏任务也就是第一个setTimeout
  6. 第一个setTimeout会先输出3,然后输出5,因为这两个都是同步任务,然后遇到then,加入微任务队列,宏任务执行完重新开始下一个循环。
  7. 因为没有同步代码,所以接着执行微任务,此时微任务队列有1个任务(第6步加入), 宏任务队列还有1个任务(第6步执行完了第一个宏任务)
  8. 执行微任务,输出6
  9. 再执行宏任务,输出4

在这里插入图片描述

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

点赞
收藏

评论区

加载中...

相关推荐

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

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java将前端的json数组字符串转换为列表

记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang

ajax

ajax定义:异步的JavaScript和XML是一种综合技术:运用了XMLHTTPRequest(xhr)和服务器交换数据,通过JavaScript局部渲染页面,从而实现异步的局部更新同步与异步同步代码按顺序执行,会阻塞代码执行(alert)异步不会阻塞代码XMLHTTPRequestxhrjsvarxhrnew

JavaScript同步、异步及事件循环 - HelloWorld