JavaScript - Event Loop

JavaScript 是一种单线程的程式语言,简单的说就是一次只能做一件事,而让它做到不阻塞的背后功臣就是 Event Loop 这个机制,接下来让我们一起认识一下它

相关名词介绍

开始介绍 Event Loop 之前要先认识一下三个东西,分别为 StackQueueWeb APIs

Stack(堆叠)

Stack 中文翻译为堆叠,是资料结构的一种,它就像是叠盘子一样,特性为后进先出

Queue(伫列)

Queue 中文翻译为伫列,是资料结构的一种,它就像排队一样,特性为先进先出

Web APIs

Web API 是浏览器提供的方法,它并不是 JavaScript 引擎的一部分,且运作于浏览器端,也就是说他们可以同时运行,常见的 Web API 有 setTimeoutXMLHttpRequest 等等,详细可以看这里

运作机制

Event Loop

知道前面一些名词之后就可以开始来看运作机制了,程式码运行会经过以上的几个流程,总共分为三大区域,分别为 Call StackWeb ApisCallback Queue

Call Stack

这个区块的运作原理使用 Stack 的方式,程式码会先到这个区块执行以下的操作

若同步的动作则直接执行非同步的动作则丢到 Web Apis 做处理若 function 内有另一个 function 则向上堆叠( Stack )执行完成后则移出 Call Stack

Web Apis

到这边的非同步动作会在浏览器背景执行,这里并没有所谓 Stack 或是 Queue 的概念,而是先执行完成会先丢到 Callback Queue 去做等待

Callback Queue

进到这边的函式会等待 Call Stack 清空后才依序将其放回 Call Stack 执行,看名字就知道这边是一个 Queue,也就是 Web Api 执行完成后,先进入这个 Queue 的函式会先被放入 Call Stack

Event Loop

Event Loop 指的就是这一整个循环,当 Call Stack 被清空则会检视 Callback Queue,并将其放入 Call Stack,就这样不断的循环,达成一个不阻塞的机制

Demo1

function A() {  console.log("functionA");  setTimeout(() => console.log("setTimeout1"), 2000);  B();}function B() {  console.log("functionB");  setTimeout(() => console.log("setTimeout2"), 1000);}console.log("start");A();console.log("end");

实际看一下 Demo 来了解运作,以上分别有 AB 两个函式,内部分别还有一个 setTimeout,而 A 函式会呼叫 B 函式,让我们来看看 console.log 出来的顺序

startfunctionAfunctionBendsetTimeout2setTimeout1

大概流程如下:

console.log("start") 丢入 Call Stack 执行,完成后移出将 A 函式丢入 Call Stack 执行将 console.log("functionA") 丢入 Call Stack 执行,完成后移出将 setTimeout1 丢到 Web Apis 执行将 B 函式丢入 Call Stack 执行将 console.log("functionB") 丢入 Call Stack 执行,完成后移出将 setTimeout2 丢到 Web Apis 执行B 函式执行完成,移出 Call StackA 函式执行完成,移出 Call Stack将 console.log("end") 丢入 Call Stack 执行,完成后移出经过一秒后 setTimeout2 执行完成,并将 callback 放入 Callback QueueCall Stack 为空,将 Callback Queue 内的 setTimeout2 callback 放入 Call Stack 执行console.log("setTimeout2") 执行完毕后移出经过两秒后 setTimeout1 执行完成,并将 callback 放入 Callback QueueCall Stack 为空,将 Callback Queue 内的 setTimeout1 callback 放入 Call Stack 执行console.log("setTimeout1") 执行完毕后移出

Demo2

console.log("start");setTimeout(() => console.log("setTimeout1"), 1000);setTimeout(() => console.log("setTimeout2"), 1000);const endTime = new Date() + 3000;while (Date() >= endTime) {}console.log("end");

这个範例执行完两个 setTimeout 后会跑一个 while 迴圈,让程式暂停 3 秒,结果如下:

startendsetTimeout1setTimeout2

大概流程如下:

console.log("start") 丢入 Call Stack 执行,完成后移出将 setTimeout1 丢到 Web Apis 执行将 setTimeout2 丢到 Web Apis 执行执行 while 迴圈经过一秒后 setTimeout1 执行完成,并将 callback 放入 Callback Queue经过一秒后 setTimeout2 执行完成,并将 callback 放入 Callback Queuewhile 迴圈达成条件并跳出(3秒)将 console.log("end") 丢入 Call Stack 执行,完成后移出Call Stack 为空,将 Callback Queue 内的 setTimeout1 callback 放入 Call Stack 执行,完成后移出Call Stack 为空,将 Callback Queue 内的 setTimeout2 callback 放入 Call Stack 执行,完成后移出

这里的重点在于 setTimeout 会在跑完迴圈后直接执行,因为迴圈执行的一秒后 Web Apis 内的 setTimeout 就已经执行完毕并丢到 Callback Queue 等待,所以当迴圈完成、Call Stack 清空后,会触发 Event Loop 机制,并将 Callback Queue 等待的函式放入 Call Stack 执行

结语

Event Loop 真的是相当有趣的机制,如果要更了解 JavaScript 一定要先了解它,之后在写一些非同步的运作也会更加容易,那就祝大家学习愉快拉!


关于作者: 网站小编

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

热门文章