XiZev / blog

record my learning of font-end
0 stars 0 forks source link

JS中的事件轮询机制EventLoop #5

Open XiZev opened 3 years ago

XiZev commented 3 years ago

前言

鉴于JavaScript是一门单线程的语言,浏览器在同一时间内只能做一件事。正是由于这个特性,如果在执行代码的过程中需要等待某些数据或者行为准备完成后才能继续进行,而这个等待过程又会持续好几秒,这就会造成代码的阻塞。这就是同步带来的问题。

异步和等待队列

为了解决这个问题,就有了异步的概念。当同步代码顺序执行时,遇到了异步操作,此时会把该异步行为从CPU中释放出去,然后继续执行同步代码。而当异步完成后会把完成后的回调函数放入到等待队列,等主程序的同步代码执行完毕后,就去监测等待队列是否为空,不为空则按照“先进先出”的规则按序取出来执行。

宏任务和微任务

当执行栈为空时,从任务队列中取出异步回调放入CPU中执行。而又根据异步操作的类型,分为了宏任务队列和微任务队列,就两者执行的优先级而言,同一层级下微任务要高于宏任务。理解需要,把代码开始执行同步任务看成一个根宏任务,每当一个宏任务执行完后,都会优先检查微任务队列是否为空,为空则执行下一个宏任务,否则按序把微任务队列中的每个任务都执行完毕后再去执行下一个宏任务。也即:

执行下一个宏任务之前,微任务队列必须为空。 宏任务结束后开始检查渲染,然后GUI线程接管渲染。渲染完毕后,JS线程继续接管,开始下一个宏任务

QQ截图20210331233912

常见微任务任务包括:

Promise的then的回调函数、async函数await下面的代码等一些ES6语法规定

常见宏任务包括:

定时器(setInterval和setTimeout)等一些由浏览器规定的

事件轮询

当执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码…,如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件轮询(Event Loop)”的原因。 QQ截图20210401001243