中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue2.6中的nextTick方法是什么

發布時間:2020-12-03 10:11:12 來源:億速云 閱讀:198 作者:小新 欄目:web開發

小編給大家分享一下Vue2.6中的nextTick方法是什么,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

淺析 Vue 2.6 中的 nextTick 方法。

事件循環

JS 的 事件循環任務隊列 其實是理解 nextTick 概念的關鍵。
這個網上其實有很多優質的文章做了詳細介紹,我就簡單過過了。

以下內容適用于瀏覽器端 JS,NodeJS 的事件循環機制并不相同。

規范中規定 task 分為兩大類: task(macrotask)microtask

通常認為是 task 的任務源:

setTimeout / setInterval
setImmediate
MessageChannel
I/O
UI rendering

通常認為是 microtask 的任務源:

Promise
process.nextTick
MutationObserver
Object.observe(已廢棄)

簡單概況:(這里是官方規范)

  1. 首先開始執行 script 腳本,直到執行上下文棧為空時,開始清空 microtask 隊列里的任務,隊列嘛,先入先出,出一個執行一個,清空完畢,走事件循環。

  2. 事件循環:不斷地去取 task 隊列的中的一個任務推入棧中執行,并在當次循環里依次清空 microtask 隊列里的任務,清空之后,可能會觸發頁面更新渲染(由瀏覽器決定)。

  3. 之后重復 事件循環 步驟。

nextTick

Vue 中數據的變化到 DOM 的更新渲染是一個異步過程。
此方法便用于在 DOM 更新循環結束之后執行延遲回調。
使用方法很簡單:

// 修改數據
vm.msg = 'Hello';
// DOM 還沒有更新
Vue.nextTick(function() {
  // DOM 更新了
});

// 作為一個 Promise 使用
Vue.nextTick().then(function() {
  // DOM 更新了
});

源碼 去除注釋,其實也只有不到一百來行,整體還是很容易理解的。

這里劃成 3 個部分介紹。

模塊變量

介紹 引入的模塊 和 定義的變量。

// noop 空函數,可用作函數占位符
import { noop } from 'shared/util';

// Vue 內部的錯誤處理函數
import { handleError } from './error';

// 判斷是IE/IOS/內置函數
import { isIE, isIOS, isNative } from './env';

// 使用 MicroTask 的標識符
export let isUsingMicroTask = false;

// 以數組形式存儲執行的函數
const callbacks = [];

// nextTick 執行狀態
let pending = false;

// 遍歷函數數組執行每一項函數
function flushCallbacks() {
  pending = false;
  const copies = callbacks.slice(0);
  callbacks.length = 0;
  for (let i = 0; i < copies.length; i++) {
    copies[i]();
  }
}

異步延遲函數

接下來是核心的 異步延遲函數。這里不同的 Vue 版本采用的策略其實并不相同。

2.6 版本優先使用 microtask 作為異步延遲包裝器。

