最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript事件循環(huán)剖析宏任務與微任務

 更新時間:2022年10月18日 09:29:48   作者:十七喜歡前端  
這篇文章主要為大家介紹了JavaScript事件循環(huán)剖析宏任務與微任務示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

相信對于剛學習JavaScript的新手來說,去理解JS中的事件循環(huán)原理以及異步執(zhí)行過程比較困難,但是這是JS必須要會的基礎知識,逃避不能解決問題,筆者曾經也被這個知識點困擾過,現(xiàn)根據以往的經驗編寫此文章,旨在幫助大家徹底搞懂它們以及自我鞏固,話不多說,進入正題。

注意:本篇文章主要是基于瀏覽器環(huán)境,Node環(huán)境沒有研究過暫不討論

引言

我們先來小試牛刀,看看下面這段代碼是怎么執(zhí)行的,例1:

  setTimeout(() => {
    console.log('time')
  });
  new Promise((resolve, reject) => {
    console.log('p1');
    resolve();
  }).then(() => {
    console.log('res')
  });
  console.log(1);
 // 輸出: p1 1 res time

怎么樣?你想的輸出結果和實際的輸出結果是一樣的嗎?如果是一樣的說明你對事件循環(huán)有一定的了解,但是你真的已經清楚的知道了事件循環(huán)的原理嗎?讓我們繼續(xù)往下看。

為什么會有事件循環(huán)?

JS是單線程的

眾所周知:JavaScript 是一門單線程語言,也就是說,同一個時間只能做一件事。這是因為 Javascript 這門腳 本語言誕生的使命所致——JavaScript 是為處理頁面中用戶的交互,以及操作 DOM 而誕生的。比如我們對 某個 DOM 元素進行添加和刪除操作,不能同時進行。 應該先進行添加,之后再刪除。

單線程就意味著,所有任務需要排隊,前一個任務結束,才會執(zhí)行后一個任務。這樣所導致的問題是: 如果 JS 執(zhí)行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞的感覺

為了解決這個問題,利用多核 CPU 的計算能力,HTML5 提出 Web Worker 標準,允許JavaScript 腳本創(chuàng)建多個線程,但是子線程完全受主線程控制。于是,JS 中出現(xiàn)了同步任務和異步任務。

同步任務和異步任務 

  • 同步任務:

同步任務都在主線程上執(zhí)行,形成一個執(zhí)行棧。在主線程上排隊執(zhí)行的任務,只有前一個任務執(zhí)行完畢,才能執(zhí)行后一個任務;

  • 異步任務:

不進入主線程、而進入”任務隊列”的任務,當主線程中的任務運行完了,才會從”任務隊列”取出異步任務放入主線程執(zhí)行。JS 的異步是通過回調函數實現(xiàn)的。異步任務相關回調函數添加到任務隊列中(任務隊列也稱為消息隊列)

注意:異步任務執(zhí)行機制在這里描述的比較籠統(tǒng),主要方便大家理解,具體細節(jié)在后面的“宏任務與微任務”中會詳細介紹

JS的事件循環(huán)就是基于同步任務與異步任務來展開的,讓我們繼續(xù)往下看:

JS事件循環(huán)

事件循環(huán)是JavaScript實現(xiàn)異步的一種方法,也是JavaScript的執(zhí)行機制

如圖:

當一個腳本第一次執(zhí)行的時候,js引擎會解析這段代碼,并將其中的同步代碼按照執(zhí)行順序加入執(zhí)行棧中,然后從頭開始執(zhí)行。

當遇到異步任務時不會一直等待事件的返回結果,而是將事件掛起(即交給其他線程處理,上圖是指Web Worker),繼續(xù)執(zhí)行執(zhí)行棧中的其他任務。

當異步事件返回結果時,js將異步事件callback函數放入隊列中,被放入隊列中的異步事件不會立即回調,等到當前執(zhí)行棧中的任務都執(zhí)行完成,處于閑置狀態(tài)的主線程按照隊列順序將處于首位事件的callback函數放入執(zhí)行棧中,執(zhí)行該函數的同步代碼,如果遇到了異步事件,同樣也會將其回調函數放入事件隊列中…

