There is an old saying that we will always be children in our parents, and I will always be a vegetable chicken 🐣🐣🐣. No matter what, the passion of learning will never die. If the answer is wrong, thank you for your advice 🌚

First personal blog

The best time to plant a tree was ten years ago, and the second best time is now

Vue source worth learning points

  1. Currie,: A function that originally has multiple arguments is passed onlyaArgument, generating a new function that takes the remaining arguments and runs them to get the structure
  2. Partial function: A function that originally has multiple arguments is passed onlyPart of theArgument, generating a new function that takes the remaining arguments and runs them to get the structure
  3. Higher-order functions: a functionThe argument is a function, the function processes the parameter function to get a function, and the processing function is the higher-order function
  4. .

Vue responsive system

Description: During vUE initialization, object.defineProperty () is used to add getters and setters for each property in data, and deP and Watcher are created to collect dependencies and distribute updates. Finally, diff algorithm is used to compare the differences between new and old Vnodes. Update the DOM in real time through patch

Simple illustration:

A detailed version

You can refer toPicture reference address: Diagram Vue response principle

Why does Vue data change frequently but only updated once

  1. Data change detected
  2. Starting a queue
  3. Buffer all data changes in the same event loop
  4. If the sameWatcher (same as watcherId)If triggered multiple times, it will only be pushed to the queueAt a time

Setter ->Dep->Watcher->update->run

Update -> queueWatcher -> maintain observer queue (repeat id Watcher) -> waiting flag bit processing -> process $nextTick (update DOM asynchronous for microtask or macro task)

Vue uses the defect of object.defineProperty ()

The length property of an array is initialized with a different False, so it is not possible to listen on the length property using the GET /set method.

Vue overwrites seven methods that can change the array to listen for data

Objects are still listened to using object.defineProperty () to add get and set

reference

  • Vue modifies the data through the array index. Does the view change?

  • Why can’t defineProperty detect array length changes

Vue. NextTick () principle

The deferred callback is performed after the next DOM update loop ends. Use this method immediately after modifying the data to get the updated DOM.

Source code implementation: Promise > MutationObserver > setImmediate > setTimeout

Reference article: Brief analysis of vue.Nexttick () principle

Implementation principle of computed

Computed is essentially a lazy evaluated observer computed Watcher. Internally, it evaluates whether the attribute needs to be re-evaluated with the this.dirty attribute tag.

  • When a computed dependency changes, the lazy watcher is notified,computed watcherthroughthis.dep.subs.lengthTo determine if there are any subscribers,
  • If there is, it will be recalculated and compared to the old and new values, and if it changes, it will be re-rendered. Vue wants to make sure that not only does the value that the attribute depends on change, but when the attribute is evaluatedThe final calculated valueOnly when things changeTrigger the render watcherRe-render, essentially an optimization.)
  • If not, just putthis.dirty = true(The property is not recalculated immediately when it depends on other data. It is only evaluated later when the property needs to be read elsewhere, which is lazy.)

The understanding of the watch

Watch has no caching function and is more of an observation function. It can listen to certain data and perform callback. When we want to deeply listen for properties in an object, we can turn on the deep: true option, which will listen for every item in the object. This can cause performance problems, and can be optimized using string listening

Note: Watcher: an observer object. There are three types of instances: render Watcher, computed Watcher, and user Watcher

Vue diff algorithm

  • Only compare old and new child nodes with the same parent (Vnode), with only O(n) time complexity.
  • During the diff comparison, the loop closes in from both sides to the middle

The process of comparing old and new nodes

1. First find the same node that does not need to be moved, and then find the reusable node with the key value

2. Find the same node that needs to be moved, and consume the second smallest

3. If the node cannot be found, the node will be created and deleted to ensure the minimum processing

Note: The comparison process does not modify the Vnode trees. Instead, the actual DOM is modified as a result of the comparison

Vue patch is real-time, not all changes are packaged and then manipulated together in the DOM (React is to queue updates and then process them centrally).

Reference article: Vue Virtual DOM Diff principle detailed explanation

Vue rendering process

  1. callcompileTo generate the render function string, compile it as follows:
  • Parse uses a large number of regular expressions to parse the Template string, converting tags, instructions, attributes, and so on into an abstract syntax tree AST.Templates -> AST (most performance consuming)
  • Optimize through the AST, find some of the static nodes and mark them so that when you do diff comparisons when you re-render a page, you can skip over those static nodesOptimize Runtime performance
  • Generate converts the final AST to a render function string
  1. callnew WatcherThe Render function is executed to generate the VNode object when the data changes
  2. callpatchMethod, compare old and new VNode objects, and add, modify, and delete real DOM elements through DOM Diff algorithm

Let’s talk about the VUE life cycle in conjunction with the source code

Vue Life cycle official diagram

What is the use of a key in Vue?

The key is the unique ID given to each Vnode. Depending on the key, our diff operation can be more accurate and faster

More accurate: since there is no in-place reuse with the key, this can be avoided in the sameNode function a.keey === B.keey comparison. So it’s more accurate. If you don’t add a key, the state of the previous node will be retained, resulting in a series of bugs.

More quickly: the uniqueness of the key can be make full use of the Map data structure, compared to traverse to find the time complexity of O (n), the Map of time complexity is O (1), only the source code is as follows:

function createKeyToOldIdx(children, beginIdx, endIdx) {
  let i, key;
  const map = {};
  for (i = beginIdx; i <= endIdx; ++i) {
    key = children[i].key;
    if (isDef(key)) map[key] = i;
  }
  return map;
}

