動圖學 JavaScript 之:事件循環(Event Loop)

前言

今天該學習 Event Loop 啦,其實以前我寫過一篇 Event Loop 的文章:javascript

淺析 JS 中的 EventLoop 事件循環(新手向)

這篇呢則是動圖學 JS 系列中的,能夠結合以前的文章食用~java

咱們都知道 JavaScript 是一門 單線程 的語言:同一時間只能運行一個任務。一般狀況下這沒什麼問題,可是若是你有一個任務須要耗費 30 秒的時間,那其餘任務難道都要等它 30 秒麼?(因爲 JS 運行在瀏覽器的主線程,因此這 30 秒的時間裏,整個頁面都會處於卡死狀態)segmentfault

幸運的是,瀏覽器提供了一些 JS 引擎不具有的功能:Web API。它包括 DOM APIsetTimeoutHTTP 請求 等等。這些功能均可以幫助咱們處理 異步、非阻塞 的操做。瀏覽器

調用棧

當咱們調用一個函數時,它會被添加到一個叫作 調用棧 (call stack) 的地方,調用棧是 JS 引擎的一部分,而不是瀏覽器特有的。本質上它是一個棧,具備 後進先出 (Last In, First Out. 即 LIFO) 的特色。當一個函數調用完成,它就被從調用棧中彈出。異步

1-call-stack.gif

上圖中函數 respond 返回了一個 setTimeout 函數,它也被添加到調用棧中,(setTimeout 正是 Web API 提供的功能之一:它可讓咱們延遲一個任務的執行而且不阻塞主線程。)setTimeout 被調用以後,傳給它的箭頭函數 () => { return 'Hey' } 就被添加進了 Web API (此處簡化了概念,具體能夠看筆者的另外一篇文章)中。同時 setTimeoutrespond 函數從調用棧中彈出,它們都返回了相應的值。函數

2-setTimeout.gif

任務隊列

在 Web API 中,一個定時器已經建立,它將會等待 1000 ms,當時間到後,這個箭頭函數並不會當即被調用棧執行,它會被添加到一個隊列中,咱們暫且稱之爲 任務隊列 (原文中叫 Callback Queue)。oop

3-task-queue.gif

這裏可能會讓人困惑:那個回調箭頭函數並非在 1000ms 後被直接添加到 調用棧 的,而是被添加進了 任務隊列。隊列嘛,就是你們排隊,先來的先服務,被誰服務?沒錯!就是調用棧。學習

事件循環

說了這麼多,終於輪到咱們的 Event Loop 登場了!若是上面的調用棧是一個銀行窗口,任務隊列中的回調函數是一個個排隊辦業務的人,那麼 Event Loop 就是叫號系統!Event Loop 的惟一任務就是 鏈接任務隊列和調用棧spa

它不停檢查 調用棧 中是否有任務須要執行,若是沒有,就檢查 任務隊列,從中彈出一個任務,放入調用棧中,如此往復循環。

4-event-loop.gif

上圖中終於輪到那個箭頭函數接受調用了,它被調用完,也被彈出了,輕輕地它走了,只留下一個 Hey! o(╯□╰)o線程

5-arrow-called.gif

一個例子

看圖片是否是挺好理解的~ 那就來看一個例子,能夠把下面的代碼粘貼到瀏覽器的控制檯親自跑一下:

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

bar();
foo();
baz();

6-example.gif

  1. 咱們調用了函數 barbar 返回了一個 setTimeout 函數。
  2. setTimeout 中的回調函數被添加到 Web APIsetTimeout 函數和 bar 調用完成被從調用棧彈出。
  3. 定時器開始,同時函數 foo 被調用,打印出 Firstfoo 函數返回 undefined
  4. 函數 baz 被調用,打印出 Third
  5. 500ms 定時器結束,回調函數被放入任務隊列,Event Loop 檢查到調用棧是空的,因此將其取出放在調用棧。
  6. 回調函數被執行,打印出 Second

全文就到這裏啦,但願對你理解 Event Loop 有所幫助~

本文是翻譯的系列文章:


本文首發於公衆號:碼力全開(codingonfire)

歡迎關注獲取最新內容哦~

codingonfire.jpg

參考文章

相關文章
相關標籤/搜索