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

vue中的任務(wù)隊(duì)列和異步更新策略(任務(wù)隊(duì)列,微任務(wù),宏任務(wù))

 更新時(shí)間:2022年08月10日 10:28:15   作者:June.1  
這篇文章主要介紹了vue中的任務(wù)隊(duì)列和異步更新策略(任務(wù)隊(duì)列,微任務(wù),宏任務(wù)),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

事件循環(huán)

JavaScript 語言的一大特點(diǎn)就是單線程,也就是說,同一個(gè)時(shí)間只能做一件事。

為了協(xié)調(diào)事件、用戶交互、腳本、UI 渲染和網(wǎng)絡(luò)處理等行為,防止主線程的不阻塞,Event Loop 的方案應(yīng)用而生。

Event Loop 包含兩類:

  • 一類是基于 Browsing Context
  • 一種是基于 Worker

二者的運(yùn)行是獨(dú)立的,也就是說,每一個(gè) JavaScript 運(yùn)行的"線程環(huán)境"都有一個(gè)獨(dú)立的 Event Loop,每一個(gè) Web Worker 也有一個(gè)獨(dú)立的 Event Loop。

任務(wù)隊(duì)列

vue 數(shù)據(jù)驅(qū)動視圖是數(shù)據(jù)改變,視圖異步等待所有數(shù)據(jù)變化完成,統(tǒng)一進(jìn)行視圖更新。

既然是異步就有順序和優(yōu)先級, 異步任務(wù)隊(duì)列是那種順序執(zhí)行 ?

tip: 微任務(wù)優(yōu)先級高于宏任務(wù) MDN 介紹

任務(wù)隊(duì)列主要分為兩種:

1、microtasks(微任務(wù)):

  • Promise :ES6的異步處理方案
  • process.nextTick(vue.nextTick) :下輪tick更新機(jī)制,
  • Mutation Observer API: DOM改變 監(jiān)聽 API

2、macrotasks(宏任務(wù)也稱任務(wù)):

  • setTimeout() : 延時(shí)器
  • setInterval(): 計(jì)時(shí)器
  • setImmediate:node.js 回調(diào)函數(shù)延遲執(zhí)行,process.nextTicl() 方法十分類似

process.nextTick()中的回調(diào)函數(shù)執(zhí)行的優(yōu)先級要高于setImmediate().這里的原因在于事件循環(huán)對觀察者的檢查是有先后順序的,process.nextTick()屬于idle觀察者,setImmediate()屬于check觀察者。在每一個(gè)輪循環(huán)檢查中,idle觀察者先于I/O觀察者,I/O觀察者先于check觀察者。

在具體實(shí)現(xiàn)上,process.nextTick()的回調(diào)函數(shù)保存在一個(gè)數(shù)組中,setImmediate()的結(jié)果則是保存在鏈表中。在行為上,process.nextTick()在每輪循環(huán)中會將該數(shù)組中的回調(diào)函數(shù)全部執(zhí)行完,而setImmediate()在每輪循環(huán)中執(zhí)行鏈表中的一個(gè)回調(diào)函數(shù)

  • I/O :系統(tǒng)IO(input/output)
  • UI render :頁面渲染
  • requestAnimationFrame():異步動畫渲染 ,瀏覽器調(diào)用指定的函數(shù)以在下次重繪之前更新動畫

如何理解微任務(wù)和宏任務(wù)?

創(chuàng)造代碼的人也是人,他們的靈感多數(shù)來自于生活。我們這里打個(gè)比方(樸靈老師也這樣比喻),javascript處理異步就像去餐館吃飯,服務(wù)員會先為顧客下單,下完單把顧客點(diǎn)的單子給后廚讓其準(zhǔn)備,然后就去服務(wù)下一位顧客,,而不是一直等待在出餐口。

javascript將顧客下單的行為進(jìn)行了細(xì)分。無外乎兩種酒水類和非酒水類。對應(yīng)著我們javascript中的macroTask和microTask。

但是在不同場景下的步驟是不一樣的,就像西餐和中餐。西餐劃分的非常詳細(xì):頭盤->湯->副菜->主菜->蔬菜類菜肴->甜品->咖啡,中餐就相對簡單許多:涼菜->熱菜->湯。

