亚洲精品中文免费|亚洲日韩中文字幕制服|久久精品亚洲免费|一本之道久久免费

      
      

            <dl id="hur0q"><div id="hur0q"></div></dl>

                JS 中的 Event Loop 是什么?

                大家好,我是前端西瓜哥,今天來認(rèn)識一下什么是 Event Loop。

                Event Loop,簡單翻譯就是 事件循環(huán),是 JS 語言下實現(xiàn)運(yùn)行時的一個機(jī)制。

                JS 的異步并不像其他語言(比如 Java)的異步那樣可以實現(xiàn)真正的并發(fā)執(zhí)行,本身其實是個單線程。

                JS 是維護(hù)了一個 任務(wù)隊列,每當(dāng)要執(zhí)行一些異步任務(wù),比如定時器或者是點擊按鈕觸發(fā)的事件響應(yīng)函數(shù)。它們不會立即執(zhí)行,而是放到這個隊列里,等待已經(jīng)在排隊的其他任務(wù)先執(zhí)行完,才輪到它們。

                隊列是一個操作受限的有序列表,表現(xiàn)為為先進(jìn)入的元素必須先出去,即 “先進(jìn)先出”,很像排隊的感覺。

                不過也有一些特殊的隊列,比如優(yōu)先級隊列,它是優(yōu)先級高的元素先出隊。

                之所以叫 Event Loop,因為它的邏輯可以描述為下面代碼

                while?(queue.waitForMessage())?{??queue.processNextMessage();}

                當(dāng)一個任務(wù)被完成后,隊列會變成等待下一個任務(wù)狀態(tài),然后處理下一個任務(wù),如此循環(huán)往復(fù)。

                因為 JS 的代碼執(zhí)行本身是一個單線程,為了不讓執(zhí)行阻塞,JS 會把網(wǎng)絡(luò)請求操作、渲染瀏覽器頁面等操作,交給其他的線程,等待其他線程處理好把結(jié)果返回給 JS。

                所以 JS 不合適 CPU 密集型,更適合 IO 密集型的場景。因為它只有一個線程,如果計算耗時太長,就會阻塞其他要執(zhí)行的任務(wù),導(dǎo)致卡頓,甚至崩潰。

                setTimeout 定時器并不準(zhǔn)

                setTimeout 在特定時間后要執(zhí)行的函數(shù),并不會立即執(zhí)行,而是會先放到任務(wù)隊列中,先等待前面的任務(wù)同步執(zhí)行完成了,才能執(zhí)行我們這個。

                下面看一個例子,因為第一個 setTimout 有一個非常耗時的同步任務(wù),導(dǎo)致下一個 setTimeout 的執(zhí)行阻塞,比前面一個 setTimeout 執(zhí)行要慢半秒。

                const?start?=?new?Date().getTime();setTimeout(()?=>?{??console.log(‘1:’,?new?Date().getTime()?–?start);??let?num?=?0;??for?(let?i?=?0;?i??{??console.log(‘2:’,?new?Date().getTime()?–?start);},?1000);/**?*?輸出結(jié)果:?*?1:?1001?*?2:?1505?*/

                定時器的時間,指的是能執(zhí)行的最早時間,但不能保證一定能在這個時間點立即執(zhí)行。

                宏任務(wù)和微任務(wù)

                任務(wù)隊列并不是嚴(yán)格意義上的先進(jìn)先出的正常隊列,是可以調(diào)整執(zhí)行順序的。

                我們將要執(zhí)行的任務(wù)分為宏任務(wù)和微任務(wù),其中宏任務(wù)是正常的先進(jìn)先出,而微任務(wù)則是可以插隊,優(yōu)先于宏任務(wù)先執(zhí)行。宏任務(wù)必須在所有微任務(wù)執(zhí)行后才能執(zhí)行。

                當(dāng)我們給任務(wù)隊列添加一個微任務(wù)時,它會跑到任務(wù)隊列宏任務(wù)前。多個微任務(wù)入隊時,會保持它們的相對順序。

                宏任務(wù)有:

                • script,即 HTML 嵌入的腳本;
                • setTimeout / setInterval 定時器;
                • setImmediate,這是 nodejs 特有的 API;
                • requestAnimationFrame,會在頁面重繪前執(zhí)行;
                • I/O 操作,比如網(wǎng)絡(luò)請求完成的回調(diào)函數(shù)執(zhí)行任務(wù)、還比如點擊按鈕要執(zhí)行的回調(diào)等。這些操作其實是其他的線程完成后觸發(fā)的,暫且歸納為 I/O 操作。

                微任務(wù)有:

                • Promise 從 pending 狀態(tài)轉(zhuǎn)換為其他狀態(tài)時,觸發(fā) then/catch/finaly 中的函數(shù),比如 Promise.resolve().then(fn)。這是最常見的微任務(wù)。
                • MutationObserver,用于監(jiān)聽 DOM 的變化
                • process.nextTick,nodejs 特有的 API

                任務(wù)隊列,理論上一個就夠了,但也可以是多個隊列的組合,沒有強(qiáng)行要求。

                多個任務(wù)隊列的實現(xiàn)可以更好地實現(xiàn)優(yōu)先級的控制,比如對于定時器任務(wù),理論上應(yīng)該是在多個宏任務(wù)中最先執(zhí)行比較好。瀏覽器沒考慮這種情況,但 nodejs 給宏任務(wù)中也設(shè)置優(yōu)先級,會讓定時器任務(wù)最先執(zhí)行。

                Event Loop 還是挺復(fù)雜的,標(biāo)準(zhǔn)文檔也比較長,我也沒怎么看,感興趣可以看看。

                https://html.spec.whatwg.org/multipage/webappapis.html#event-loops

                一道經(jīng)典異步題

                async?function?async1()?{??console.log(“async1?start”);??await?async2();??console.log(“async1?end”);}async?function?async2()?{??console.log(“async2”);}console.log(“script?start”);setTimeout(function()?{??console.log(“setTimeout”);},?0);async1();new?Promise(function(resolve)?{??console.log(“promise1”);??resolve();}).then(function()?{??console.log(“promise2”);});console.log(‘script?end’)

                解題思路為:

                • 找到同步代碼。同步代碼有:普通同步代碼、new Promise(fn) 執(zhí)行傳入的回調(diào)函數(shù)、async 執(zhí)行時遇到 await 的前面部分(包括 await 的右側(cè)函數(shù)執(zhí)行也是同步的,這里是易錯點)。
                • 看看任務(wù)隊列中有哪些微任務(wù)和宏任務(wù),記住微任務(wù)全執(zhí)行完了才會執(zhí)行宏任務(wù)。
                • 執(zhí)行任務(wù),任務(wù)里面的異步任務(wù)又按順序進(jìn)入到任務(wù)隊列。

                結(jié)果是:

                // 同步代碼script startasync1 startasync2promise1script end// 微任務(wù)async1 endpromise2// 宏任務(wù)setTimeout

                結(jié)尾

                JS 運(yùn)行機(jī)制是單線程,當(dāng)有多個異步任務(wù)要同時執(zhí)行,并不能并發(fā)執(zhí)行,必須讓優(yōu)先級高的任務(wù)執(zhí)行完才能執(zhí)行后面的。如果正在執(zhí)行的任務(wù)比較耗時,會導(dǎo)致后面的任務(wù)被阻塞。

                Event Loop 的機(jī)制中,最基本的一條就是:微任務(wù)比宏任務(wù)先執(zhí)行。

                我是前端西瓜哥,歡迎關(guān)注我,一起學(xué)習(xí)前端技術(shù)。

                鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
                用戶投稿
                上一篇 2022年6月21日 15:15
                下一篇 2022年6月21日 15:15

                相關(guān)推薦

                聯(lián)系我們

                聯(lián)系郵箱:admin#wlmqw.com
                工作時間:周一至周五,10:30-18:30,節(jié)假日休息