preface

This article mainly handwritten Vue2.0 source code – asynchronous update principle

Last time we introduced the Vue render update principle, we can realize the data change view automatically update, so this article mainly focuses on the performance optimization of view update, including the important API implementation of nextTick

Applicable to the crowd: no time to look at the official source code or look at the source code to see the more meng and do not want to see the students

Suggestion: This article involves the concept of JS event loop related to macro task and micro task is not very clear students can look at the relevant information


The body of the

<script>
  // Instantiate Vue
  let vm = new Vue({
    el: "#app".data() {
      return {
        a: 123}; },// render(h) {
    // return h('div',{id:'a'},'hello')
    // },
    template: `<div id="a">hello {{a}}</div>`});// Rendering watcher executes a rendering watcher every time we change data. This affects performance
  setTimeout(() = > {
    vm.a = 1;
    vm.a = 2;
    vm.a = 3;
  }, 1000);
</script>
Copy the code

If you think about it in terms of the logic that every time we change the data it triggers the watcher to update it and if it’s a render watcher does that mean that once the data changes it’s going to render it again and that’s a waste of performance and there’s a better way to do it Let the data changes after the unified to update the view

1. Rewrite of watcher’s update

// src/observer/watcher.js

import { queueWatcher } from "./scheduler";
export default class Watcher {
  update() {
    // Each time watcher makes an update, can they be cached and then called together
    // Asynchronous queuing mechanism
    queueWatcher(this);
  }
  run() {
    // The actual trigger update
    this.get(); }}Copy the code

Let’s change the update method to add asynchronous queues

2. QueueWatcher Implements the queue mechanism

// src/observer/scheduler.js

import { nextTick } from ".. /util/next-tick";
let queue = [];
let has = {};
function flushSchedulerQueue() {
  for (let index = 0; index < queue.length; index++) {
    // Call watcher's run method to perform the actual update
    queue[index].run();
  }
  // Clear the queue after execution
  queue = [];
  has = {};
}

// Implement the asynchronous queuing mechanism
export function queueWatcher(watcher) {
  const id = watcher.id;
  / / to weight watcher
  if (has[id] === undefined) {
    // Synchronize code execution to put all watcher in the queue
    queue.push(watcher);
    has[id] = true;
    // Make an asynchronous callnextTick(flushSchedulerQueue); }}}Copy the code

A new scheduler.js file is created to synchronize the watcher to the queue and then clear the queue after executing the events on the queue. The watcher queue is executed using nextTick

3. Implementation principle of nextTick

// src/util/next-tick.js

let callbacks = [];
let pending = false;
function flushCallbacks() {
  pending = false; // Restore flag to false
  // Execute the callbacks in sequence
  for (let i = 0; i < callbacks.length; i++) { callbacks[i](); }}let timerFunc; // Define an asynchronous method with graceful degradation
if (typeof Promise! = ="undefined") {
  // If promise is supported
  const p = Promise.resolve();
  timerFunc = () = > {
    p.then(flushCallbacks);
  };
} else if (typeofMutationObserver ! = ="undefined") {
  // MutationObserver is an asynchronous method that listens for dom changes
  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);
  };
} else if (typeofsetImmediate ! = ="undefined") {
  // If neither of the preceding supports setImmediate
  timerFunc = () = > {
    setImmediate(flushCallbacks);
  };
} else {
  // The last degradation is to use setTimeout
  timerFunc = () = > {
    setTimeout(flushCallbacks, 0);
  };
}

export function nextTick(cb) {
  // In addition to rendering watcher, the nextTick is collected into the array along with the user's own manual call
  callbacks.push(cb);
  if(! pending) {// If nextTick is called multiple times, the flag will be changed to false after the asynchronous queue is cleared
    pending = true; timerFunc(); }}Copy the code

Create a new util/next-tick.js to represent the utility class functions because the nextTick user can also call them manually. The main idea is to call asynchronous methods to execute the nextTick wrapped methods in a microtask-first way

4.$nextTick mounts the prototype

// src/render.js

import { nextTick } from "./util/next-tick";

export function renderMixin(Vue) {
  // The nextTick method mounted on the prototype can be called manually by the user
  Vue.prototype.$nextTick = nextTick;
}
Copy the code

Finally, mount the $nextTick to Vue’s prototype

4. Mind maps with asynchronous updates

summary

So far, Vue’s asynchronous update principle has been completed. The core principle is that nextTick implements asynchronous queue. If you need to understand js event loop mechanism, you can look at the mind map and write the core code by yourself

Finally, if you find this article helpful, remember to like it three times. Thank you very much!

Series of links (will be updated later)

  • Handwriting Vue2.0 source code (a) – response data principle
  • Handwriting Vue2.0 source code (2) – template compilation principle
  • Handwriting Vue2.0 source code (three) – initial rendering principle
  • Handwriting Vue2.0 source code (four) – rendering update principle
  • Handwriting Vue2.0 source code (five) – asynchronous update principle
  • Handwriting Vue2.0 source code (six) -diff algorithm principle
  • Handwriting Vue2.0 source code (seven) -Mixin Mixin principle
  • Handwriting Vue2.0 source code (eight) – component principle
  • Handwriting Vue2.0 source code (nine) – listening attribute principle
  • Handwriting Vue2.0 source code (ten) – the principle of computing attributes
  • Handwriting Vue2.0 source code (eleven) – global API principle
  • The most complete Vue interview questions + detailed answers
  • Handwritten vue-Router source code
  • Write vuex source code
  • Handwriting vue3.0 source code

Shark brother front touch fish technology group

Welcome technical exchanges within the fish can be pushed for help – link