通過可視化來學習JavaScript事件循環(huán)
事件循環(huán),是每個 JavaScript 開發(fā)人員都必須要掌握的知識,開始學的時候,理解起來可能有點混亂。但我是一個視覺學習者,所以我想我會嘗試通過低分辨率 gif 以視覺方式來解釋它,以便幫助你更好的學習和理解事件循環(huán)。
首先,什么是事件循環(huán),為什么要學習它?
JavaScript 是單線程的:一次只能運行一個任務。
通常你會覺得這沒什么大不了的,但是,假設您正在運行一個需要 30 秒的任務,在該任務期間,我們等待 30 秒才能發(fā)生其他任何事情(JavaScript 默認在瀏覽器的主線程上運行,所以整個 UI 都卡住了),但是,我想沒有人想要一個響應很慢有點卡頓的網(wǎng)站。
幸運的是,瀏覽器為我們提供了一些 JavaScript 引擎本身不提供的功能:Web API。這包括 DOM API、setTimeout、HTTP 請求等。這可以幫助我們創(chuàng)建一些異步的、非阻塞的行為。
當我們調(diào)用一個函數(shù)時,它會被添加到調(diào)用堆棧中。調(diào)用堆棧是 JS 引擎的一部分,這不是特定于瀏覽器的,它是一個堆棧,這意味著它是先進后出的(想想一堆煎餅)。當一個函數(shù)返回一個值時,它會從堆棧中彈出。
響應函數(shù)返回一個 setTimeout 函數(shù)。setTimeout 是由 Web API 提供給我們的:它讓我們可以在不阻塞主線程的情況下延遲任務。我們傳遞給 setTimeout 函數(shù)的回調(diào)函數(shù),箭頭函數(shù) () => { return 'Hey' } 被添加到 Web API。與此同時,setTimeout 函數(shù)和 respond 函數(shù)從堆棧中彈出,它們都返回了它們的值!
在 Web API 中,計時器的運行時間與我們傳遞給它的第二個參數(shù)一樣長,即 1000 毫秒。回調(diào)不會立即添加到調(diào)用堆棧中,而是傳遞給稱為隊列的東西。
這可能是一個令人困惑的部分:這并不意味著回調(diào)函數(shù)在 1000 毫秒后被添加到調(diào)用堆棧(因此返回一個值)!它只是在 1000 毫秒后被添加到隊列中。但這是一個隊列,函數(shù)必須等待輪到它!
現(xiàn)在,我們一直在等待的部分......事件循環(huán)完成其唯一任務的時間:將隊列與調(diào)用堆棧連接!如果調(diào)用堆棧是空的,那么,如果所有先前調(diào)用的函數(shù)都返回了它們的值,并且已經(jīng)從堆棧中彈出,則隊列中的第一項被添加到調(diào)用堆棧中。在這種情況下,沒有調(diào)用其他函數(shù),這意味著當回調(diào)函數(shù)成為隊列中的第一項時,調(diào)用堆棧為空。
回調(diào)被添加到調(diào)用堆棧,被調(diào)用,并返回一個值,然后從堆棧中彈出。
閱讀一篇文章很有趣,但你只有通過一遍又一遍地實際操作它才能完全理解學會。如果我們運行以下命令,請嘗試找出記錄到控制臺的內(nèi)容:
讓我們快速看一下在瀏覽器中運行這段代碼時發(fā)生了什么:
- 我們調(diào)用 bar。bar 返回一個 setTimeout 函數(shù)。
- 我們傳遞給 setTimeout 的回調(diào)被添加到 Web API,setTimeout 函數(shù)和 bar 從調(diào)用堆棧中彈出。
- 計時器運行,同時 foo 被調(diào)用并記錄First。foo 返回(未定義),baz 被調(diào)用,回調(diào)被添加到隊列中。
- baz日志Third。事件循環(huán)在 baz 返回后看到調(diào)用堆棧為空,之后回調(diào)被添加到調(diào)用堆棧中。
- 回調(diào)記錄Second。
總結(jié)
以上就是我跟您分享關于事件循環(huán)的內(nèi)容,希望這能讓您對學習事件循環(huán)感到輕松有趣!如果它仍然看起來令人困惑,請不要擔心,最重要的是了解某些錯誤/行為可能來自哪里,以便有效地從谷歌中搜索到正確的解決方案。
如果您覺得今天內(nèi)容對您有用的話,請記得點贊我,關注我,并將它分享給您身邊的朋友,也許能夠幫助到他,最后,感謝閱讀,祝編程愉快!