如此反復,就形成了一個循環(huán),這也是被稱為“事件循環(huán)(EventLoop)”的原因。

js事件循環(huán)的基本原理已經描述清楚,但是異步任務之間也有所不同:

任務隊列實際上分為兩個:宏任務隊列和微任務隊列。上圖只表示了一個是為了便于大家理解事件循環(huán),下面就是事件循環(huán)更細節(jié)的東西了

宏任務與微任務

上面講到,js在執(zhí)行異步任務時,回調函數會被放在js的任務隊列中,實際上,回調函數的類別不同,執(zhí)行的優(yōu)先級也不同。

不同的優(yōu)先級被分為兩類,一類是宏任務(Micro task),一類是微任務(Macro task)。

回調函數是微任務時,會被放在微任務隊列,回調函數是宏任務時,會被放在宏任務隊列。

微任務的優(yōu)先級高于宏任務,當主線程的任務執(zhí)行完成時,會首先去執(zhí)行微任務隊列中首位的回調函數,當微任務隊列中為空時,才回去執(zhí)行宏任務隊列中的回調函數。

常見的宏任務有哪些?

  • 包括整體代碼 script
  • setTimeout()
  • setInterval()
  • setImmediate()(Node獨有)
  • I/O
  • UI 交互事件(瀏覽器獨有)
  • requestAnimationFrame() (瀏覽器獨有)

常見的微任務有哪些?

  • Promise.then(); Promise.cath()
  • async/await
  • process.nextTick() (Node獨有)
  • MutationObserver() (H5新增,監(jiān)聽DOM樹變化)
  • Object.observe() (異步監(jiān)視對象修改,已廢棄)

注意:new Promise()屬于同步任務,但是Promise.then(); Promise.cath()屬于異步任務的微任務

執(zhí)行過程總結(重點)

現(xiàn)在我們對事件循環(huán)有了深入了解了,但是它們的執(zhí)行過程還不是很清晰,我們再把執(zhí)行過程弄清楚了以后就能游刃有余了。

同步任務 —> 微任務 —> 宏任務...

  • 先執(zhí)行所有同步任務,碰到異步任務放到任務隊列中
  • 同步任務執(zhí)行完畢,開始執(zhí)行當前所有的異步任務
  • 先執(zhí)行任務隊列里面所有的微任務,如果執(zhí)行過程中又產生了微任務也會在本次執(zhí)行過程中執(zhí)行(即在下一個宏任務執(zhí)行之前執(zhí)行,可以看看案例1)
  • 然后執(zhí)行一個宏任務(從宏任務隊列頭部pop出一個宏任務進執(zhí)行棧,該任務中的具體代碼也如步驟1執(zhí)行)
  • 然后再執(zhí)行所有的微任務(此時的微任務一般為步驟4中產生出的微任務)
  • 再執(zhí)行一個宏任務,再執(zhí)行所有的微任務·······依次類推到執(zhí)行結束。

3-6的這個循環(huán)稱為事件循環(huán)Event Loop

案例挑戰(zhàn)

學會了嗎?讓我們來做幾個案例鞏固一下吧

案例1:

const promise = new Promise((resolve, reject) => {
    resolve("10")
  }).then(res => {
    console.log("res1:", res)    //res1: hahaha
    return 9
  }).then(res => {
    console.log("res2:", res)    //res2: 9
    return 8
  }).then(res => {
    console.log("res3:", res)    //res3: 8
    let promise2=new Promise((resolve,reject)=>{
        resolve("p2")
      }).then(res=>{
        console.log(res)
        setTimeout(function(){
          console.log("setTimeout2")
        },0)
      })
  })
  console.log('aaa')
  setTimeout(function(){
    console.log("setTimeout1")
  },0)
  const promise1 = new Promise((resolve, reject) => {
    console.log("p1")
    resolve(989)
}).then(res => {
    console.log(res)
    return 990
}).then(res=>{
  console.log(res)
  return 991
}).then(res=>{
  console.log(res)
  return 0
})
/*輸出結果:
aaa
p1
res1: 10
989
res2: 9
990
res3: 8
991
p2
setTimeout1
setTimeout2
*/

