About vUE reading and summary, this is an understanding of VUE after in-depth thinking. Learn more by analogy.

Background (Why learn source code for open Source projects)

An example I recently saw for myself: In vue-Router, the life cycle can be mixed with vue.min, where the mixed life cycle is called at this stage of the life cycle of each component:

  Vue.mixin({
    beforeCreate () {
      if (isDef(this.$options.router)) {
        this._routerRoot = this
        this._router = this.$options.router
        this._router.init(this)
        Vue.util.defineReactive(this.'_route'.this._router.history.current)
      } else {
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      registerInstance(this.this)
    },
    destroyed () {
      registerInstance(this)}})Copy the code

See this implementation, for the future want to implement vUE plug-in and binding life cycle, provides a good idea and method, often can be connected by analogy, have unexpected harvest.

Tell me what you understand about MVVM

The MVVM consists of the following three components

  • Interface of the View:
  • Model: Data Model
  • ViewModel: Act as a bridge between View and Model

In the era of JQuery, if you need to refresh the UI, you need to fetch the corresponding DOM and then update the UI, so that the data and business logic is strongly coupled with the page.

In MVVM, the core is two-way data binding, such as dirty data detection in Angluar and data hijacking in Vue.

What exactly is MVVM? Instead of focusing on how MVVM came to be, let's look at how a typical application is built and learn about MVVM from there:

This is a typical MVC setup. The Model renders the data, the View renders the user interface, and the View Controller moderates the interaction between the two.

Although the View and View Controller are technically different components, they almost always go hand in hand, in pairs.

Try linking them:

In a typical MVC application, a lot of logic is stored in a View Controller. Some of them are View Controllers, but a lot of them are what’s called presentation logic.

In MVVM generic terms, these are the things that convert Model data into something that the View can render, such as converting an NSDate to a formatted NSString.

There’s something missing from our diagram, something that would allow us to put all the representation logic in there. We’re going to call it “View Model” — it sits between the View/Controller and Model:

This diagram describes exactly what MVVM is: an enhanced VERSION of MVC where we formally connect the View and Controller and move the presentation logic out of the Controller and into a new object, the View Model.

Talk about V-if and V-show

V – show and v – the if

  1. v-if: True conditional rendering. False, not in the DOM.
  2. v-show: always in the DOM, just toggled with the DISPLAY property of CSS (present in HTML structure, but not rendered with CSS). Exists in a DOM structure
  3. display:noneIs not in the render tree.

Visibility: hidden and display: None

Display: None: The tag does not appear on the page (although you can still interact with it through the DOM). Other tags do not allocate space for it. The tag will appear on the page, but will not be visible. Other tags will allocate space for it.

Data in a component must be an object returned by a function, not just an object

Parse (json.stringify (…)) by passing vm.$data to json.parse (json.stringify (…)) ) to get a deep copy of the original data object.

Describe some common types of component communication

props emit

Props props: emit

Problem: Multi-level nested components

provide / inject

This pair of options needs to be used together to allow an ancestor component to inject a dependency into all of its descendants, regardless of how deep the component hierarchy is, and remain in effect for as long as its upstream and downstream relationships are established.

Element – UI button component, part of the source

// Button component core source code
export default {
    name: 'ElButton'.// Get elForm and elFormItem components by inject
    inject: {
        elForm: {
            default: ' '
        },
        elFormItem: {
            default: ' '}},// ...
    computed: {
        _elFormItemSize() {
            return (this.elFormItem || {}).elFormItemSize;
        },
        buttonSize() {
            return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
        },
        / /...
    },
    // ...
};
Copy the code

Problem: Cannot implement child component to pass data to ancestor component

$attrs $listeners

Provide and inject data of multilevel components, but do not allow child components to transmit data to their ancestors. $attrs and $Listeners can be used for child parent transmission

For details, see attrs and Attrs and Attrs and Listeners in this article

EventBus

For some projects where vuEX is not necessary, consider

EventBus: EventBus can be used to easily communicate between sibling components and cross-level components, but it can also cause problems when used incorrectly (vue is a single-page application, and if you refresh a page, the EventBus associated with it will be removed, thus causing business to fail). Therefore, vuex is recommended for small pages where the logic is not complex

