国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

今天,我明白了JS事件循環機制

maochunguang / 736人閱讀

摘要:而這些隊列由的事件循環來搞定宏任務與微任務,在最新標準中,它們被分別稱為與。我們梳理一下事件循環的執行機制循環首先從宏任務開始,遇到,生成執行上下文,開始進入執行棧,可執行代碼入棧,依次執行代碼,調用完成出棧。

寫在前面

js是一門單線程的編程語言,也就是說js在處理任務的時候,所有任務只能在一個線程上排隊被執行,那如果某一個任務耗時比較長呢?總不能等到它執行結束再去執行下一個。
所以在線程之內,又被分為了兩個隊列:

同步任務隊列

異步任務隊列

舉個例子來說:比如你去銀行辦理業務,都需要領號排隊。銀行柜員一個個辦理業務,這時這個柜員就相當于一個js線程,客戶排的隊就相當于同步任務隊列,每個人對于柜員相當于一個個的任務。
但這個時候,你的電話突然響了,你去接電話接了半小時。這時候人家柜員一看你這情況,直接叫了下一個,而你領的號就作廢了,只能重新零號排隊。這時候你就是被分發到了異步任務隊列。
等你前邊的人都完事了,柜員把你叫過去辦了你的業務,這時候就是同步隊列中的任務執行完了,主線程會處理異步隊列中的任務。

同步任務和異步任務

這里說的異步任務,它的意思是包含了獨立于主執行棧之外的宏任務和微任務

先看一個簡單的例子,對這樣的執行機制有個簡單的認識:

console.log("start")

console.log("end")

上邊的執行結果大家肯定都明白,先輸出start,再輸出end,這一段代碼會進入同步隊列,順序執行。

那么我們加點料:

console.log("start")

setTimeout(function() {
    console.log("setTimeout")
}, 0)

console.log("end")

這樣的情況,函數調用棧執行到setTimeout時,setTimeout會在規定的時間點將回調函數放入異步隊列,等待同步隊列的任務被執行完,立即執行,所以結果是:start、end、setTimeout。

但需要注意的一點是,普遍認為setTimeout定時執行的認知是片面的,因為假設setTimeout規定2秒后執行,但同步隊列中有一個函數,執行花了很長時間,甚至花了1秒。那么這時setTimeout中的回調也會等上至少1秒之后,同步任務都執行完了,再去執行。這時候的setTimeout回調執行的時機就會超過2秒,也就是至少3秒。

宏任務與微任務

宏任務與微任務都是獨立與主執行棧之外的另外兩個隊列,可以在概念上劃分在異步任務隊列里。而這些隊列由js的事件循環(EventLoop)來搞定

macro-task(宏任務)與micro-task(微任務),在最新標準中,它們被分別稱為task與jobs。

由于寫文章時沒有注意到,實際上宏任務與微任務的概念是不準確的,但由于文章中涉及多處宏任務、微任務的解讀,所以本文暫時還是用宏任務、微任務來分別代指task、jobs。但讀者要明白規范中沒有宏任務的概念,只有task與jobs

其中宏任務(task)包括:

script(整體代碼)

setTimeout, setInterval, setImmediate,

I/O

UI rendering

ajax請求不屬于宏任務,js線程遇到ajax請求,會將請求交給對應的http線程處理,一旦請求返回結果,就會將對應的回調放入宏任務隊列,等請求完成執行。

微任務(jobs)包括:

process.nextTick

Promise

Object.observe(已廢棄)

MutationObserver(html5新特性)

這些我們可以理解為它們在執行上下文中都是可執行代碼,會立即執行,只不過會將各自的回調函數放入對應的任務隊列中(宏任務微任務),也就相當于一個調度者。

我們梳理一下事件循環的執行機制:
循環首先從宏任務開始,遇到script,生成執行上下文,開始進入執行棧,可執行代碼入棧,依次執行代碼,調用完成出棧。
執行過程中遇到上邊提到的調度者,會同步執行調度者,由調度者將其負責的任務(回調函數)放到對應的任務隊列中,直到主執行棧清空,然后開始執行微任務的任務隊列。微任務也清空后,再次從宏任務開始,一直循環這一過程。

示例

上邊說了那么多,還是用一些代碼來驗證一下是否是這樣的,先來一個簡單一點的。

console.log("start")

setTimeout(function() {
    console.log("timeout")
}, 0)

new Promise(function(resolve) {
    console.log("promise")
    resolve()
}).then(function() {
    console.log("promise resolved")
})

console.log("end")

根據上邊的結論,分析一下執行過程:

建立執行上下文,進入執行棧開始執行代碼,打印start

往下執行,遇到setTimeout,將回調函數放入宏任務隊列,等待執行

繼續往下,有個new Promise,其回調函數并不會被放入其他任務隊列,因此會同步地執行,打印promise,但是當resolve后,.then會把其內部的回調函數放入微任務隊列

執行到了最底部的代碼,打印出end。這時,主執行棧清空了,開始尋找微任務隊列里有沒有可執行代碼

發現了微任務隊列中有之前放進去的代碼,執行打印出promise resolved,第一次循環結束

再開始第二次循環,從宏任務開始,檢查宏任務隊列是否有可執行代碼,發現有一個,打印timeout

所以,打印順序是:start-->promise-->end-->promise resolved-->timeout

上邊是一個簡單示例,比較好理解。那么接下來看一個稍微復雜一點的(這里直接用漢字直觀地表明了打印的時機,避免看起來費勁):

