- 原文地址:dev.to/lydiahallie…
- 原文做者:Lydia Hallie
對於事件循環,這是每一個 JavaScript 開發人員必然會遇到或者須要理解的內容之一。javascript
可是對於初級開發者來講,理解起來可能有些混亂。java
由於我是一個視覺學習者,因此我經過低分辨率 gif 圖的可視化方式來幫助你理解它。git
可是首先,事件循環是什麼,爲何要關心呢?github
JavaScript 是 單線程的:一次只能運行一個任務。瀏覽器
一般,這沒什麼大不了的,可是如今想象你正在運行一個耗時 30 秒的任務。數據結構
在此任務中,咱們等待 30 秒才能進行其餘任何操做(默認狀況下,JavaScript 在瀏覽器的主線程上運行,所以整個用戶界面都停滯了)😬 。異步
都到 2020 年了,沒有人想停留在一個速度慢,交互反應遲鈍的網站。函數
幸運的是,瀏覽器爲咱們提供了JavaScript 引擎自己不提供的一些功能:Web API。oop
這包括 DOM API,setTimeout
HTTP 請求等,這能夠幫助咱們建立一些異步的,非阻塞的行爲。post
當咱們調用一個函數時,它會被添加到稱爲 調用棧 的數據結構中。
調用棧是 JS 引擎的一部分,這不是特定於瀏覽器的。
它是一個調用棧,這意味着它是 先進先出 的(例如一堆煎餅)。
當一個函數返回一個值時,它會從調用棧中彈出 👋。
該 respond
函數返回一個 setTimeout
函數。
在 setTimeout
由 Web API 提供給咱們:它讓咱們拖延的任務,而不會阻塞主線程。
咱們傳遞給該 setTimeout
函數的回調函數,箭頭函數 () => { return "Hey" }
已添加到 Web API。
同時,該 setTimeout
函數和 response 函數從調用棧中彈出,它們都返回了它們的值!
在 Web API中,計時器的運行時間與咱們傳遞給它的第二個參數 1000ms 同樣長。回調不會當即添加到調用棧中,而是會傳遞給稱爲隊列的東西。
這多是一個使人困惑的部分:這並不意味着在 1000 毫秒後將回調函數添加到調用棧中(從而返回一個值)!它只是在 1000 毫秒後添加到 隊列中。但這是一個隊列,該功能必須等待輪到它!
接下爲是咱們一直在等待的重點內容……
讓事件循環執行其惟一的任務了:將隊列與調用棧鏈接起來!若是調用棧爲 空,那麼若是全部先前調用的函數都返回了它們的值並已從堆棧中彈出,則隊列中的 第一項 將添加到調用棧中,在這種狀況下,沒有其餘函數被調用,這意味着當回調函數成爲隊列中的第一項時,調用棧爲空。
回調被添加到調用棧中,被調用,並返回一個值,並從調用棧中彈出。
閱讀一篇文章頗有趣,可是經過反覆地實際操做,你會對此理解得更深。
若是運行如下 js,請想一下控制檯會輸出什麼內容:
const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");
bar();
foo();
baz();
複製代碼
想出答案了嗎?
讓咱們快速看一下在瀏覽器中運行此代碼時發生的過程:
咱們調用 bar
,bar
返回一個 setTimeout
函數。
咱們傳遞給的回調 setTimeout
被添加到 Web API,該 setTimeout
函數中,並 bar
從調用堆棧中彈出。
計時器運行,同時 foo
調用並記錄 First
,foo
返回(未定義),baz
被調用,並將回調添加到隊列中。
baz
輸出 Third
,事件循環看到 baz
返回後調用棧爲空,而後將回調添加到調用棧。
回調再打印出 Second
。
但願這會使你對事件循環的理解更加清析!最重要的是 瞭解某些錯誤 / 行爲可能從何而來。
當遇到不明白的地方時,也能 高效地 在 Google 上搜索正確的關鍵字 ,並能搜索到正確的答案 💪🏼 。
- 譯者:夜盡天明
- 譯者博客地址:github.com/biaochenxuy…
外國友人技術博客的語言表達的方式和風格、與國人的仍是有很大差異的啊。
姐妹篇:驚豔!可視化的 js:動態圖演示 Promises & Async/Await 的過程!
翻譯了兩篇文章,仍是蠻有趣的 😇,瞬間感受本身的英文水平高達 8 級了啦 (白日夢 🤩)。
推薦閱讀: 經過10 個實例小練習,快速入門熟練 Vue3 核心新特性
支持一下下👇