class EventBus{
    constructor(){
        // A map that stores the mapping between events and callbacks
        this.event=Object.create(null);
    };
    // Register events
    on(name,fn){
        if(!this.event[name]){
            // An event can have multiple listeners
            this.event[name]=[];
        };
        this.event[name].push(fn);
    };
    // Trigger the event
    emit(name,... args){
        // Call the callback function
        this.event[name]&&this.event[name].forEach(fn= >{ fn(... args) }); };// An event that is triggered only once
    once(name,fn){
        // It registers the event, triggers the event, and finally cancels the event.
        const cb=(. args) = >{
            / / triggersfn(... args);/ / cancel
            this.off(name,fn);
        };
        / / to monitor
        this.on(name,cb);
    };
    // Cancel the event
    off(name,offcb){
        if(this.event[name]){
            let index=this.event[name].findIndex((fn) = >{
                return offcb===fn;
            })
            this.event[name].splice(index,1);
            if(!this.event[name].length){
                delete this.event[name]; }}}}Copy the code

Vuex

For state management, vuEX is still recommended when logic is complex

What are the phases of the Vue life cycle doing

beforeCreate,created

The beforeCreate and Created life cycles are executed in _init at initialization time

Specific code in vue/SRC/core/instance/init. Js

Vue.prototype._init = function() {
      // expose real self
    / /...
    vm._self = vm
    initLifecycle(vm) // Initialize the life cycle
    initEvents(vm) // Initialize the event
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm) // Initialize props, methods, data, computed, and so on
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')
    // ...
}
Copy the code
  1. beforeCreate. Can’t use props, methods, data, computed, etc.
  2. initStateInitialize props, methods, data, computed, and so on.
  3. createdIn this case, props, methods, data, computed, and so on are available. If you want to use the data attribute, call it here.

The beforeCreate and created hook functions do not render the DOM, so we cannot access the DOM. If you need to access props, data, etc., you need to use the Created hook function.

beforeMount,mounted

Mounting refers to mounting the compiled HTML template to the corresponding virtual DOM

Called before the mount begins: The associated render function is called for the first time.

This hook is not called during server-side rendering.

export function mountComponent (vm: Component, el: ? Element, hydrating? : boolean) :Component {
  vm.$el = el
  if(! vm.$options.render) { vm.$options.render = createEmptyVNodeif(process.env.NODE_ENV ! = ='production') {
      /* istanbul ignore if */
      // ...
    }
  }
  callHook(vm, 'beforeMount')

  let updateComponent
  /* istanbul ignore if */
  if(process.env.NODE_ENV ! = ='production' && config.performance && mark) {
    updateComponent = () = > {
      // ...
      vm._update(vnode, hydrating)
      // ...}}else {
    updateComponent = () = > {
      vm._update(vm._render(), hydrating)
    }
  }

  // manually mounted instance, call mounted on self
  // mounted is called for render-created child components in its inserted hook
  if (vm.$vnode == null) {
    vm._isMounted = true
    callHook(vm, 'mounted')}return vm
}
Copy the code

BeforeMount hook function is executed before vm._render() is executed to render VNode. Mounted hook is executed after vm._update() is executed to patch VNode to the real DOM.

beforeUpdate,updated

BeforeUpdate and updated hook functions should be executed at data update time

  Vue.prototype._update = function (vnode: VNode, hydrating? : boolean) {
    const vm: Component = this
    if (vm._isMounted) {
      callHook(vm, 'beforeUpdate')}const prevEl = vm.$el
    const prevVnode = vm._vnode
    const prevActiveInstance = activeInstance
    activeInstance = vm
    vm._vnode = vnode
    // ...
  }
Copy the code

One detail here is _isMounted, which means that beforeUpdate is executed after mounted

Updated means that the component DOM was updated when the hook was called, so you can now perform DOM-dependent operations

beforeDestroy,destroyed

BeforeDestroy and Destroyed hook functions are executed during component destruction

  Vue.prototype.$destroy = function () {
    const vm: Component = this
    if (vm._isBeingDestroyed) {
      return
    }
    callHook(vm, 'beforeDestroy')
    vm._isBeingDestroyed = true
    // remove self from parent
    const parent = vm.$parent
    if(parent && ! parent._isBeingDestroyed && ! vm.$options.abstract) { remove(parent.$children, vm) }// teardown watchers
    if (vm._watcher) {
      vm._watcher.teardown()
    }
    let i = vm._watchers.length
    while (i--) {
      vm._watchers[i].teardown()
    }
    // remove reference from data ob
    // frozen object may not have observer.
    if (vm._data.__ob__) {
      vm._data.__ob__.vmCount--
    }
    // call the last hook...
    vm._isDestroyed = true
    // invoke destroy hooks on current rendered tree
    vm.__patch__(vm._vnode, null)
    // fire destroyed hook
    callHook(vm, 'destroyed')
    // turn off all instance listeners.
    vm.$off()
    // remove __vue__ reference
    if (vm.$el) {
      vm.$el.__vue__ = null
    }
    // release circular reference (#6759)
    if (vm.$vnode) {
      vm.$vnode.parent = null}}}Copy the code

