Heim  >  Artikel  >  Web-Frontend  >  Implementieren Sie eine asynchrone Update-Warteschlange über nextTick() in Vuejs

Implementieren Sie eine asynchrone Update-Warteschlange über nextTick() in Vuejs

亚连
亚连Original
2018-06-14 15:11:361789Durchsuche

In diesem Artikel wird hauptsächlich die Quellcode-Analyse der asynchronen Aktualisierungswarteschlange nextTick() in Vuejs vorgestellt. Jetzt teile ich sie mit Ihnen und gebe sie als Referenz.

Die offizielle Website von Vue erklärt dies wie folgt:

Das detaillierte reaktive Prinzip der asynchronen Aktualisierungswarteschlange in vue2.0

Die offizielle Website erklärt wie folgt:

Solange Vue Datenänderungen beobachtet, öffnet es eine Warteschlange und puffert alle Datenänderungen, die in derselben Ereignisschleife auftreten. Wenn derselbe Watcher mehrmals ausgelöst wird, wird er nur einmal in die Warteschlange verschoben. Diese Deduplizierung während der Pufferung ist wichtig, um unnötige Berechnungen und DOM-Operationen zu vermeiden. Beim nächsten „Tick“ der Ereignisschleife leert Vue dann die Warteschlange und führt die eigentliche (deduplizierte) Arbeit aus. Vue versucht intern, natives Promise.then und MutationObserver für asynchrone Warteschlangen zu verwenden. Wenn die Ausführungsumgebung dies nicht unterstützt, wird stattdessen setTimeout(fn, 0) verwendet.

Wenn Sie beispielsweise vm.someData = „new value“ festlegen, wird die Komponente nicht sofort erneut gerendert. Wenn die Warteschlange geleert wird, wird die Komponente beim nächsten „Tick“ aktualisiert, wenn die Ereignisschleifenwarteschlange gelöscht wird. In den meisten Fällen müssen wir uns um diesen Vorgang nicht kümmern, aber wenn Sie nach der Aktualisierung des DOM-Status etwas tun möchten, kann dies etwas schwierig sein. Während Vue.js Entwickler im Allgemeinen dazu ermutigt, „datengesteuert“ zu denken und das DOM nicht direkt zu berühren, gibt es Zeiten, in denen wir das wirklich tun müssen. Um zu warten, bis Vue die Aktualisierung des DOM nach den Datenänderungen abgeschlossen hat, können Sie Vue.nextTick(callback) unmittelbar nach den Datenänderungen verwenden. Diese Rückruffunktion wird aufgerufen, nachdem die DOM-Aktualisierung abgeschlossen ist. Der

Quellcode-Analyse

-Methodenprototyp und die Analysekommentare lauten beispielsweise wie folgt:

var nextTick = (function () {
    var callbacks = []; // 存储需要触发的回调函数
    var pending = false; // 是否正在等待的标识(false:允许触发在下次事件循环触发callbacks中的回调, true: 已经触发过,需要等到下次事件循环)
    var timerFunc; // 设置在下次事件循环触发callbacks的 触发函数

    //处理callbacks的函数
    function nextTickHandler () {
      pending = false;// 可以触发timeFunc
      var copies = callbacks.slice(0);//复制callback
      callbacks.length = 0;//清空callback
      for (var i = 0; i < copies.length; i++) {
        copies[i]();//触发callback回调函数
      }
    }

    //如果支持Promise,使用Promise实现
    if (typeof Promise !== &#39;undefined&#39; && isNative(Promise)) {
      var p = Promise.resolve();
      var logError = function (err) { console.error(err); };
      timerFunc = function () {
        p.then(nextTickHandler).catch(logError);
        // ios的webview下,需要强制刷新队列,执行上面的回调函数
        if (isIOS) { setTimeout(noop); }
      };

      //如果Promise不支持,但是支持MutationObserver(h5新特性,异步,当dom变动是触发,注意是所有的dom都改变结束后触发)
    } else if (typeof MutationObserver !== &#39;undefined&#39; && (
        isNative(MutationObserver) ||
        // PhantomJS and iOS 7.x
        MutationObserver.toString() === &#39;[object MutationObserverConstructor]&#39;
      )) {
      // use MutationObserver where native Promise is not available,
      // e.g. PhantomJS IE11, iOS7, Android 4.4
      var counter = 1;
      var observer = new MutationObserver(nextTickHandler);
      //创建一个textnode dom节点,并让MutationObserver 监视这个节点;而 timeFunc正是改变这个dom节点的触发函数
      var textNode = document.createTextNode(String(counter));
      observer.observe(textNode, {
        characterData: true
      });
      timerFunc = function () {
        counter = (counter + 1) % 2;
        textNode.data = String(counter);
      };
    } else {// 上面两种不支持的话,就使用setTimeout

      timerFunc = function () {
        setTimeout(nextTickHandler, 0);
      };
    }
    //nextTick接受的函数, 参数1:回调函数 参数2:回调函数的执行上下文
    return function queueNextTick (cb, ctx) {
      var _resolve;//用于接受触发 promise.then中回调的函数
      //向回调数据中pushcallback
      callbacks.push(function () {
        //如果有回调函数,执行回调函数
        if (cb) { cb.call(ctx); }
        if (_resolve) { _resolve(ctx); }//触发promise的then回调
      });
      if (!pending) {//是否执行刷新callback队列
        pending = true;
        timerFunc();
      }
      //如果没有传递回调函数,并且当前浏览器支持promise,使用promise实现
      if (!cb && typeof Promise !== &#39;undefined&#39;) {
        return new Promise(function (resolve) {
          _resolve = resolve;
        })
      }
    }
  })();