2.5 版本則是 macrotask 結合 microtask。然而,在重繪之前狀態改變時會有小問題(如 #6813)。此外,在事件處理程序中使用 macrotask 會導致一些無法規避的奇怪行為(如#7109,#7153,#7546,#7834,#8109)。

所以 2.6 版本現在又改用 microtask 了,為什么是又呢。。因為 2.4 版本及之前也是用的 microtask。。。

microtask 在某些情況下也是會有問題的,因為 microtask 優先級比較高,事件會在順序事件(如#4521,#6690 有變通方法)之間甚至在同一事件的冒泡過程中觸發(#6566)。

// 核心的異步延遲函數,用于異步延遲調用 flushCallbacks 函數
let timerFunc;

// timerFunc 優先使用原生 Promise
// 原本 MutationObserver 支持更廣,但在 iOS >= 9.3.3 的 UIWebView 中,觸摸事件處理程序中觸發會產生嚴重錯誤
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve();
  timerFunc = () => {
    p.then(flushCallbacks);

    // IOS 的 UIWebView,Promise.then 回調被推入 microtask 隊列但是隊列可能不會如期執行。
    // 因此,添加一個空計時器“強制”執行 microtask 隊列。
    if (isIOS) setTimeout(noop);
  };
  isUsingMicroTask = true;

  // 當原生 Promise 不可用時,timerFunc 使用原生 MutationObserver
  // 如 PhantomJS,iOS7,Android 4.4
  // issue #6466 MutationObserver 在 IE11 并不可靠,所以這里排除了 IE
} else if (
  !isIE &&
  typeof MutationObserver !== 'undefined' &&
  (isNative(MutationObserver) ||
    // PhantomJS 和 iOS 7.x
    MutationObserver.toString() === '[object MutationObserverConstructor]')
) {
  let counter = 1;
  const observer = new MutationObserver(flushCallbacks);
  const textNode = document.createTextNode(String(counter));
  observer.observe(textNode, {
    characterData: true,
  });
  timerFunc = () => {
    counter = (counter + 1) % 2;
    textNode.data = String(counter);
  };
  isUsingMicroTask = true;

  // 如果原生 setImmediate 可用,timerFunc 使用原生 setImmediate
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  timerFunc = () => {
    setImmediate(flushCallbacks);
  };
} else {
  // 最后的倔強,timerFunc 使用 setTimeout
  timerFunc = () => {
    setTimeout(flushCallbacks, 0);
  };
}

一句話總結優先級:microtask 優先
Promise > MutationObserver > setImmediate > setTimeout

nextTick 函數

nextTick 函數。接受兩個參數:

  1. cb 回調函數:是要延遲執行的函數;

  2. ctx:指定 cb 回調函數 的 this 指向

Vue 實例方法 $nextTick 做了進一步封裝,把 ctx 設置為當前 Vue 實例

export function nextTick(cb?: Function, ctx?: Object) {
  let _resolve;

  // cb 回調函數會經統一處理壓入 callbacks 數組
  callbacks.push(() => {
    if (cb) {
      // 給 cb 回調函數執行加上了 try-catch 錯誤處理
      try {
        cb.call(ctx);
      } catch (e) {
        handleError(e, ctx, 'nextTick');
      }
    } else if (_resolve) {
      _resolve(ctx);
    }
  });

  // 執行異步延遲函數 timerFunc
  if (!pending) {
    pending = true;
    timerFunc();
  }

  // 當 nextTick 沒有傳入函數參數的時候,返回一個 Promise 化的調用
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
      _resolve = resolve;
    });
  }
}

小結

整體看過來,感覺還是比較好理解的吧~ 2.6 版本相比之前簡化了一點。

小結一下,每次調用 Vue.nextTick(cb) 會做些什么:
cb 函數經處理壓入 callbacks 數組,執行 timerFunc 函數,延遲調用 flushCallbacks 函數,遍歷執行 callbacks 數組中的所有函數。

延遲調用優先級如下:
Promise > MutationObserver > setImmediate > setTimeout

版本差異

其實 Vue 2.4、2.5、2.6 版本的 nextTick 策略都略不一樣。

整體 2.62.4 的比較相似。(仔細瞅了瞅,基本就是一樣的,2.6 timerFunc 多了個 setImmediate 判斷)

2.5 版本其實也差不多。。。源碼寫法有些不一樣,整體優先級是:Promise > setImmediate > MessageChannel > setTimeout,如果更新是在 v-on 事件處理程序中觸發的,nextTick 會優先使用 macrotask。

以上是“Vue2.6中的nextTick方法是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

江西省| 裕民县| 江源县| 莎车县| 视频| 西青区| 屏东县| 珠海市| 安福县| 孟村| 长治县| 凯里市| 大港区| 嘉禾县| 黎平县| 临沧市| 长宁区| 嘉兴市| 会昌县| 北碚区| 新乡县| 万安县| 江源县| 洛南县| 温泉县| 左贡县| 韶关市| 无为县| 外汇| 嘉黎县| 修武县| 肇东市| 环江| 蕲春县| 吴旗县| 长兴县| 平果县| 德化县| 都昌县| 双柏县| 安泽县|