BeforeDestroy the hook function executes at the beginning of the execution of $destroy, followed by a series of destruction actions, including deleting itself from parent’s $children, deleting watcher, The currently rendered VNode performs hook destruction, etc., and then calls the destroy hook function.

__patch__(vm._vnode, NULL) triggers the destroy hook function of its children. This is the same as when the destroy hook function is mounted.

actived,deactivated

The activated and deactivated hook functions are custom hooks for keep-alive components

  1. activatediskeep-aliveCalled when the component is activated.
  2. deactivatediskeep-aliveCalled when a component is destroyed.

errorCaptured

Called when an error from a descendant component is caught. The hook receives three parameters: the error object, the component instance where the error occurred, and a string containing information about the source of the error. This hook can return false to prevent further propagation of the error.

What happens at New Vue

  1. Call _init to merge configuration, initialize lifecycle, initialize event center, initialize render, initialize Data, props, computed, Watcher, and so on
  2. throughObject.definePropertySet up thesettergetterFunction to implement reactive and dependency collection

Talk about how the reactive principle works

When a Vue instance is created, Vue iterates through the properties of the data option, hijacking the reading of the data by adding getter and setter to the property with Object.defineProperty (getters are used to rely on collection, setters) To distribute updates), and internally track dependencies, notifying properties of changes when they are accessed and modified.

Each component instance has a corresponding Watcher instance, which records all the data properties of dependencies during component rendering (for dependency collection, for computed Watcher, for user Watcher instances), and then informs the dependency of that data when it changes The Watcher instance is recalculated (updates are distributed) to re-render its associated components.

To sum up, vue.js adopts data hijacking combined with publishe-subscribe mode. It hijacks setter and getter of each attribute through Object.defineProperty, releases messages to subscribers when data changes, and triggers listener callback of response

A central role

  • Observer: Adds getters and setters to objects that rely on collecting and distributing updates. Not only a data listener, but also a publisher;
  • Watcher (Subscriber) : The Observer forwards the data to the actual subscriber, the Watcher object. When Watcher receives new data, it updates the view. Watcher instances are divided into render Watcher (render Watcher), computed Watcher, and listener user Watcher. Maintains an array of instances of DEPS (for collecting dependencies). For secondary dependency collection, cleanupDeps will remove the DEPs of the old subscription after each new subscription is added.
  • Compile (compiler) : a role specific to the MVVM framework that scans and parses each node element instruction, as well as the “chores” of initializing the instruction’s data and creating subscribers;
  • Dep: Used to collect the dependencies of the current responsive object. Each responsive object has a Dep instance (subs is an array of Watcher instances)dep.notify()Notify each Watcher (iterating through subs, calling each Watcher’s Update () method)

The relationships of the core roles are as follows:

The core code

Implement the observer

// Iterate over the object
function observer(target) {
  // target is an object
  if (target && typeof target === 'object') {
    Object.keys(target).forEach(key= > {
      defineReactive(target, key, target[key])
    })
  }
}