任務(wù)隊(duì)列,下面看幾個(gè)示例, 輸出內(nèi)容便是執(zhí)行順序:

任務(wù)隊(duì)列,下面看幾個(gè)示例, 輸出內(nèi)容便是執(zhí)行順序:

setTimeout(()=>{
    console.log('1')
    Promise.resolve().then(function() {
        console.log('2')
    })
}, 0)
setTimeout(()=>{
    console.log('3')
    Promise.resolve().then(function() {
        console.log('4')
    })
}, 0)
setTimeout(function() {console.log('6')}, 0)
requestAnimationFrame(function(){
    console.log('5')
})
setTimeout(function() {console.log('7')}, 0)
new Promise(function executor(resolve) {
    console.log('1')
    resolve()
    console.log('2')
}).then(function() {
    console.log('4')
})
console.log('3')
console.log('1');
setTimeout(() => {
    console.log('5');
    process.nextTick(() => console.log('6'));
}, 0);
process.nextTick(() => {
    console.log('3');
    process.nextTick(() => console.log('4'));
});
console.log('2');

這樣就可以理解Vue的異步更新策略運(yùn)行機(jī)制

  created() {
    this.textDemo()
  },
  methods: {
    textDemo() {
      console.log(1)
      setTimeout(() => { // macroTask
        console.log(4)
        setTimeout(() => { // macroTask
          console.log(8)
        }, 0)
        this.$nextTick(() => { // microTask
          console.log(5)
        })
        Promise.resolve().then(function() { // microTask
          console.log(7)
        })
        this.$nextTick(() => { // microTask
          console.log(6)
        })
      }, 0)
      this.$nextTick(() => { // microTask
        console.log(3)
      })
      console.log(2)
    },
}

到此我們已經(jīng)知道代碼是如何運(yùn)行的了, 如果你想要更深入理解, 請繼續(xù)向下閱讀。

深究Vue異步更新策略原理

我們先看一個(gè)示例:

<template>
? <div>
? ? <div ref="test">{{test}}</div>
? ? <button @click="handleClick">tet</button>
? </div>
</template>
<script>
export default {
? ? data () {
? ? ? ? return {
? ? ? ? ? ? test: 'begin'
? ? ? ? };
? ? },
? ? methods () {
? ? ? ? handleClick () {
? ? ? ? ? ? this.test = 'end';
? ? ? ? ? ? console.log(this.$refs.test.innerText);// 結(jié)果輸出 begin
? ? ? ? }
? ? }
}
</script>

通過上面示例可以看出 Vue是異步執(zhí)行DOM更新, 更新會緩沖到隊(duì)列中, 在nextTick 集中刷新隊(duì)列并執(zhí)行實(shí)際 (已去重的) 工作

當(dāng)然新版 this.$nextTick 有一些變化 。從Vue 2.5+開始,抽出來了一個(gè)單獨(dú)的文件next-tick.js來執(zhí)行它。

在這里插入圖片描述

其大概的意思就是:在Vue 2.4之前的版本中,nextTick 幾乎都是基于 microTask 實(shí)現(xiàn)的(具體可以看文章nextTick一節(jié)),但是由于 microTask 的執(zhí)行優(yōu)先級非常高,在某些場景之下它甚至要比事件冒泡還要快,就會導(dǎo)致一些詭異的問題;但是如果全部都改成 macroTask,對一些有重繪和動畫的場景也會有性能的影響。所以最終 nextTick 采取的策略是默認(rèn)走 microTask,對于一些DOM的交互事件,如 v-on綁定的事件回調(diào)處理函數(shù)的處理,會強(qiáng)制走 macroTask。

具體做法就是,在Vue執(zhí)行綁定的DOM事件時(shí),默認(rèn)會給回調(diào)的handler函數(shù)調(diào)用withMacroTask方法做一層包裝,它保證整個(gè)回調(diào)函數(shù)的執(zhí)行過程中,遇到數(shù)據(jù)狀態(tài)的改變,這些改變而導(dǎo)致的視圖更新(DOM更新)的任務(wù)都會被推到macroTask。

源碼:

