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

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

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

前言:

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

收集去重后的watcher進行更新

這里先回顧一下依賴收集的相關知識:

  • 頁面首次掛載,會從vm實例上獲取data中的值,從而調用屬性的get方法來收集watcher
  • vm實例上的屬性更新它的值時,會執(zhí)行收集到的watcherupdate方法

看下之前完成的代碼:

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

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

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

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

代碼如下:

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

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

export default Watcher;

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

function flushSchedulerQueue () {
  queue.forEach(watcher => {
    watcher.run();
    if (watcher.options.render) { // 在更新之后執(zhí)行對應的回調: 這里是updated鉤子函數(shù)
      watcher.cb();
    }
  });
  // 執(zhí)行完成后清空隊列
  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)
    }
  }
}

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

實現(xiàn)nextTick方法

queueWatcher中其實并不是直接調用setTimeout來進行視圖更新的,而是會調用內部的nextTick方法。為用戶提供的$nextTick方法,也會調用nextTick方法。

該方法實現(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會接收一個回調函數(shù),并將回調函數(shù)放到callbacks數(shù)組中,之后會通過timerFunc來異步執(zhí)行callbacks中的每一個函數(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對異步API進行了兼容處理,分別會先嘗試使用微任務Promise.then、MutationObserver、setImmediate ,如果這些API瀏覽器都不支持的話,那么會使用宏任務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原型上,也要增加用戶可以通過實例來調用的$nextTick方法,其內部調用nextTick

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

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

測試demo詳解

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

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

<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>

其輸出結果如下:

在了解了$nextTick的具體實現(xiàn)后,我們詳細分析下代碼的執(zhí)行流程:

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

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

相關文章

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

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

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

    vue輸入框中輸完后光標自動跳到下一個輸入框中的實現(xiàn)方法

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

    Vue解決ajax跨域的問題

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

    vue-cli2.9.3 詳細教程

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

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

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

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

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

    使用vue點擊li,獲取當前點擊li父輩元素的屬性值方法

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

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

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

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

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

    對vue生命周期的深入理解

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

最新評論