// Listen for the current attribute with defineProperty
function defineReactive(target, key, val) {
  const dep = new Dep()
  / / recursion
  observer(val)
  Object.defineProperty(target, key, {
    / / can be enumerated
    enumerable: true.// Cannot be configured
    configurable: false.get: function() {
      return val
    },
    set: function(value) {
      console.log(val, value)
      val = value
    }
  })
}
Copy the code

Implement deP subscribers

class Dep {
  constructor() {
    // Initialize the subscription queue
    this.subs = []
  }
  // Add a subscription
  addSub(sub) {
    this.subs.push(sub)
  }
  // Notify subscribers
  notify() {
    this.subs.forEach(sub= > {
      sub.update()
    })
  }
}
Copy the code

The subs array in the subscriber Dep is the Watcher instance

Realize the Watcher class

class Watcher {
  constructor() {}
  update() {
    // Update the view}}Copy the code

Override setter methods in defineReactive to notify subscribers in listeners:

// Listen for the current attribute with defineProperty
function defineReactive(target, key, val) {
  const dep = new Dep()
  / / recursion
  observer(val)
  Object.defineProperty(target, key, {
    / / can be enumerated
    enumerable: true.// Cannot be configured
    configurable: false.get: function() {
      return val
    },
    set: function(value) {
      console.log(val, value)
      dep.notify()
    }
  })
}
Copy the code

2. The relationship between Watcher and Dep

The DEP is instantiated in watcher and subscribers are added to dep.subs, which notifies each Watcher of updates through notify through dep.subs.

3. The computed and watch

Computed in nature is an lazily evaluated observer.

Computed implements an inert WATcher internally, that is,computed Watcher, which does not evaluate immediately and holds an instance of DEP. The this.dirty attribute tag internally calculates whether the attribute needs to be reevaluated.

When the dependency state of computed changes, the lazy Watcher is notified, and computed Watcher determines whether there are subscribers by this.dep.subs.length. If it does, it recalculates and compares the old and new values, and if it changes, it rerenders. (Vue wanted to make sure that not only did the values of the calculated property dependencies change, but that the rendering Watcher was only triggered to re-render when the final calculated value of the calculated property changed, essentially an optimization.)

If not, just set this.dirty = true. (When a calculated property depends on other data, it is not recalculated immediately, but only computed later when the property needs to be read elsewhere, which is called lazy.)

The difference between

Computed attributes: Depend on other attribute values, and computed values are cached. If the attribute values it depends on change, computed values will be recalculated the next time it gets computed values.

Watch listener: More of a “watch” function, cache-free, similar to some data listening callbacks that perform subsequent operations whenever the monitored data changes.

4. Rely on collection

  1. InitState triggers a computed Watcher dependency collection when the computed property is initialized
  2. When initState, user Watcher dependency collection is triggered when the watch property is initialized
  3. The render() procedure triggers the Render Watcher dependency collection
  4. When re-render is executed, vm.render() removes the subs subscription and reassigns it

5. Send updates

  1. Component, reactive data is modified to trigger setter logic
  2. Call dep. Notity ()
  3. Traverse dep.subs(Watcher instance), calling update() on each Watcehr
  4. The update() procedure, further optimized to take advantage of queues, executes all Watcher runs after nextTick and finally their callback functions.

What happens if you change the current component’s dependency data 10,000 times in a for loop (nextTick principle)

What if I change the data that the current component depends on 10,000 times in a for loop? (Involves batch update and the nextTick principle) Overall process:

JS runtime mechanism

JS execution is single threaded and is based on event loops. The event cycle can be roughly divided into the following steps:

  1. All synchronization tasks are executed on the main thread, forming an execution Context stack.
  2. In addition to the main thread, there is a “task queue”. Whenever an asynchronous task has a result, an event is placed in the “task queue”.
  3. Once all synchronization tasks in the execution stack are completed, the system reads the task queue to see what events are in it. Those corresponding asynchronous tasks then end the wait state, enter the execution stack, and start executing.
  4. The main thread repeats step 3 above.

The execution of the main thread is a tick, and all asynchronous results are scheduled through the “task queue”. Message queues hold individual tasks. According to the specification, tasks fall into two categories, macro task and Micro Task. After each Macro task is finished, all micro tasks should be cleared.

for (macroTask of macroTaskQueue) {  
  // 1. Handle current MACRO-TASK
  handleMacroTask();  
  // 2. Handle all MICRO-TASK
  for (microTask of microTaskQueue) {    
    handleMicroTask(microTask);  
}}
Copy the code

In the browser environment:

Common Macro tasks include setTimeout, MessageChannel, postMessage, and setImmediate

Common micro Tasks are MutationObsever and Promise.then

Asynchronous update queue

Number is constantly ++, constantly triggering the update method on the Watcher object in its Dep. And then we end up with a queue that filters Watcher objects with the same ID, so there’s actually only one Watcher object in the queue that corresponds to number. On the next tick (when number has changed to 1000), the Watcher object’s run method is triggered to update the view, changing the number from 0 to 1000.

If the same watcher is triggered more than once, it will only be pushed into the queue once. This removal of duplicate data while buffering is important to avoid unnecessary computation and DOM manipulation.

Vue internally attempts to use native Promise.then, MutationObserver, and setImmediate for asynchronous queues, and setTimeout(fn, 0) instead if the execution environment does not support it.

In the Vue2.5 source code, MacroTask degrades through setImmediate, MessageChannel, and setTimeout

The realization principle of VUE’s nextTick method is as follows:

  1. Vue uses an asynchronous queue to control when DOM updates and nextTick callbacks are executed
  2. Due to its high-priority nature, MicroTask ensures that the microtasks in the queue are completed before an event loop
  3. Considering compatibility, Vue made a demotion scheme from microtask to Macrotask

How does Vue respond to arrays

  1. Override all methods in an array that change the array itself, such as push, pop, and so on.
  2. Then manually call notify to render Watcher and perform update

Why does computed property change on its own when it depends on change

Computed and Watch share a Watcher class, and in the case of computed there is a DEPS. Vue uses cleanupDeps to remove old subscriptions each time new subscriptions are added while collecting dependencies twice

Why is Proxy adopted in Vue3.0 and Object. DefineProperty abandoned

  1. Object.defineproperty itself has some ability to detect array subscript changes, but in Vue, this feature is deprecated for performance/experience value reasons.

To solve this problem, rewrite all the methods in the array that can change the array itself, such as push, pop, and so on. Then manually call notify to render Watcher and perform update

push();
pop();
shift();
unshift();
splice();
sort();
reverse();
Copy the code
  1. Object.defineproperty can only hijack attributes of an Object, soWe need to iterate over every property of every object. If the property value is also an object thenYou need deep traversalObviously, ifCan hijack an entire objectYes is the better choice.

A Proxy can hijack an entire object and return a new object. Proxy can Proxy not only objects, but also arrays. You can also proxy dynamically added properties.

What exactly does a key in Vue do

The key is the unique ID given to each vNode, with which our diff operations can be more accurate and faster (diff nodes are also faster for simple list page rendering, but with hidden side effects such as not having transitions, or binding data (form) state on some nodes, There will be state mismatches.

In the process of diFF algorithm, the beginning and end of the new node will be compared with the old node. When there is no match, the key of the new node will be compared with the old node, so as to find the corresponding old node

The sameNode function a. keey === B. Keey can be compared with the sameNode function a. keey === B. Therefore, it will be more accurate. If you do not add key, the state of the previous node will be retained, which will cause a series of bugs.

Faster: The uniqueness of the key can be fully exploited by the Map data structure, and the Map’s time complexity is only O(1) compared to the time complexity of traversal lookup O(n).

Talk about the rendering process of Vue

  1. Call the compile function to generate the render function string as follows:

    • The parse function parses the template to generate an AST (abstract syntax tree)
    • The optimize function optimizes static nodes (flags don’t need to be updated every time,diff skips static nodes, reducing the comparison process and optimizing patch performance)
    • Generate generates the render function string
  2. Call the new Watcher function to listen for changes in the data, and when the data changes, the Render function executes to generate the VNode object

  3. The patch method is called to compare the old and new VNode objects, and the DOM diff algorithm is used to add, modify, and delete real DOM elements.

Describe the implementation principle and cache strategy of Keep-Alive

export default {
  name: "keep-alive".abstract: true.// Abstract component properties, which are ignored when a component instance sets up a parent-child relationship, during initLifecycle
  props: {
    include: patternTypes, // The cached component
    exclude: patternTypes, // The component is not cached
    max: [String.Number] // Specify the cache size
  },

  created() {
    this.cache = Object.create(null); / / cache
    this.keys = []; // The cached VNode key
  },

  destroyed() {
    for (const key in this.cache) {
      // Delete all caches
      pruneCacheEntry(this.cache, key, this.keys); }},mounted() {
    // Listen for cached/uncached components
    this.$watch("include".val= > {
      pruneCache(this.name= > matches(val, name));
    });
    this.$watch("exclude".val= > {
      pruneCache(this.name= >! matches(val, name)); }); },render() {
    // Get the vNode of the first child
    const slot = this.$slots.default;
    const vnode: VNode = getFirstComponentChild(slot);
    constcomponentOptions: ? VNodeComponentOptions = vnode && vnode.componentOptions;if (componentOptions) {
      // Name is not in inlcude or is returned directly to vnode from exlude
      // check pattern
      constname: ? string = getComponentName(componentOptions);const { include, exclude } = this;
      if (
        // not included(include && (! name || ! matches(include, name))) ||// excluded
        (exclude && name && matches(exclude, name))
      ) {
        return vnode;
      }

      const { cache, keys } = this;
      // Get the component's name field first, otherwise the component's tag
      constkey: ? string = vnode.key ==null
          ? // same constructor may get registered as different local components
            // so cid alone is not enough (#3269)
            componentOptions.Ctor.cid +
            (componentOptions.tag ? ` : :${componentOptions.tag}` : "")
          : vnode.key;
      // Hit the cache, take the vNode component instance directly from the cache, and rearrange the key order to the last one
      if (cache[key]) {
        vnode.componentInstance = cache[key].componentInstance;
        // make current key freshest
        remove(keys, key);
        keys.push(key);
      }
      // Set vNode to cache if the cache is not hit
      else {
        cache[key] = vnode;
        keys.push(key);
        // prune oldest entry
        // If Max is configured and the cache length exceeds this. Max, remove the first object from the cache
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode); }}// keepAlive flag bit
      vnode.data.keepAlive = true;
    }
    return vnode || (slot && slot[0]); }};Copy the code

The principle of