function add$1 (event, handler, once$$1, capture, passive) {
    handler = withMacroTask(handler);
    if (once$$1) { handler = createOnceHandler(handler, event, capture); }
    target$1.addEventListener(
        event,
        handler,
        supportsPassive
        ? { capture: capture, passive: passive }
        : capture
    );
}
/**
 * Wrap a function so that if any code inside triggers state change,
 * the changes are queued using a Task instead of a MicroTask.
 */
function withMacroTask (fn) {
    return fn._withTask || (fn._withTask = function () {
        useMacroTask = true;
        var res = fn.apply(null, arguments);
        useMacroTask = false;
        return res
    })
}

最后,寫一段DEMO驗(yàn)證一下 :

<template>
?? ?<div>
?? ? ? ?<button @click="handleClick">change</button>
?? ?</div>
</template>
<script>
export default {
? ?created() {
? ? ? this.handleClick() // ?得出結(jié)果 : 2 3 1 4
? },
? ?methods: {
?? ? ? handleClick() {
?? ? ? ? setTimeout(() => { // macroTask
?? ? ? ? ? console.log(4)
?? ? ? ? }, 0)
?? ?
?? ? ? ? this.$nextTick(() => { // microTask
?? ? ? ? ? console.log(2)
?? ? ? ? })
?? ?
?? ? ? ? Promise.resolve().then(function() { // microTask
?? ? ? ? ? console.log(1)
?? ? ? ? })
?? ?
?? ? ? ? this.$nextTick(() => { // microTask
?? ? ? ? ? console.log(3)
?? ? ? ? })
?? ? ? }
? ?}
}
</script>

在Vue 2.5+中,這段代碼的輸出順序是1 - 2 - 3 - 4, 而 Vue 2.4 和 不通過DOM 輸出 2 - 3 - 1 - 4。nextTick執(zhí)行順序的差異正好說明了上面的改變。

tips: 所以這里需要留意遇到DOM操作, 同步執(zhí)行受阻或者節(jié)點(diǎn)內(nèi)容未及時(shí)更新可以使用 this.$nextTick 等待一下在執(zhí)行下面的操作。

<div id="example">
    <audio ref="audio"
           :src="url"></audio>
    <span ref="url"></span>
    <button @click="changeUrl">click me</button>
</div>
<script>
const musicList = [
    'http://sc1.111ttt.cn:8282/2017/1/11m/11/304112003137.m4a?tflag=1519095601&pin=6cd414115fdb9a950d827487b16b5f97#.mp3',
    'http://sc1.111ttt.cn:8282/2017/1/11m/11/304112002493.m4a?tflag=1519095601&pin=6cd414115fdb9a950d827487b16b5f97#.mp3',
    'http://sc1.111ttt.cn:8282/2017/1/11m/11/304112004168.m4a?tflag=1519095601&pin=6cd414115fdb9a950d827487b16b5f97#.mp3'
];
var vm = new Vue({
    el: '#example',
    data: {
        index: 0,
        url: ''
    },
    methods: {
        changeUrl() {
            this.index = (this.index + 1) % musicList.length
            this.url = musicList[this.index];
            this.$refs.audio.play();
        }
    }
});
</script>

毫無懸念,這樣肯定是會報(bào)錯(cuò)的:

Uncaught (in promise) DOMException: The element has no supported sources.

原因就在于audio.play()是同步的,而這個(gè)時(shí)候DOM更新是異步的,src屬性還沒有被更新,結(jié)果播放的時(shí)候src屬性為空,就報(bào)錯(cuò)了。

解決辦法就是在play的操作加上this.$nextTick()。

this.$nextTick(function() {
    this.$refs.audio.play();
});

異步更新有什么好處?

<template>
  <div>
    <div>{{test}}</div>
  </div>
</template>
<script>
export default {
    data () {
        return {
            test: 0
        };
    },
    mounted () {
      for(let i = 0; i < 1000; i++) {
        this.test++;
      }
    }
}
</script>

