[学习笔记] JavaScript - Event Loop (1) : 机制以及相关延伸

本篇内容参考连结
[第十六週] JavaScript 进阶:事件迴圈 Event Loop、Stack、Queue
[笔记] 理解 JavaScript 中的事件循环、堆叠、伫列和併发模式(Learn event loop, stack, queue, and concurrency mode of JavaScript in depth)
Philip Roberts | JSConf EU

Event Loop

Data Structure

在準备了解Event Loop前, 必须先回忆一下一些资料结构

Stack 堆叠 : 原则是 LIFO ("Last in, First Out"), 最后进去的先出来.Queue 伫列 : 原则是 FIFO ("First in, First Out"), 所谓先进先出.

Definition

由于JS Engine是单执行绪(Single thread), 只能执行同步(synchronous)事件, 并一次执行一个任务, 所以需要一个机制来处理非同步(asynchronous)的事件. 而这个机制的集中一个环节就叫做 Event Loop, 用来决定执行任务的顺序.

Call Stack

是用来记录程式目前执行到程式哪个部分, 当进入某一个函式, 便会把这个函式添加(push)到最上方, 直到函式return或结束则会从堆叠抽离(pop).

参考以下範例

function b() {    console.log("b finished");}function a() {    b();    console.log("a finished");}a();

结果会得到

b finished
a finished

当我们去执行的时候, 首先进入stack的是档案中全域环境的程式(这里称作 main()), 如下

main()

接着往下执行, a() 首先被呼叫, 此时会把a()函式堆叠在上面, 并先进入a()函式做执行, 而在a()中, b()又被呼叫,又做了一次堆叠在最上面, 最后call stack 会长的如下

b();
a();
main();

之后跑到 console.log("b finished"); 后, b()执行完毕, 并会从call stack中抽离

a();
main();

以此类推, a()执行完,也会从 call stack中抽离, 最后回到 main()中继续逐行执行直到结束, 然后main()也抽离.

Call Stack - 补充

Stack Overflow : 资源是有限的, 当程式一直堆叠的时候, 例如函式不断呼叫自己呈现无限迴圈如下, 程式进入a()之后就一直不断重複堆叠, 到最后会出现错误 (Maximum call stack size exceeded), 也就是 Stack Overflow.
function a() {    a();}a();
Blocking : 当执行一段程式需要等待很长的时间, 像是网页卡住的感觉, 就叫做阻塞 Blocking. 像是把非同步 ajax request 请求变成同步(Synchronous), 堆叠时就逼须等request拿到资料后, 并从stack中pop出去才可以往下执行.

Callback Queue

当有非同步操作的时候, 像是setTimeout, 浏览器会先丢一个timer到Web API, 等时间到了后, 就会把timer中的 Callback function 丢进Callback Queue. 再藉由Event Loop的机制, 等待Call stack净空后, 就会开始执行.

console.log("First");setTimeout(function(){    console.log("Second");},5000);console.log("Third");

执行结果为

"First"
"Third"
"Second"

先来看call stack的变化, 首先会先放入 main(), 之后执行console.log("First");. 接下来执行到setTimeout这个非同步函式, 浏览器丢一个timer到Web API, 在此同时 setTimeout 就算执行完了, 也从stack抽离, 并不会阻塞整个程式五秒, 所以下一个console.log("Third");就会接着执行.

再来看callback queue, 当在Web API的timer时间到了后, 会把setTimeout的callback丢入callback queue. 等最后一个main()也抽离并净空后,才会依序把callback丢回 call stack, 并开始执行 console.log("Second");.

Event Loop

在一个一个了解架构后, 终于回到Event Loop, 其作用就是监控堆叠(call stack)和伫列(callback queue),当堆叠当中没有执行项目的时候, 便把伫列中的内容拉到堆叠中去执行.

Event Loop 的监测顺序

监控call stack监控callback queue如果call stack为空, 且call queue有pending callback把callback queue里的程式, 依序丢入call stack去执行回到步骤一

强调 : 第一优先永远是call stack, 当call stack没净空时, 即使非同步的事件处理完, 还是需要等到call stack都执行完, callback queue才会被执行到

Event Loop - 补充

setTimeout 0 : 虽然字面上看起来是不用等, 但实际上利用Event Loop的机制, 使它里面的程式全部跑到callback queue, 并等到全部程式跑完才会依queue的顺序执行render engine : 为了创造更流畅的UI,应该避免把笨重和等待时间长久的Code放在Call Stack, 因为优先顺序是Call Stack > Render Engine > Callback queue. 当都放在Call Stack时会造成Render Engine无法更新, 相反的放在callback queue,

Event Loop 延伸主题

macrotask and microtaskJob queue

关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章