  1. Gets the first child component object wrapped around Keep-Alive and its component name

  2. Include /exclude (if any) is matched to determine whether to cache. Does not match and returns the component instance directly

  3. The cache Key is generated based on the component ID and tag, and the cache object is looked up to see if the component instance has been cached. If so, fetch the cached value and update the key’s position in this.keys (updating the key’s position is the key to implement the LRU substitution strategy)

  4. Store the component instance and the key in this.cache, then check if the number of cached instances exceeds the Max value. If so, delete the most recent and oldest unused instance (the key with subscript 0) according to the LRU substitution policy.

  5. Finally, the keepAlive property of the component instance is set to true, which is used in the rendering and execution of the wrapped component’s hook function

Caching strategies

LRU (Least Recently Used) Cache policy: Replace the data that has not been Used for the longest time with new data.

The idea is that “if data has been accessed recently, it has a higher chance of being accessed in the future.

The most common implementation is to use a linked list to store cached data. The detailed algorithm is as follows:

  1. Insert new data into the linked list header;
  2. Whenever a cache hit (that is, cached data is accessed), the data is moved to the head of the linked list;
  3. When the list is full, discard the data at the end of the list.

What was the purpose of Vue2.0’s introduction of the virtual DOM

Vue (Virtual DOM)

  1. Parser can be converted to abstract the original rendering process.
  2. Cross-platform capabilities. Render to a platform other than DOM, to achieve SSR, isomorphic rendering these advanced features.
  3. About the virtual DOM being faster than the real DOM. The advantage of the virtual DOM is in the case of large, frequent DOM changes. But that’s not often the case.

Can you talk about the performance optimization considerations when implementing VUE

Open the process of vue source code, found that there is much worth learning to write optimization process, recorded here:

