Vue source analysis [5] – VUE life cycle

The following code and analysis process need to be viewed in conjunction with vue.js source code, by comparing the break points one by one.

1.beforeCreate

Let’s take a look at the execution process

  • New Vue is executed firstinitMixin(Vue); “, but only a _init is mounted to the Vue and _init is not executed.
  • Next, executenew VueHTML or main.js will eventually have this entry after importing Vue filesfunction Vue(options)
  • To performthis._init(options);And into theinitMixinIn theVue.prototype._init = function (options).
  • performcallHook(vm, 'beforeCreate');, triggers the beforeCreate hook function

callHook:

    // Triggers the lifecycle hook function
    function callHook(
        vm,  / / the Vue instance
        hook // Key of the hook function
    ) {
        // #7573 disable dep collection when invoking lifecycle hooks
        // DeP collection is disabled when lifecycle hooks are called
        //Dep.target = _target; / / store
        pushTarget();
        // Get the declared periodic function added to the VM
        $option = $option;
        var handlers = vm.$options[hook];
        if (handlers) {  / / array
            for (var i = 0, j = handlers.length; i < j; i++) {
                try {
                    // Execute the lifecycle function
                    /** * For example, in the component's beforeCreate hook, we write the following code: Handlers [I]. Call (VM) executes the code for the beforeCreate hook function. And the this pointer is passed to the VM, which is Vue
                    debugger
                    handlers[i].call(vm);
                } catch (e) {
                    handleError(e, vm, (hook + " hook")); }}}/** * if you want to call lifecycle hooks: * <el-select ref="select"@hook:mounted="callback"></el-select>
         */
        if (vm._hasHookEvent) {
            vm.$emit('hook:' + hook);
        }
        // push a pushTarget
        popTarget();
    }
Copy the code

1 pushTarget: _target is empty because no parameter is passed. Add the target of the Dep to the targetStack and update the target of the Dep to the current Watcher object

    // Dep is the data dependency corresponding to subscriber Watcher
    var Dep = function Dep() {
        //uid is initialized to 0, and each Dep has a unique ID
        this.id = uid++;
        /* subs is used to store Watcher's dependencies */
        this.subs = [];
    };
    Dep.target = null; // Initialize to NULL, and finally update with pushTarget
    // Target stack
    var targetStack = [];

    function pushTarget(_target) {
        if (Dep.target) { / / target is a Watcher; Static symbol
            targetStack.push(Dep.target);// Centrally manage dep.target
        }
        Dep.target = _target;// Update to the current passed target
    }
Copy the code

popTarget

    function popTarget() {
        // push a pushTarget
        // pop() removes and returns the last element of the array.
        Dep.target = targetStack.pop();
    }
Copy the code

$option = 2 vm.$option = 2 vm.$option = 2 Moving forward, you can see that initMixin(Vue) has this code:

vm.$options = mergeOptions(
           // Parse the options attribute on constructor
              resolveConstructorOptions(vm.constructor), 
              // The options are passed by function Vue(options), i.e. new Vue(), where,
              // We will define the related lifecycle and related methods and properties on the component ourselves
              options || {},
              vm
);
Copy the code

[Figure 1. Execute beforeCreate to print this]

2. created

After executing beforeCreate, create is executed.

Execute at initMixin:

callHook(vm, 'created'); // Trigger the created hook functionCopy the code

3. beforeMount

In mountComponent(){} do:

callHook(vm, 'beforeMount');
Copy the code

It is executed in this order:

  • New Vue is executed firstinitMixin(Vue); “, but only a _init is mounted to the Vue and _init is not executed.
  • Next, executenew VueHTML or main.js will eventually have this entry after importing Vue filesfunction Vue(options)
  • To performthis._init(options);And into theinitMixinIn theVue.prototype._init = function (options).
  • performcallHook(vm, 'beforeCreate');, triggers the beforeCreate hook function
  • performcallHook(vm, 'created');Trigger the created hook function
  • Performs the last stepvm.$mount(vm.$options.el);Execute the mount at the end,Vue.prototype.$mount = function()Generate the render rendering function and the actual DOM
  • At the end of the function, returnsmount.call( this, el, hydrating)The mount function in the middle of the file,Vue.prototype.$mount = function()
  • Then performmountComponent( this, el, hydrating), mount components, render pages.
  • At this point, we can see the actual DOM.

4. mounted

In mountComponent(){} do:

        if (vm.$vnode == null) {
            vm._isMounted = true;
            // Execute the life cycle function Mounted
            / / render the data
            callHook(vm, 'mounted');
        }
Copy the code

Source to ask questions

1. In which lifecycle do AJAX requests go?

When created, the DOM in the view is not rendered, so the DOM node is directly manipulated and relevant elements cannot be found. In Mounted, the DOM has been rendered and DOM nodes can be directly manipulated. In general, they are placed in mounted to ensure logical uniformity. Since server-side rendering does not have DOM and does not support Mounted methods, it is created in the case of server-side rendering.

2. When do I need to use beforeDestroy?

  • It is possible that the $on method is used on the current component and needs to be unbound before the component is destroyed
  • Clear self-defined timers
  • Unbind the event’s native scroll, mousemove…

3. Lifecycle call sequence of vUE parent and child components