案例2:

console.log('1');
// 定義注解 setTimeout_1 用于下文使用方便
setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})
// setTimeout_2
setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})
// 輸出結果:  1 7 6 8 2 4 3 5 9 11 10 12

案例3:

console.log('1');    
setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})
setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})
// 輸出結果:1 7 6 8 2 4 3 5 9 11 10 12

以上就是JavaScript事件循環(huán)剖析宏任務與微任務的詳細內容,更多關于JavaScript 事件循環(huán)宏任務微任務的資料請關注腳本之家其它相關文章!

相關文章

  • 淺談原生JS中的延遲腳本和異步腳本

    淺談原生JS中的延遲腳本和異步腳本

    下面小編就為大家?guī)硪黄獪\談原生JS中的延遲腳本和異步腳本。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • JavaScript中如何判斷一個值是否為Null

    JavaScript中如何判斷一個值是否為Null

    我們在開發(fā)的時候經常會判斷一個null值,那么我們該如何去判斷呢?下面這篇文章主要給大家介紹了關于JavaScript中如何判斷一個值是否為Null的相關資料,需要的朋友可以參考下
    2023-12-12
  • Javascript實現(xiàn)仿QQ隨機數驗證

    Javascript實現(xiàn)仿QQ隨機數驗證

    這篇文章主要為大家詳細介紹了Javascript實現(xiàn)仿QQ隨機數驗證,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Boostrap基礎教程之JavaScript插件篇

    Boostrap基礎教程之JavaScript插件篇

    Boostrap提供了12種JavaScript插件,在本文中給大家介紹了,不知道的朋友可以參考下,本文重點給大家介紹bootstrap基礎之js插件,感興趣的朋友一起學習吧
    2016-09-09
  • three.js載入常用類型3D模型的幾種方法

    three.js載入常用類型3D模型的幾種方法

    通過Three.js的材質和幾何體,我們可以很方便的創(chuàng)建基礎3D模型,下面這篇文章主要給大家介紹了關于three.js載入常用類型3D模型的幾種方法,需要的朋友可以參考下
    2024-04-04
  • Bootstrap每天必學之折疊

    Bootstrap每天必學之折疊

    Bootstrap每天必學之折疊,本文向大家講解了Bootstrap折疊操作,感興趣的小伙伴們可以參考一下
    2016-04-04
  • js 獲取json數組里面數組的長度實例

    js 獲取json數組里面數組的長度實例

    下面小編就為大家?guī)硪黄猨s 獲取json數組里面數組的長度實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • 自定義排序算法在JavaScript中的應用

    自定義排序算法在JavaScript中的應用

    這篇文章主要介紹了自定義排序算法在JavaScript中的應用,通過自定義排序函數,我們能夠精確控制數組元素的排序邏輯,從而滿足各種復雜的應用場景,需要的朋友可以參考下
    2024-12-12
  • 小程序如何定位所在城市及發(fā)起周邊搜索

    小程序如何定位所在城市及發(fā)起周邊搜索

    這篇文章主要介紹了小程序如何定位所在城市及發(fā)起周邊搜索,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • Webpack處理樣式資源的配置詳情

    Webpack處理樣式資源的配置詳情

    Webpack 本身是不能識別樣式資源的,所以我們需要借助 Loader 來幫助 Webpack 解析樣式資源,本文就來介紹一下Webpack處理樣式資源的配置詳情,感興趣的可以了解一下
    2023-12-12

最新評論

缙云县| 黔西| 垫江县| 台前县| 凤山县| 都匀市| 远安县| 宜兰市| 十堰市| 海阳市| 舒兰市| 中超| 保定市| 呼伦贝尔市| 汉寿县| 桦川县| 秦安县| 灵寿县| 壶关县| 滨海县| 额济纳旗| 博乐市| 安阳市| 寿光市| 库车县| 花莲县| 桦川县| 涪陵区| 来安县| 芷江| 辽中县| 石阡县| 开平市| 克什克腾旗| 九龙城区| 五莲县| 琼中| 根河市| 乾安县| 嫩江县| 黄冈市|