  1. The cache function uses closures to implement caching

  2. When collecting secondary dependencies, cleanupDeps removes the dependencies that existed last time but don’t exist this time

  3. Traverse, handle deep listening data, remove circular references

  4. The main role of optimize in the compilation optimization phase is to mark up static static nodes

  5. The keep-alive component uses the lRU cache elimination algorithm

  6. Asynchronous components, rendered in two batches

The process of Diff, just a little bit

process

  1. Compare siblings first and then children

  2. First determine whether one party has child nodes or one party has no child nodes. If the new party has child nodes and the old party does not, the new child node replaces the original node. Similarly, if the new party does not have children and the old party does, it is equivalent to deleting the old node.

  3. Now, if we look at the case where we both have children, this is the heart of the DIff. First, it determines whether the two nodes are the same by determining whether the key, tag, isComment, and data of the two nodes are defined or not, and whether the types of the two nodes are different when the tag type is input. If not, the new node will be replaced with the old node.

  4. If the node is the same, the patchVNode stage will be entered. At this stage, the core is to use the double-pointer algorithm and compare the old and new nodes at the same time. In this process, the static mark and key in template compilation will be used to skip the comparison of static nodes. If not, other comparisons will be made.

For example:

// old arr
["a"."b"."c"."d"."e"."f"."g"."h"]
// new arr
["a"."b"."d"."f"."c"."e"."x"."y"."g"."h"]
Copy the code
  1. Compare from beginning to end, [a, B] is sameVnode, enter patch, stop at [c];