上面的例子非常直觀,可以這么理解當(dāng)數(shù)據(jù)更新同步操作DOM會出現(xiàn)頻繁渲染視圖造成頁面卡頓,極端的消耗資源。所以異步更新大大提升了性能, 并且數(shù)據(jù)更新很高效體驗(yàn)并沒有降低。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue中自定義指令(directive)的基本使用方法

    vue中自定義指令(directive)的基本使用方法

    Vue中內(nèi)置了很多的指令,但有時(shí)候這些指令并不能滿足我們,或者說我們想為元素附加一些特別的功能,這時(shí)候我們就需要用到vue中一個(gè)很強(qiáng)大的功能了—自定義指令,這篇文章主要給大家介紹了關(guān)于vue中自定義指令(directive)的基本使用方法,需要的朋友可以參考下
    2021-09-09
  • Vue中插槽slot的使用方法與應(yīng)用場景詳析

    Vue中插槽slot的使用方法與應(yīng)用場景詳析

    這篇文章主要給大家介紹了關(guān)于Vue中插槽slot的使用方法與應(yīng)用場景的相關(guān)資料,插槽(Slot)是Vue提出來的一個(gè)概念,正如名字一樣,插槽用于決定將所攜帶的內(nèi)容,插入到指定的某個(gè)位置,從而使模板分塊,具有模塊化的特質(zhì)和更大的重用性,需要的朋友可以參考下
    2021-06-06
  • 利用vue-router實(shí)現(xiàn)二級菜單內(nèi)容轉(zhuǎn)換

    利用vue-router實(shí)現(xiàn)二級菜單內(nèi)容轉(zhuǎn)換

    這篇文章主要介紹了如何利用vue-router實(shí)現(xiàn)二級菜單內(nèi)容轉(zhuǎn)換,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Vue+Echarts實(shí)現(xiàn)繪制多設(shè)備狀態(tài)甘特圖

    Vue+Echarts實(shí)現(xiàn)繪制多設(shè)備狀態(tài)甘特圖

    這篇文章主要為大家詳細(xì)介紹了Vue如何結(jié)合Echarts實(shí)現(xiàn)繪制多設(shè)備狀態(tài)甘特圖,文中的示例代碼講解詳細(xì),有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • 基于Vue實(shí)現(xiàn)拖拽功能

    基于Vue實(shí)現(xiàn)拖拽功能

    這篇文章主要為大家詳細(xì)介紹了Vue實(shí)現(xiàn)拖拽功能,拖動方塊進(jìn)行移動,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • Vue中el-form標(biāo)簽中的自定義el-select下拉框標(biāo)簽功能

    Vue中el-form標(biāo)簽中的自定義el-select下拉框標(biāo)簽功能

    這篇文章主要介紹了Vue中el-form標(biāo)簽中的自定義el-select下拉框標(biāo)簽功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • vue頁面跳轉(zhuǎn)后返回原頁面初始位置方法

    vue頁面跳轉(zhuǎn)后返回原頁面初始位置方法

    下面小編就為大家分享一篇vue頁面跳轉(zhuǎn)后返回原頁面初始位置方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • vue如何將字符串的一部分處理為html文檔并渲染到頁面

    vue如何將字符串的一部分處理為html文檔并渲染到頁面

    這篇文章主要介紹了vue如何將字符串的一部分處理為html文檔并渲染到頁面,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 基于Vue實(shí)現(xiàn)本地消息隊(duì)列MQ的示例詳解

    基于Vue實(shí)現(xiàn)本地消息隊(duì)列MQ的示例詳解

    這篇文章為大家詳細(xì)主要介紹了如何基于Vue實(shí)現(xiàn)本地消息隊(duì)列MQ, 讓消息延遲消費(fèi)或者做緩存,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2024-02-02
  • vue-router的hooks用法詳解

    vue-router的hooks用法詳解

    這篇文章主要介紹了vue-router的hooks用法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06

最新評論

彭阳县| 融水| 鹿泉市| 化州市| 福安市| 永德县| 栾城县| 禄劝| 澄迈县| 太仆寺旗| 广安市| 桃源县| 寻乌县| 肃南| 自治县| 潜江市| 北票市| 隆子县| 嘉义县| 河津市| 洪江市| 鄄城县| 敦化市| 龙井市| 安庆市| 木里| 衡山县| 股票| 临沧市| 都江堰市| 万年县| 虹口区| 龙门县| 苏州市| 红河县| 甘德县| 江源县| 田林县| 正阳县| 南宁市| 隆德县|