欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue手寫實(shí)現(xiàn)異步更新詳解

 更新時(shí)間:2022年08月15日 11:05:22   作者:夏日  
這篇文章主要介紹了Vue手寫實(shí)現(xiàn)異步更新詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下,希望對(duì)你的學(xué)習(xí)有所幫助

前言:

本文將詳細(xì)講解具體的更新過程,并手寫實(shí)現(xiàn)Vue的異步更新邏輯相關(guān)代碼。

收集去重后的watcher進(jìn)行更新

這里先回顧一下依賴收集的相關(guān)知識(shí):

  • 頁(yè)面首次掛載,會(huì)從vm實(shí)例上獲取data中的值,從而調(diào)用屬性的get方法來收集watcher
  • 當(dāng)vm實(shí)例上的屬性更新它的值時(shí),會(huì)執(zhí)行收集到的watcherupdate方法

看下之前完成的代碼:

class Watcher {
  // some code ...
  update () {
    // 直接執(zhí)行更新操作
    this.get()
  }
}

那么watcherupdate到底應(yīng)該如何被執(zhí)行呢?這就是本文的重點(diǎn)。

watcher的更新操作主要分為如下倆步:

  • watcher去重后放到隊(duì)列中
  • 在異步任務(wù)中執(zhí)行存放的所有watcherrun方法

代碼如下:

class Watcher {
  // some code
  update () {
    queueWatcher(this);
  }

  run () {
    this.get();
  }
}

export default Watcher;

let queue = [];
let has = {}; // 使用對(duì)象來保存id,進(jìn)行去重操作
let pending = false; // 如果異步隊(duì)列正在執(zhí)行,將不會(huì)再次執(zhí)行

function flushSchedulerQueue () {
  queue.forEach(watcher => {
    watcher.run();
    if (watcher.options.render) { // 在更新之后執(zhí)行對(duì)應(yīng)的回調(diào): 這里是updated鉤子函數(shù)
      watcher.cb();
    }
  });
  // 執(zhí)行完成后清空隊(duì)列
  queue = [];
  has = {};
  pending = false;
}

function queueWatcher (watcher) {
  const id = watcher.id;
  if (!has[id]) {
    queue.push(watcher);
    has[id] = true;
    if (!pending) {
      pending = true;
      // 異步執(zhí)行watcher的更新方法
      setTimeout(flushSchedulerQueue)
    }
  }
}

此時(shí)已經(jīng)實(shí)現(xiàn)了視圖的異步更新,但是Vue還為用戶提供而了$nextTick方法,讓用戶可以在DOM更新之后做些事情。即$nextTick中的方法會(huì)在flushSchedulerQueue 執(zhí)行后才能執(zhí)行,下面就來看下$nextTick和視圖更新之間的邏輯。

實(shí)現(xiàn)nextTick方法

queueWatcher中其實(shí)并不是直接調(diào)用setTimeout來進(jìn)行視圖更新的,而是會(huì)調(diào)用內(nèi)部的nextTick方法。為用戶提供的$nextTick方法,也會(huì)調(diào)用nextTick方法。

該方法實(shí)現(xiàn)如下:

let callbacks = [];
let pending = false;

function flushCallbacks () {
  callbacks.forEach(cb => cb());
  callbacks = [];
  pending = false;
}

export function nextTick (cb) {
  callbacks.push(cb);
  if (!pending) {
    pending = true;
    timerFunc();
  }
}

nextTick會(huì)接收一個(gè)回調(diào)函數(shù),并將回調(diào)函數(shù)放到callbacks數(shù)組中,之后會(huì)通過timerFunc來異步執(zhí)行callbacks中的每一個(gè)函數(shù):

let timerFunc;
if (Promise) {
  timerFunc = function () {
    return Promise.resolve().then(flushCallbacks);
  };
} else if (MutationObserver) {
  timerFunc = function () {
    const textNode = document.createTextNode('1');
    const observer = new MutationObserver(() => {
      flushCallbacks();
      observer.disconnect();
    });
    const observe = observer.observe(textNode, { characterData: true });
    textNode.textContent = '2';
  };
} else if (setImmediate) {
  timerFunc = function () {
    setImmediate(flushCallbacks);
  };
} else {
  timerFunc = function () {
    setTimeout(flushCallbacks);
  };
}

timerFunc對(duì)異步API進(jìn)行了兼容處理,分別會(huì)先嘗試使用微任務(wù)Promise.thenMutationObserver、setImmediate ,如果這些API瀏覽器都不支持的話,那么會(huì)使用宏任務(wù)setTimeout

queueWatcher里我們將flushSchedulerQueue作為參數(shù)執(zhí)行nextTick

function queueWatcher (watcher) {
  const id = watcher.id;
  if (!has[id]) {
    queue.push(watcher);
    has[id] = true;
    if (!pending) {
      pending = true;
      nextTick(flushSchedulerQueue);
    }
  }
}

Vue原型上,也要增加用戶可以通過實(shí)例來調(diào)用的$nextTick方法,其內(nèi)部調(diào)用nextTick

Vue.prototype.$nextTick = function (cb) {
  nextTick(cb);
};

$nextTick會(huì)將用戶傳入的回調(diào)函數(shù)也放到callbacks中,通過異步API來執(zhí)行。