  2. Compare from end to end, [h,g] is sameVnode, enter patch, stop at [f];

  3. To judge whether the old data has been compared, the extra information is added and needs to be mounted (not in this case).

  4. To determine whether the new data has been compared, the redundant description is deleted and needs to be unmounted (not in this case).

  5. PatchVNode phase. At this stage, the core is to use the double-pointer algorithm and compare the old and new nodes at the same time. In this process, the static mark and key in template compilation will be used to skip the comparison of static nodes. If not, other comparisons will be made.

Disadvantages: Because the peer comparison is adopted, if the nodes at this level are found to be different, the old nodes will be replaced between the new nodes, without comparing whether the child nodes under them are the same

Compare vue2, VUe3, and React

Vue2, Vue3

Vue3. X draws on ivI algorithm and Inferno algorithm.

It determines the type of VNode when creating it, and uses bit operation to determine the type of a VNode in the process of mount/patch. On this basis, combined with the core Diff algorithm, the performance has been improved compared with Vue2

Vue and react

React uses key set level comparison. Vue uses dual pointer comparison. React uses key set level comparison

Talk about the vue – the router

VueRouter’s implementation of different patterns looks something like this:

  1. First, determine the selected mode based on mode. If the current environment does not support the history mode, the system forcibly switches to the hash mode.

  2. If the current environment is not a browser environment, it will switch to abstract mode. Different history action objects are then generated based on different schemas.

The new process of the Router

  1. The app variable inside the init method is the this of the current Vue instance stored.
  2. Store your app in an array of apps. Use this.app to determine if the instance has already been initialized.
  3. Use history to determine the switching action for different routes.
  4. Response callbacks for route changes are registered with history.listen.

Difference between Hash and history

  1. Most notably, the hash mode URL is displayed with hash signs, while history is not.
  2. They are implemented differently under Vue. Hash mode relies on the onHashchange event (listening for changes to location.hash), and History mode (popState) relies on the two new methods in HTML5 history. PushState () can change urls without sending requests, and replaceState() can read the history stack and modify browser records.
  3. History mode needs to be supported on the back end when you really need to send HTTP requests via urls, such as when you manually enter the URL and press enter, or when you refresh (restart) the browser. Because the history mode, the front end of the URL must and the actual backend sends the request URL, for example, there is a URL with path path (for example, www.lindaidai.wang/blogs/id), if there is no on the path to the back-end processing, it will return a 404 error. So you need to add a candidate resource to the back end that covers all the cases, usually with a 404 page from the front end.

Refer to the article

  • Cn.vuejs.org/v2/guide/re…
  • Ustbhuangyi. Making. IO/vue – analysi…
  • Introduce MVVM

PS: Welcome to exchange and study, please point out any shortcomings.