<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          徹底了解js事件循環(huán)怎么處理宏任務、微任務

          共 2955字,需瀏覽 6分鐘

           ·

          2022-01-26 14:49

          關注 入坑互聯(lián)網 ,回復“加群

          加入我們一起學習,天天進步


          Event Loop,事件循環(huán),線程進程。這些概念對初識前端的同學來說可能會一頭霧水。而且運行js代碼的運行環(huán)境除了瀏覽器還有node。因此不同環(huán)境處理Event Loop又變得不同,十分容易混淆。

          首先看一段代碼:

          console.log('script start');
          setTimeout(function() { console.log('setTimeout');}, 0);
          Promise.resolve().then(function() { console.log('promise1');}).then(function() { console.log('promise2');});
          console.log('script end');

          打印順序是什么?

          正確答案是

          script start, script end, promise1, promise2, setTimeout

          為什么會出現(xiàn)這樣打印順序呢?

          要理解這些你首先需要對事件循環(huán)機制處理宏任務和微任務的方式有了解。

          每個線程都會有它自己的event loop(事件循環(huán)),所以都能獨立運行。然而所有同源窗口會共享一個event loop以同步通信。event loop會一直運行,來執(zhí)行進入隊列的宏任務。一個event loop有多種的宏任務源(譯者注:event等等),這些宏任務源保證了在本任務源內的順序。但是瀏覽器每次都會選擇一個源中的一個宏任務去執(zhí)行。這保證了瀏覽器給與一些宏任務(如用戶輸入)以更高的優(yōu)先級。

          宏任務(task)

          瀏覽器為了能夠使得JS內部task與DOM任務能夠有序的執(zhí)行,會在一個task執(zhí)行結束后,在下一個 task 執(zhí)行開始前,對頁面進行重新渲染 (task->渲染->task->...)

          鼠標點擊會觸發(fā)一個事件回調,需要執(zhí)行一個宏任務,然后解析HTMl。還有下面這個setTimeout,setTimeout的作用是等待給定的時間后為它的回調產生一個新的宏任務。這就是為什么打印‘setTimeout’在‘script end’之后。因為打印‘script end’是第一個宏任務里面的事情,而‘setTimeout’是另一個獨立的任務里面打印的。

          微任務(Microtasks )

          微任務通常來說就是需要在當前 task 執(zhí)行結束后立即執(zhí)行的任務,比如對一系列動作做出反饋,或者是需要異步的執(zhí)行任務而又不需要分配一個新的 task,這樣便可以減小一點性能的開銷。只要執(zhí)行棧中沒有其他的js代碼正在執(zhí)行且每個宏任務執(zhí)行完,微任務隊列會立即執(zhí)行。如果在微任務執(zhí)行期間微任務隊列加入了新的微任務,會將新的微任務加入隊列尾部,之后也會被執(zhí)行。微任務包括了mutation observe的回調還有接下來的例子promise的回調。

          一旦一個pormise有了結果,或者早已有了結果(有了結果是指這個promise到了fulfilled或rejected狀態(tài)),他就會為它的回調產生一個微任務,這就保證了回調異步的執(zhí)行即使這個promise早已有了結果。所以對一個已經有了結果的promise調用.then(yey, nay)會立即產生一個微任務。這就是為什么‘promise1’,'promise2'會打印在‘script end’之后,因為所有微任務執(zhí)行的時候,當前執(zhí)行棧的代碼必須已經執(zhí)行完畢。‘promise1’,'promise2'會打印在‘setTimeout’之前是因為所有微任務總會在下一個宏任務之前全部執(zhí)行完畢。

          如何分辨宏任務和微任務?

          現(xiàn)在先對前面那個例子進行解釋:

          console.log('script start');
          setTimeout(function() { console.log('setTimeout');}, 0);
          Promise.resolve().then(function() { console.log('promise1');}).then(function() { console.log('promise2');});
          console.log('script end');

          JS中分為兩種任務類型:macrotask和microtask,在ECMAScript中,microtask稱為jobs,macrotask可稱為task

          macrotask(又稱之為宏任務)

          1、每一個task會從頭到尾將這個任務執(zhí)行完畢,不會執(zhí)行其它

          2、瀏覽器為了能夠使得JS內部task與DOM任務能夠有序的執(zhí)行,會在一個task執(zhí)行結束后,在下一個 task 執(zhí)行開始前,對頁面進行重新渲染 (task->渲染->task->...)

          microtask(又稱為微任務),可以理解是在當前task 執(zhí)行結束后立即執(zhí)行的任務

          1、也就是說,在當前task任務后,下一個task之前,在渲染之前

          2、它的響應速度相比setTimeout(setTimeout是task)會更快,因為無需等渲染

          3、在某一個macrotask執(zhí)行完后,就會將在它執(zhí)行期間產生的所有microtask都執(zhí)行完畢(在渲染前)

          我們分步驟來進行這個例子過程解答

          js執(zhí)行引擎開始執(zhí)行上述代碼時,會先進一個main()方法加入執(zhí)行棧。console.log方法是一個webkit內核支持的普通方法,而不是WebAPIs涉及的方法,所以這里當遇到console.log立即出棧被引擎執(zhí)行。

          引擎繼續(xù)往下,將setTimeout添加到執(zhí)行棧。setTimeout()方法屬于事件循環(huán)模型中WebAPIs中的方法,引擎在將setTimeout()方法出棧執(zhí)行時,將延時執(zhí)行的函數(shù)交給了相應模塊,即圖右方的timer模塊來處理。

          然后主線程繼續(xù)向下執(zhí)行,遇到promise立即執(zhí)行,then方法存入微任務隊列,promise執(zhí)行之后,即狀態(tài)變更之后,執(zhí)行微任務中的then方法。

          最后執(zhí)行setTimeOut;

          總結下運行機制:

          執(zhí)行一個宏任務(棧中沒有就從事件隊列中獲取)

          執(zhí)行過程中如果遇到微任務,就將它添加到微任務的任務隊列中

          宏任務執(zhí)行完畢后,立即執(zhí)行當前微任務隊列中的所有微任務(依次執(zhí)行)

          當前宏任務執(zhí)行完畢,開始檢查渲染,然后GUI線程接管渲染

          渲染完畢后,JS線程繼續(xù)接管,開始下一個宏任務(從事件隊列中獲取)


          ?? 看完三件事

          如果你覺得這篇內容對你挺有啟發(fā),我想邀請你幫我三個小忙:

          1. 點贊,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓)。
          2. 關注公眾號「入坑互聯(lián)網」,不定期分享原創(chuàng)知識。
          3. 也看看其它文章

          如何做到優(yōu)秀,好難!

          面試題聯(lián)盟之CSS篇

          年底前端面試及答案-html/css

          年底面試之es6總結

          年底面試之JavaScript總結(用心收集)

          - END -


          結伴同行前端路




          瀏覽 56
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  激情五月天色 | 婷婷色综合淫淫网 | 亚洲男女啪啪 | 亚州多毛少妇 | 国产久久精品内射 |