ホームページ  >  記事  >  ウェブフロントエンド  >  Vue2.6のnextTickメソッドの解析

Vue2.6のnextTickメソッドの解析

不言
不言転載
2019-02-28 11:58:152210ブラウズ

この記事の内容は Vue2.6 の nextTick メソッドの解析に関するものです。必要な方は参考にしていただければ幸いです。

Vue 2.6nextTick メソッドの簡単な分析。

イベント ループ

JS の イベント ループ タスク キュー は、実際、nextTick の概念を理解するための鍵です。
実際、このインターネット上にはそれを詳しく紹介した質の高い記事がたくさんあるので、簡単に読んでみました。

次の内容はブラウザ側 JS に適用されます。NodeJS のイベント ループ メカニズムは異なります。

仕様では、タスクが task(macrotask)microtask の 2 つのカテゴリに分類されると規定されています。

通常 task と見なされるタスク ソース:

setTimeout / setInterval
setImmediate
MessageChannel
I/O
UI rendering

通常 microtask と見なされるタスク ソース:

Promise
process.nextTick
MutationObserver
Object.observe(已废弃)

簡単な概要: (これが公式の仕様です)

  1. まず、実行コンテキスト スタックが空になるまで スクリプト script の実行を開始し、その後 ## のクリアを開始します。 #microtask queue タスクは先入れ先出しでキューに入れられ、それぞれが次々に実行され、タスクがクリアされた後にイベント ループが実行されます。

  2. イベント ループ: タスク キューからタスクを継続的にフェッチし、実行のためにスタックにプッシュし、現在のタスクで実行します。ループ microtask queue 内のタスクを順番にクリアします。クリア後、ページ更新のレンダリングがトリガーされる場合があります (ブラウザーによって決定されます)。

  3. その後、

    イベント ループの手順を繰り返します。

nextTick

Vue のデータから DOM の更新されたレンダリングへの変更は、非同期プロセスです。

このメソッドは、DOM 更新サイクルの終了後に遅延コールバックを実行するために使用されます。
使用方法は非常に簡単です:

// 修改数据
vm.msg = 'Hello';
// DOM 还没有更新
Vue.nextTick(function() {
  // DOM 更新了
});

// 作为一个 Promise 使用
Vue.nextTick().then(function() {
  // DOM 更新了
});
コメントを除いたソース コードは実際には 100 行未満ですが、それでも全体を理解するのは非常に簡単です。

これは 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);
  };
}
優先度を一文で要約:

マイクロタスクの優先度
約束 > MutationObserver > setImmediate > setTimeoutnextTick関数

nextTick 関数。 2 つのパラメータを受け入れます:

    cb コールバック関数
  1. : 遅延させる関数です。 ##: 指定された cb コールバック関数の

    this は を指します。

  2. Vue インスタンス メソッド

    $nextTick がさらにカプセル化され、 ctx現在の Vue インスタンス

    に設定されます。
  3. 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 array

timerFunc 関数

を実行し、flushCallbacks 関数 の呼び出しを遅らせ、
callbacks 配列 内のすべての関数を走査して実行します。 遅延呼び出しの優先順位は次のとおりです: Promise > setImmediate >

##バージョンの違い


実際、Vue 2.4、2.5、および 2.6 バージョンの nextTick 戦略は次のとおりです。若干異なります。 全体的に 2.6

2.4 は比較的似ています。 (よく見てください。基本的には同じです。2.6

timerFunc には setImmediate の判定が追加されています)

2.5 バージョンは実際には似ています。 。 。ソース コードの書き方は少し異なります。 Promise > setTimeout >更新は v-on イベント ハンドラーでトリガーされ、nextTick は最初にマクロタスクを使用します。

以上がVue2.6のnextTickメソッドの解析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。