Ich habe die Logik der nextTick()-Funktion erklärt in den Kommentaren

Der Grund, warum die oben genannten drei Möglichkeiten zur Behandlung von Rückrufen Priorität verwenden: Weil sich Promise und MutationObserver in derselben Ereignisschleife wie das ausgelöste Ereignis befinden (sie werden nur in der Mikrowarteschlange ausgeführt), aber der setTimeout-Rückruf Die Funktion läuft innerhalb der Zeitschleife.

Der Grund für die erste Verwendung von Promise ist, dass MutationObserver stoppt, nachdem es eine Zeit lang in UIWebview von ios9.3.3 oder höher ausgeführt wurde.
Die Kommentare im obigen Code haben die Codelogik vollständig erklärt. Einfaches Verständnis: Schieben Sie den Rückruf in die Warteschlange. Wenn er noch nicht ausgeführt wurde, wird die Rückruffunktion bei der nächsten Ausführung der Ereignisschleife ausgelöst.

Hinweis: Wenn Sie nextTick() verwenden, ohne eine Rückruffunktion festzulegen, aber Promise verwenden, um die Rückruffunktion festzulegen, zeigt dies nicht auf die aktuelle Vue-Instanz, sondern auf das Fenster (der strenge Modus ist undefiniert);
Aber aus der obigen Analyse können wir sehen, dass der Ausführungskontext über den ersten Parameter der Rückruffunktion in Promise.then() übergeben wird.

Wo nextTick() verwendet wird

1 Es ist eine Funktion von globalem Vue, sodass wir sie direkt über Vue aufrufen können.

2. Im Vue-System werden Vorgänge zur Verarbeitung von Dom-Updates verwendet.

In Vue gibt es einen Watcher, der zum Beobachten von Datenänderungen und zum anschließenden Aktualisieren des Doms verwendet wird. Wir wussten bereits, dass in Vue nicht jede Datenänderung eine Aktualisierung des Doms auslöst. Stattdessen werden diese Vorgänge in einer Warteschlange zwischengespeichert. Nach dem Ende einer Ereignisschleife wird die Warteschlange aktualisiert und die Dom-Aktualisierungsvorgänge werden einheitlich ausgeführt.

function queueWatcher (watcher) {
    var id = watcher.id;
    if (has[id] == null) {
      has[id] = true;
      if (!flushing) {
        queue.push(watcher);
      } else {
        // if already flushing, splice the watcher based on its id
        // if already past its id, it will be run next immediately.
        var i = queue.length - 1;
        while (i >= 0 && queue[i].id > watcher.id) {
          i--;
        }
        queue.splice(Math.max(i, index) + 1, 0, watcher);
      }
      // queue the flush
      if (!waiting) {
        waiting = true;
        nextTick(flushSchedulerQueue);
      }
    }
  }

Erklären Sie kurz die Logik des obigen Codes, da es sich um den Code des Beobachters handelt und später analysiert wird. Die Funktion von nextTick() besteht hier darin, den vom Watcher am Ende dieser Ereignisschleife überprüften Dom-Aktualisierungsvorgang zu aktualisieren.

3. Partielles Vue löst $nextTick() aus und führt die entsprechende Logik aus, nachdem der Dom aktualisiert wurde.

Vue.prototype.$nextTick = function (fn) {
  return nextTick(fn, this)// 设置nextTick回调函数的上下文环境是当前Vue实例
};

Das Obige ist ein Code in renderMinxin, der der Code zum Initialisieren des Rendermoduls ist.

Zusammenfassung

Wenn wir den Code nicht verstehen, werden wir Missverständnisse haben.

1. nextTick() zeichnet die aktuelle Seite nicht neu und wird erst ausgeführt, wenn die Seite neu gezeichnet wird, wird aber definitiv ausgeführt, nachdem die Ereignisschleife endet.

2. Das Auslösen dieser Methode wird nicht ausgeführt, nachdem die Seitenaktualisierung abgeschlossen ist. Das erste Element wurde bereits erwähnt, aber warum können die aktualisierten Daten in dieser Methode abgerufen werden? Das dom-Element wurde geändert, als der Beobachter die Flush-Warteschlange ausführte, sodass es zu diesem Zeitpunkt abgerufen werden kann.

Beispiele, die den obigen Punkt beweisen:

h5 hat eine Methode requestFrameAnimation(callback), der Rückruf dieser Methode wird aufgerufen, bevor die Seite neu gezeichnet wird. Durch Experimente wird beim Aktualisieren des Doms nextTick() vor dieser Methode ausgeführt.

Ich habe das Obige für Sie zusammengestellt und hoffe, dass es Ihnen in Zukunft hilfreich sein wird.

Verwandte Artikel:

So laden Sie Daten mithilfe der Baumansicht im Bootstrap-Framework dynamisch

Über das Codebeispiel für ein Kapitelverzeichnis zur Website-Generierung

Einführung in die Vue-Datenbindung im Detail

Das obige ist der detaillierte Inhalt vonImplementieren Sie eine asynchrone Update-Warteschlange über nextTick() in Vuejs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn