深入浅出 Event Loop 事件轮询,大厂面试必考。

802 阅读3分钟

前言:

深入浅出:本文尽量(不敢保证)以通俗易懂原则解释,避免大家陷入过于理论、晦涩,想了解一个问题,带出好几个问题的尴尬窘境。保证(斗胆保证)大家有所收获,如果没有收获,那么劳驾多看几遍,顺便动动你可爱的小手。学而不思则罔,思而不则殆.废话不多说,开始正题。

JS执行机制:

知其然,知其所以然。众所周知,JS从创立之初就定性为单线程语言,如果想查经据典,请移步阮一峰的个人网站。代码执行自上而下,一行一行执行,如果有一行报错,那么后面代码将不能执行。先执行同步代码,再执行异步代码。异步基于回调来实现,event-loop就是异步实现的原理。

js-async.jpg

异步场景:

  • 1.定时器:setTimemout/setInterval。macroTask,宏任务。
  • 2.事件监听:dom操作,事件驱动,不是异步,但是依靠Event-loop机制实现。 macroTask,宏任务。
  • 3.Ajax:代理XMLHttpRequest发送请求,实现局部更新。macroTask,宏任务。
  • 4.Promises: ES6,语法糖,异步编程提供统一接口,链式写法,解决ajax回调地狱问题。microTask,微任务
  • 5.Asyn/Await:ES7,语法糖。macroTask,微任务。
  • 6.publish-subscribe pattern:发布/订阅者模式。思想前卫、用户体验更好。 目下先了解event-loop实现原理,其它Ajax、Promise、Async/Await、publish-subscribe pattern后续视情况更新。

Event-loop演示图

event-loop.png

示例代码

示例1:

1setTimeout(() => {
2console.log('asynchronous2')
:3: }, 500);
4console.log('synchronization1')
4setTimeout(() => {
5console.log('asynchronous1')
6:   }, 100);
7setTimeout(() => {
8console.log('asynchronous3')
9:   }, 100);
10console.log('synchronization2')

执行结果: 1:打印:synchronization1、synchronization2, 2:打印:asynchronous1、asynchronous3、 3:打印:asynchronous2

示例2:

 1console.log('synchronization1')
 2const btn = document.getElementById('btn')
 3: btn.addEventListener('click', function () {
 4console.log('dom:asynchronous')
 5:  })
 6console.log('synchronization2')

执行结果: 先打印:synchronization1、synchronization2 点击按钮打印:dom:asynchronous

思考

那么问题来了,示例1和示例2中代码到底是如何实现的?跟上图有什么关系。客官勿急,且看下文。 示例1代码为例

  • 1: 第一行同步代码,丢到call stack,执行打印"'synchronization1'”,并清空当前call stack
  • 2: 第二行setTimeout异步代码,丢到web api,记录当前定时器时间及要执行代码。示例2中不同的是,则将点击事件记录在web api中
  • 3: 第六行同步代码,丢到call stack,浏览器执行打印"synchronization2",并清空当前call stac
  • 4: 当前调用栈为空,未有待执行任务。一旦同步代码执行完,此时启动event-loop轮询机(如涉及dom渲染,会先尝试dom渲染,因本示例不涉及dom操作),查找callback quene是否有任务队列。有则捞出,丢到call stack里执行。那么callback quene的队列是怎么来的,涉及到web api中异步代码。根据定时器定义时间长短及代码顺讯,如示例代码依次将100ms/asynchronous1(执行顺讯在前,时间最短),100ms/asynchronous3(执行顺讯在后,时间最短)、3ms/asynchronous2(等待时间最长).web api 则将异步代码丢到callback quene.此时若call stack为空,继续event-loop轮询机制。示例2中代码不同的是当点击事件触发时,则将执行代码丢到callback quene中