Copy the code

Note: In the absence of a key, it is faster. Thanks for the reminder of my elder brother Fengyangyang in the comment section: Quote from the official website: The special attribute of key is mainly used in Vue’s virtual DOM algorithm to identify VNodes when comparing old and new nodes. Without keys, Vue uses an algorithm that minimizes dynamic elements and tries to modify/reuse elements of the same type in place as much as possible. When using keys, it rearranges the elements based on key changes and removes elements where the key does not exist.

Vue-router There are several routing modes

Default value: “hash” (the browser environment) | “the abstract” (Node. Js environment)

Optional value: “hash” | | “history”, “abstract”

Configure the routing mode:

  • hash: Uses the URL hash value for routing.Support for all browsers, including browsers that do not support the HTML5 History Api.
  • history: rely onHTML5 History APIAnd server configuration.
  • abstract: Supports all JavaScript runtime environments, such as the Node.js server side. If no browser API is found, the route is automatically forced into this mode.

How keep-alive works

define

The keep-alive component accepts three attribute parameters: include, exclude, and Max

  • includeSpecify what needs to be cachedComponent nameSet, parameter format supportString, the RegExp, Array.When a string, multiple component names are separated by commas.
  • excludeSpecifies that the cache is not requiredComponent nameCollection, the argument format is the same as include.
  • maxSpecifies the maximum number of cacheable components, after which the first is deleted. The parameter format can be String or Number.

The principle of

The keep-alive instance caches the VNode of the corresponding component, and returns the VNode directly from the cache object if it hits the cache

LRU (Least Recently Used) algorithm is used to eliminate data according to the historical access records of data. Its core idea is that “if the data has been accessed recently, the chance of access in the future is higher”. (Murphy’s Law: The more you worry about something, the more it happens)

A method for resolving access to object properties

Eg: access A.B.C.D

Function currying + closure + recursion

    function createGetValueByPath( path ) {
      let paths = path.split( '. ' ); // [ xxx, yyy, zzz ]
      
      return function getValueByPath( obj ) {
        let res = obj;
        let prop;
        while( prop = paths.shift() ) {
          res = res[ prop ];
        }
        returnres; }}let getValueByPath = createGetValueByPath( 'a.b.c.d' );
    
    var o = {
      a: {
        b: {
          c: {
            d: {
              e: 'Right'}}}}};var res = getValueByPath( o );
    console.log( res );
Copy the code

Overrides of 7 array methods in vue

Vue overrides the 7 methods of the array with prototype interception, first getting an Observer of the array. If there is a new value, call observeArray to listen for the new value, then call Notify, notify Render Watcher, and perform the update

const arrayProto = Array.prototype;
export const arrayMethods = Object.create(arrayProto);
const methodsToPatch = [
  "push"."pop"."shift"."unshift"."splice"."sort"."reverse"
];

methodsToPatch.forEach(function(method) {
  // cache original method
  const original = arrayProto[method];
  def(arrayMethods, method, function mutator(. args) {
    const result = original.apply(this, args);
    const ob = this.__ob__;
    let inserted;
    switch (method) {
      case "push":
      case "unshift":
        inserted = args;
        break;
      case "splice":
        inserted = args.slice(2);
        break;
    }
    if (inserted) ob.observeArray(inserted);
    // notify change
    ob.dep.notify();
    return result;
  });
});

Observer.prototype.observeArray = function observeArray(items) {
  for (var i = 0, l = items.length; i < l; i++) { observe(items[i]); }};Copy the code

Vue handles the defineReactive implementation in response

    // Simplified version
    function defineReactive( target, key, value, enumerable ) {
      // This is the Vue instance
      let that = this;

      // The inside of the function is a local scope, and the value is the variable used only within the function (closure).
      if ( typeof value === 'object'&& value ! =null&&!Array.isArray( value ) ) {
        // A reference type that is not an array
        reactify( value ); / / recursion
      }

      Object.defineProperty( target, key, {
        configurable: true.enumerable:!!!!! enumerable, get () {console.log( Read `${key}Attribute ` ); / / additional
          return value;
        },
        set ( newVal ) {
          console.log( ` set${key}Properties:${newVal}` ); / / additionalvalue = reactify( newVal ); }}); }Copy the code

Vue responsive Reactify implementation

// Make the object o responsive
    function reactify( o, vm ) {
      let keys = Object.keys( o );

      for ( let i = 0; i < keys.length; i++ ) {
        let key = keys[ i ]; / / the property name
        let value = o[ key ];
        if ( Array.isArray( value ) ) {
          / / array
          value.__proto__ = array_methods; // The array is responsive
          for ( let j = 0; j < value.length; j++ ) {
            reactify( value[ j ], vm ); / / recursion}}else {
          // Object or value type
          defineReactive.call( vm, o, key, value, true); }}}Copy the code

Why do I not need data to access the data attribute

The implementation of the this.xxx transformation for the access property broker this.data. XXX in vUE

    /** Map an object's property access to an object's property member */
    function proxy( target, prop, key ) {
      Object.defineProperty( target, key, {
        enumerable: true.configurable: true,
        get () {
          returntarget[ prop ][ key ]; }, set ( newVal ) { target[ prop ][ key ] = newVal; }}); }Copy the code

References to articles (except as indicated in the article)

  • Vue.js technology revealed
  • “Interview Questions” 20+Vue interview questions
  • How many of the 12 vUE high-frequency principles interview questions can you answer?
  • Vue source code analysis of B station (video missing)
  • You are looking for vUE source all the universe is here
  • Inside Vue technology