Vue に nextTick があるのはなぜですか?

要約: この記事では、nextTick の役割、使用シナリオ、およびその背後にある原則を分析し、すべての人に役立つことを願っています。

この記事は HUAWEI CLOUD コミュニティから共有されたものです "Vue における nextTick の役割とは? 」、CoderBinによる。

1.ネクストティックとは

公式の定義を見てみましょう。

次の DOM 更新ループが終了した後に、遅延コールバックを実行します。データを変更した直後にこのメソッドを使用して、更新された DOM を取得します。

どういう意味ですか?

DOM の更新時に Vue が非同期で実行されることがわかります。データが変更されると、Vue は非同期更新キューを開き、ビューはキュー内のすべてのデータ変更が完了するのを待ってから、均一に更新する必要があります。

例えば:

HTML 構造

<div id="app"> {{ message }} </div>

vue インスタンスをビルドする

const vm = new Vue({
  el: '#app',
  data: {
    message: '原始值'
 }
})

メッセージの修正

this.message = '修改后的值1' 
this.message = '修改后的值2' 
this.message = '修改后的值3'

この時、ページの最新のDOMノードを取得したいのですが、古い値が取得されてしまいます。

console.log(vm.$el.textContent) // 原始值

これは、メッセージ データが変更されると、vue はすぐに Dom を更新せず、データを変更する操作を非同期操作キューに入れるためです。

同じデータを変更し続けると、非同期操作キューも重複排除されます

同じイベント ループ内のすべてのデータ変更が完了するのを待った後、キュー内のイベントが処理され、DOM が更新されます。

なぜ nexttick があるのか

例えば

{{num}} 
for(let i=0; i<100000; i++){ 
  num = i 
}

nextTick の更新メカニズムがない場合、num の値が更新されるたびにビューが更新されます (上記のコードはビューを 100,000 回更新します)。本質的には最適化戦略です

2. 使用シーン

データを変更した直後に更新された DOM 構造を取得したい場合は、Vue.nextTick() を使用できます。

  • 最初のパラメータは: コールバック関数 (最新の DOM 構造を取得できます)
  • 2 番目のパラメーターは次のとおりです。実行関数のコンテキスト
// 修改数据
vm.message = '修改后的值'
// DOM 还没有更新
console.log(vm.$el.textContent) // 原始的值
Vue.nextTick(function () {
 // DOM 更新了
  console.log(vm.$el.textContent) // 修改后的值
})

コンポーネントで vm.$nextTick() インスタンス メソッドを使用するには、this.$nextTick() を渡すだけでよく、コールバック関数の this は現在の Vue インスタンスに自動的にバインドされます。

this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
this.$nextTick(function () {
    console.log(this.$el.textContent) // => '修改后的值'
})

$nextTick() は Promise オブジェクトを返します。これは、async/await で同じことを達成するために使用できます。

this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
await this.$nextTick()
console.log(this.$el.textContent) // => '修改后的值'

3. 実現原理

ソースコードの場所: /src/core/util/next-tick.js

callbacks は非同期操作キューです

コールバック関数が追加された後、timerFunc 関数が実行されます。Pending は、同じ時間が 1 回しか実行できないことを識別するために使用されます。

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;
 });
 }
}

timerFunc 関数の定義は、現在の環境でサポートされているメソッドに応じて、呼び出すメソッドを決定するためのものです。

Promise.then、MutationObserver、setImmediate、setTimeout

上記の方法のいずれかを使用してダウングレードします

export let isUsingMicroTask = false
if (typeof Promise !== 'undefined' && isNative(Promise)) {
 //判断1:是否原生支持Promise
 const p = Promise.resolve()
 timerFunc = () => {
 p.then(flushCallbacks)
 if (isIOS) setTimeout(noop)
 }
 isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
 isNative(MutationObserver) ||
 MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
 //判断2:是否原生支持MutationObserver
 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
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
 //判断3:是否原生支持setImmediate
 timerFunc = () => {
 setImmediate(flushCallbacks)
 }
} else {
 //判断4:上面都不行,直接用setTimeout
 timerFunc = () => {
 setTimeout(flushCallbacks, 0)
 }
}

マイクロ タスクでもマクロ タスクでも、flushCallbacks で使用されます。

ここで、コールバック内の関数のコピーを作成し、コールバックを空のままにします。

コールバック内の関数を順番に実行します

function flushCallbacks () {
  pending = false
 const copies = callbacks.slice(0)
 callbacks.length = 0
 for (let i = 0; i < copies.length; i++) {
    copies[i]()
 }
}

第四に、最終的なまとめ

  1. コールバック関数をコールバックに入れ、実行を待機します
  2. 実行関数をマイクロタスクまたはマクロタスクに入れる
  3. イベントはマイクロタスクまたはマクロ タスクにループし、実行関数はコールバック内のコールバックを順番に実行します。

 

フォローをクリックして、HUAWEI CLOUDの新技術について初めて学びましょう〜

{{o.name}}
{{m.name}}

おすすめ

転載: my.oschina.net/u/4526289/blog/5584854