console.log("第一次循環主執行棧開始")

setTimeout(function() {
    console.log("第二次循環開始,宏任務隊列的第一個宏任務執行中")
    new Promise(function(resolve) {
        console.log("宏任務隊列的第一個宏任務的微任務繼續執行")
        resolve()
    }).then(function() {
        console.log("第二次循環的微任務隊列的微任務執行")
    })
}, 0)

new Promise(function(resolve) {
    console.log("第一次循環主執行棧進行中...")
    resolve()
}).then(function() {
    console.log("第一次循環微任務,第一次循環結束")
    setTimeout(function() {
        console.log("第二次循環的宏任務隊列的第二個宏任務執行")
    })
})

console.log("第一次循環主執行棧完成")

同樣我們分析一下執行過程:

第一次循環

進入執行棧執行代碼,打印第一次循環主執行棧開始

遇到setTimeout,將回調放入宏任務隊列等待執行

promise聲明過程是同步的,打印第一次循環主執行棧進行中...,resolve后遇到.then,將回調放入微任務隊列

打印第一次循環主執行棧完成

檢查微任務隊列是否有可執行代碼,有一個第三步放入的任務,打印第一次循環微任務,第一次循環結束,第一次循環結束,同時遇到setTimeout,將回調放入宏任務隊列

第二次循環

從宏任務入手,檢查宏任務隊列,發現有兩個宏任務,分別是第一次循環第二步和第一次循環第五步被放入的任務,先執行第一個宏任務,打印第二次循環開始,宏任務隊列的第一個宏任務執行中

遇到promise聲明語句,打印宏任務隊列的第一個宏任務繼續執行,這時候又被resolve了,又會將.then中的回調放入微任務隊列,這是這個宏任務隊列中的第一個任務還沒執行完

第一個宏任務中的同步代碼執行完畢,檢查微任務隊列,發現有一段第二步放進去的代碼,執行打印第二次循環的微任務隊列的微任務執行,此時第一個宏任務執行完畢

開始執行第二個宏任務,打印第二次循環的宏任務隊列的第二個宏任務執行,所有任務隊列全部清空,執行完畢

所以打印順序為:

第一次循環主執行棧開始

第一次循環主執行棧進行中...

第一次循環主執行棧完成

第一次循環微任務,第一次循環結束

第二次循環開始,宏任務隊列的第一個宏任務執行中

第二次循環的宏任務隊列的第一個宏任務的微任務繼續執行

第二次循環的微任務隊列的微任務執行

第二次循環的宏任務隊列的第二個宏任務執行

看一下gif,事件循環以肉眼可見的形式呈現出來(兩次循環之間有微小的時間間隔)

總結

js的執行機制是面試中常考的點,也是非常繞的。但相信完全了解事件循環機制,仔細分析的話,面試遇到這樣的題完全不是問題。我在寫這篇文章的時候,發現自己之前理解的很大一部分是錯的。如果大家覺得哪里有錯誤,還請幫忙指點出來。

歡迎關注我的公眾號: 一口一個前端,不定期分享我所理解的前端知識

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106108.html

相關文章

  • 前端校招準備系列--js中的setTimeout到底是什么?

    摘要:瀏覽器是多進程的,而瀏覽器的內核渲染進程是多線程的。如果已經將回調函數放進任務隊列,但是主線程正在執行一個非常耗時的任務,當這個任務執行完畢后,主線程去任務隊列中取任務,這個時候,就會出現連續執行的情況,也就是說相當于失效了。 前言 ??在刷筆試題的時候,經常會碰到setTimeout的問題,只知道這個是設置定時器;但是考察的重點一般是在一個方法中包含了定時器,定時器中的打印和方法中打...

    Godtoy 評論0 收藏0
  • 由setTimeout深入JavaScript執行環境的異步機制

    摘要:圖片轉引自的演講和兩個定時器中回調的執行邏輯便是典型的機制。異步編程關于異步編程我的理解是,在執行環境所提供的異步機制之上,在應用編碼層面上實現整體流程控制的異步風格。 問題背景 在一次開發任務中,需要實現如下一個餅狀圖動畫,基于canvas進行繪圖,但由于對于JS運行環境中異步機制的不了解,所以遇到了一個棘手的問題,始終無法解決,之后在與同事交流之后才恍然大悟。問題的根節在于經典的J...

    codeGoogle 評論0 收藏0
  • 事件循環機制

    摘要:事件觸發線程主要負責將準備好的事件交給引擎線程執行。進程瀏覽器渲染進程瀏覽器內核,主要負責頁面的渲染執行以及事件的循環。第二輪循環結束。 將自己讀到的比較好的文章分享出來,大家互相學習,各位大佬有好的文章也可以留個鏈接互相學習,萬分感謝! 線程與進程 關于線程與進程的關系可以用下面的圖進行說明: showImg(https://segmentfault.com/img/bVbjSZt?...

    Blackjun 評論0 收藏0
  • 事件循環機制

    摘要:事件觸發線程主要負責將準備好的事件交給引擎線程執行。進程瀏覽器渲染進程瀏覽器內核,主要負責頁面的渲染執行以及事件的循環。第二輪循環結束。 將自己讀到的比較好的文章分享出來,大家互相學習,各位大佬有好的文章也可以留個鏈接互相學習,萬分感謝! 線程與進程 關于線程與進程的關系可以用下面的圖進行說明: showImg(https://segmentfault.com/img/bVbjSZt?...

    CloudwiseAPM 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<