[譯] 圖解Event Loop

原文《JavaScript Visualized: Event Loop》 - By Lydia Hallie
本文主要經過生動形象的動圖講解事件循環的一些基本概念,主要面向初學者,譯者已取得原做者的贊成。本文一些部分採用意譯,以幫助你們更好地理解。

本文首發於我的博客 Logan's Blog,其餘JS相關內容也可前往小弟博客共同窗習探討。javascript

事件循環(Event Loop),是每一個JS開發者都會接觸到的概念,可是剛接觸時可能會存在各類疑惑。我是一個視覺型學習者,因此打算經過gif動圖的可視化形式幫助你們理解它。java

首先咱們來看看,什麼是事件循環,咱們爲何要了解它呢?git

衆所周知,JavaScript是 單線程(single-threaded) 的,也就是同一時間只能運行一個任務。通常狀況下這並無什麼問題,可是假如咱們要運行一個耗時30秒的任務,咱們就得等待30秒後才能執行下一個任務(這30秒期間,JavaScript佔用了主線程,咱們什麼都不能作,包括頁面也是卡死狀態)。這都9012年了,不帶這麼坑爹的吧?github

好在瀏覽器向咱們提供了JS引擎不具有的特性:Web APIWeb API包括DOM API定時器HTTP請求等特性,能夠幫助咱們實現異步、非阻塞的行爲。瀏覽器

當咱們調用一個函數時,函數會被放入一個叫作調用棧(call stack,也叫執行上下文棧)的地方。調用棧是JS引擎的一部分,並不是瀏覽器特有的。調用棧是一個棧數據結構,具備後進先出的特色(Last in, first out. LIFO)。當函數執行完畢返回時,會被彈出調用棧。數據結構

圖例中的respond函數返回一個setTimeout函數調用,setTimeout函數是Web API提供給咱們的功能:它容許咱們延遲執行一個任務而不用阻塞主線程。setTimeout被調用時,咱們傳入的回調函數,即箭頭函數() => { return 'hey' }會被傳遞給Web API處理,而後setTimeoutrespond依次執行完畢出棧。異步

Web API中會執行定時器,定時間隔就是咱們傳入setTimeout的第二個參數,也就是1000ms。計時結束後回調函數並不會當即進入調用棧執行,而是會被加入一個叫作 任務隊列(Task Queue) 的地方。函數

看到這裏,有些人可能會疑惑:1000ms以後,回調居然沒有放入調用棧執行,而是被放入了任務隊列,那何時被執行呢?不要急,既然是一個隊列,那就要排排坐,吃果果。oop

接下來就是咱們期待已久,萬衆矚目的 事件循環(Event Loop) 閃亮登場的時刻了。Event Loop的工做就是鏈接任務隊列和調用棧,當調用棧中的任務均執行完畢出棧,調用棧爲空時,Event Loop會檢查任務隊列中是否存在等待執行的任務,若是存在,則取出隊列中第一個任務,放入調用棧。學習

咱們的回調函數被放入調用棧中,執行完畢,返回其返回值,而後被彈出調用棧。

閱讀一時爽,但只有經過反覆練習,將其變爲本身的東西后纔會一直爽。咱們來作個小練習檢測下學習成果,看看下面代碼輸出什麼:

const foo = () => console.log('First');
const bar = () => setTimeout(() => console.log('Second'), 500);
const baz = () => console.log('Third');

bar();
foo();
baz();
複製代碼

相信你們均可以輕鬆給出正確答案。咱們一塊兒來看下這段代碼運行時發生了什麼:

  1. bar被調用,返回setTimeout的調用;
  2. 傳入setTimeout的回調被傳遞給Web API處理,setTimeout執行完畢出棧,bar執行完畢出棧;
  3. 定時器開始運行,同時主線程中foo被調用,打印Firstfoo執行完畢出棧;
  4. baz被調用,打印Thirdbaz執行完畢出棧;
  5. 500ms後定時器運行完畢,回調函數被放入任務隊列;
  6. Event Loop檢測到調用棧爲空,從任務隊列中取出回調函數放入調用棧;
  7. 回調函數被執行,打印Second,執行完畢出棧。

但願本文能幫助你對事件循環有一個初步的瞭解,若是還有疑惑,可留言交流探討。

相關文章
相關標籤/搜索