今天該學習 Event Loop 啦,其實以前我寫過一篇 Event Loop 的文章:javascript
淺析 JS 中的 EventLoop 事件循環(新手向)
這篇呢則是動圖學 JS 系列中的,能夠結合以前的文章食用~java
咱們都知道 JavaScript 是一門 單線程 的語言:同一時間只能運行一個任務。一般狀況下這沒什麼問題,可是若是你有一個任務須要耗費 30 秒的時間,那其餘任務難道都要等它 30 秒麼?(因爲 JS 運行在瀏覽器的主線程,因此這 30 秒的時間裏,整個頁面都會處於卡死狀態)segmentfault
幸運的是,瀏覽器提供了一些 JS 引擎不具有的功能:Web API。它包括 DOM API
,setTimeout
,HTTP 請求
等等。這些功能均可以幫助咱們處理 異步、非阻塞 的操做。瀏覽器
當咱們調用一個函數時,它會被添加到一個叫作 調用棧 (call stack) 的地方,調用棧是 JS 引擎的一部分,而不是瀏覽器特有的。本質上它是一個棧,具備 後進先出 (Last In, First Out. 即 LIFO) 的特色。當一個函數調用完成,它就被從調用棧中彈出。異步
上圖中函數 respond
返回了一個 setTimeout
函數,它也被添加到調用棧中,(setTimeout
正是 Web API 提供的功能之一:它可讓咱們延遲一個任務的執行而且不阻塞主線程。)setTimeout
被調用以後,傳給它的箭頭函數 () => { return 'Hey' }
就被添加進了 Web API (此處簡化了概念,具體能夠看筆者的另外一篇文章)中。同時 setTimeout
和 respond
函數從調用棧中彈出,它們都返回了相應的值。函數
在 Web API 中,一個定時器已經建立,它將會等待 1000 ms,當時間到後,這個箭頭函數並不會當即被調用棧執行,它會被添加到一個隊列中,咱們暫且稱之爲 任務隊列 (原文中叫 Callback Queue)。oop
這裏可能會讓人困惑:那個回調箭頭函數並非在 1000ms 後被直接添加到 調用棧 的,而是被添加進了 任務隊列。隊列嘛,就是你們排隊,先來的先服務,被誰服務?沒錯!就是調用棧。學習
說了這麼多,終於輪到咱們的 Event Loop 登場了!若是上面的調用棧是一個銀行窗口,任務隊列中的回調函數是一個個排隊辦業務的人,那麼 Event Loop 就是叫號系統!Event Loop 的惟一任務就是 鏈接任務隊列和調用棧:spa
它不停檢查 調用棧 中是否有任務須要執行,若是沒有,就檢查 任務隊列,從中彈出一個任務,放入調用棧中,如此往復循環。
上圖中終於輪到那個箭頭函數接受調用了,它被調用完,也被彈出了,輕輕地它走了,只留下一個 Hey!
o(╯□╰)o線程
看圖片是否是挺好理解的~ 那就來看一個例子,能夠把下面的代碼粘貼到瀏覽器的控制檯親自跑一下:
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
函數返回 undefined
。baz
被調用,打印出 Third
。Second
。全文就到這裏啦,但願對你理解 Event Loop 有所幫助~
本文是翻譯的系列文章:
本文首發於公衆號:碼力全開(codingonfire)
歡迎關注獲取最新內容哦~