測(cè)試demo詳解

上面已經(jīng)講解了視圖更新和$nextTick的實(shí)現(xiàn)代碼,接下來寫一個(gè)demo來實(shí)踐一下。

下面是實(shí)際開發(fā)中可能會(huì)用到的一段代碼:

<div id="app">{{name}}</div>
<script>
  const vm = new Vue({
    el: '#app',
    data () {
      return {
        name: 'zs'
      };
    }
  });
  vm.name = 'ls';
  console.log('$el', vm.$el);
  vm.$nextTick(() => {
    console.log('next tick $el', vm.$el);
  });
</script>

其輸出結(jié)果如下:

在了解了$nextTick的具體實(shí)現(xiàn)后,我們?cè)敿?xì)分析下代碼的執(zhí)行流程:

  • 在修改值之后,我們將要更新的watcher隊(duì)列放到了flushSchedulerQueue函數(shù)中來執(zhí)行
  • nextTickflushSchedulerQueue放到了callbacks中,通過異步任務(wù)來執(zhí)行flushCallbacks
  • 由于異步任務(wù)要等到主線程中的代碼執(zhí)行完畢后才會(huì)執(zhí)行,所以此時(shí)先打印vm.$el,視圖尚未更新
  • 接下來會(huì)繼續(xù)執(zhí)行vm.$nextTick,將vm.$nextTick中的回調(diào)函數(shù)也放到了callbacks中,但是其位置在flushSchedulerQueue后邊
  • 主線程中的代碼執(zhí)行完畢,開始執(zhí)行異步任務(wù)flushCallbacks。首先執(zhí)行flushSchedulerQueue更新DOM,然后再執(zhí)行$nextTick中的回調(diào)函數(shù),此時(shí)回調(diào)函數(shù)中可以獲取到最新的DOM

到此這篇關(guān)于Vue手寫實(shí)現(xiàn)異步更新詳解的文章就介紹到這了,更多相關(guān)Vue異步更新內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決Vue2.x父組件與子組件之間的雙向綁定問題

    解決Vue2.x父組件與子組件之間的雙向綁定問題

    這篇文章主要介紹了解決Vue2.x父組件與子組件之間的雙向綁定問題,需要的朋友可以參考下
    2018-03-03
  • vue輸入框中輸完后光標(biāo)自動(dòng)跳到下一個(gè)輸入框中的實(shí)現(xiàn)方法

    vue輸入框中輸完后光標(biāo)自動(dòng)跳到下一個(gè)輸入框中的實(shí)現(xiàn)方法

    最近在工作中遇到了些問題,總結(jié)下分享給同樣遇到這個(gè)問題的朋友,這篇文章主要給大家介紹了關(guān)于vue輸入框中輸完后光標(biāo)自動(dòng)跳到下一個(gè)輸入框中的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2023-03-03
  • Vue解決ajax跨域的問題

    Vue解決ajax跨域的問題

    這篇文章主要介紹了Vue解決ajax跨域的問題,跨域請(qǐng)求:是指協(xié)議名、主機(jī)名、端口號(hào)三者有任何一個(gè)不一樣,而且跨域請(qǐng)求是請(qǐng)求發(fā)出去了,服務(wù)器接收并返回了結(jié)果,只是瀏覽器沒有接收響應(yīng)結(jié)果。感興趣的同學(xué)可以參考閱讀
    2023-04-04
  • vue-cli2.9.3 詳細(xì)教程

    vue-cli2.9.3 詳細(xì)教程

    這篇文章主要介紹了vue-cli2.9.3 詳細(xì)教程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • 使用vue實(shí)現(xiàn)手寫簽名功能

    使用vue實(shí)現(xiàn)手寫簽名功能

    這篇文章主要介紹了使用vue實(shí)現(xiàn)手寫簽名功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • 解決vue elementUI 使用el-select 時(shí) change事件的觸發(fā)問題

    解決vue elementUI 使用el-select 時(shí) change事件的觸發(fā)問題

    這篇文章主要介紹了解決vue elementUI 使用el-select 時(shí) change事件的觸發(fā)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 使用vue點(diǎn)擊li,獲取當(dāng)前點(diǎn)擊li父輩元素的屬性值方法

    使用vue點(diǎn)擊li,獲取當(dāng)前點(diǎn)擊li父輩元素的屬性值方法

    今天小編就為大家分享一篇使用vue點(diǎn)擊li,獲取當(dāng)前點(diǎn)擊li父輩元素的屬性值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • vue如何使用原生高德地圖你知道嗎

    vue如何使用原生高德地圖你知道嗎

    這篇文章主要為大家詳細(xì)介紹了vue如何使用原生高德地圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Vue3之列表動(dòng)畫和狀態(tài)動(dòng)畫示例詳解

    Vue3之列表動(dòng)畫和狀態(tài)動(dòng)畫示例詳解

    這篇文章主要為大家介紹了Vue3之列表動(dòng)畫和狀態(tài)動(dòng)畫示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 對(duì)vue生命周期的深入理解

    對(duì)vue生命周期的深入理解

    這篇文章主要給大家介紹了關(guān)于對(duì)vue生命周期的深入理解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12

最新評(píng)論