从动图轻松入门非同步 JavaScript(第一章)
了解非同步 JavaScript 背后如何运作
浏览器执行环境中的 JavaScript 是单线程的,也就是一次只能执行一件事,通常这不是问题,但假设目前有一个超~~繁琐的事件要处理 30 秒,或是去索取一个未知要多少时间的外部资源,这样其他事情就都被搁置在后,让用户等待。
这是非常大的问题,但解决方法也非常简单:「不要呆呆站在那里等!」。
假设订了外送,会乖乖地等到外送员到家后吃饭,还是先做其他事情呢?想必是后者,那么同样的道理,各种不同的执行环境(runtime) 也提供了 JavaScript 自身并不存在的功能来处理非同步的操作,比如在浏览器中有: Web API,可以轻松创造非同步、避免事件阻塞的网页。
图解专有名词
Call Stack:处理事情,就像在吃松饼
回到 JavaScript 引擎本身,当调用一个函数时,函数会被加入到一个叫做:「Call Stack」的 STACK (堆栈)之中,想象成吃松饼一样,松饼(函数)由最上方加入然后再由上方开始吃掉(处理),代码由上而下执行将函数推入执行堆栈中,当被执行完就会离开。
Web API:浏览器提供的非同步好帮手
而处理非同步事件常遇到的有:fetch
、setTimeout
、addEventListener
,这些都是由 Web API 所提供的方法,使用这些方法传入的回调函数将会交由 Web API 处理,因此 Call Stack 才能迅速被清空,处理下一个事件,不阻塞 JavaScript 的执行。
Callback Queue:等待入场的队伍
Web API 的事项处理完成后并不会马上返回 Call Stack 被执行,而是会被放入 Callback Queue 中等待。这也造成了像是 setTimeout
或 setInterval
并不“准确”的如同描述的时间内被执行,而是单纯在描述时间后会被加入 Callback Queue。
Event Loop:连接整个流程
那么 Callback Queue 中的事项要如何被执行呢? 就轮到 Event Loop 出场的时候了,它只有也仅有一个功能:“连接 Callback Queue 与 Call Stack”。具体来说,当 Call Stack 是空的,第一件 Callback Queue 的事项就会被放入 Call Stack 中,
结语
希望经过简单的动图,可以更直观快速的了解到非同步 JavaScript 背后究竟发生了什么事。
参考资料
- DEV - JavaScript Visualized: Event Loop
- JSConf - What the heck is the event loop anyway?
- JSConf - In The Loop - setTimeout, micro tasks, requestAnimationFrame, requestIdleCallback
- Loupe - 图示化了解非同步 JavaScript 背后运作