Home > Web Front-end > Vue.js > Detailed explanation of data initialization (initState) in vue

Detailed explanation of data initialization (initState) in vue

青灯夜游
Release: 2020-10-30 17:57:37
forward
4612 people have browsed it

The following Vue.js tutorial column will take you to understand the data initialization (initState) in vue. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.

Detailed explanation of data initialization (initState) in vue

Data initialization

The Vue instance will run a series of initialization operations when it is created. Among these initialization operations, the one most closely associated with data binding is initState.

First of all, let’s take a look at his code:

function initState(vm) {
    vm._watchers = [];
    var opts = vm.$options;
    if(opts.props) {
        initProps(vm, opts.props); //初始化props
    }
    if(opts.methods) {
        initMethods(vm, opts.methods); //初始化methods
    }
    if(opts.data) {
        initData(vm); //初始化data
    } else {
        observe(vm._data = {}, true /* asRootData */ );
    }
    if(opts.computed) {
        initComputed(vm, opts.computed); //初始化computed
    }
    if(opts.watch && opts.watch !== nativeWatch) {
        initWatch(vm, opts.watch); //初始化watch
    }
}
Copy after login

In the initialization of so much data, props, methods and data are relatively simple (so I won’t introduce them in detail☺) , while computed and watch are relatively difficult and have complicated logic, so I will mainly talk about computed and watch below (the following code part is simplified).

InitState mainly initializes the props, methods, data, computed and watch data in the vue instance.

When initializing props (initProps), each attribute in props will be traversed, and then type verification, data monitoring, etc. will be performed (a hook function that will throw a warning when assigning a value to props attributes) is provided.

When initializing methods (initMethods), it is mainly to monitor whether the method names in methods are legal.

When initializing data (initData), the observe function will be run to deeply traverse each attribute in the data to perform data hijacking.

When initializing computed (initComputed), it will monitor whether the data already exists in data or props. If it exists, a warning will be thrown. Otherwise, the defineComputed function will be called, monitor the data, and bind getters and properties to the properties in the component. setter. If the value of an attribute in computed is a function, it defaults to the attribute's getter function. In addition, the value of the attribute can also be an object. It has only three valid fields: set, get and cache, which respectively indicate the attribute's setter, getter and whether to enable caching. Get is required and cache defaults to true.

function initComputed(vm, computed) {
    var watchers = vm._computedWatchers = Object.create(null);

    for(var key in computed) {
        var userDef = computed[key];
        var getter = typeof userDef === 'function' ? userDef : userDef.get;

        //创建一个计算属性 watcher
        watchers[key] = new Watcher(
            vm,
            getter || noop,
            noop,
            computedWatcherOptions
        );

        if(!(key in vm)) {
            //如果定义的计算属性不在组件实例上,对属性进行数据劫持
            //defineComputed 很重要,下面我们再说
            defineComputed(vm, key, userDef);
        } else {
            //如果定义的计算属性在data和props有,抛出警告
        }
    }
}
Copy after login

When initializing watch (initWatch), the vm.$watch function will be called to bind setter callbacks to the properties in the watch (if there is no such property in the component, it cannot be successfully monitored. The property must exist in props, data or computed). If the value of the attribute in the watch is a function, the default is the setter callback function of the attribute. If the value of the attribute is an array, the contents of the array are traversed and callbacks are bound to the attributes respectively. In addition, the value of the attribute can also be an object. , at this time, the handler field in the object represents the setter callback function, immediate represents whether to execute the handler method inside immediately, and deep represents whether to monitor deeply.

vm.$watch function will directly use Watcher to construct the observer object. The value of the attribute in watch exists as watcher.cb, and is executed in the watcher.run function when the observer updates. If you want to understand this process, you can read my introduction to Watcher in the vue responsive system-observe, watcher, and dep in my previous article.

function initWatch(vm, watch) {
    //遍历watch,为每一个属性创建侦听器
    for(var key in watch) {
        var handler = watch[key];
        //如果属性值是一个数组,则遍历数组,为属性创建多个侦听器
        //createWatcher函数中封装了vm.$watch,会在vm.$watch中创建侦听器
        if(Array.isArray(handler)) {
            for(var i = 0; i < handler.length; i++) {
                createWatcher(vm, key, handler[i]);
            }
        } else {
            //为属性创建侦听器
            createWatcher(vm, key, handler);
        }
    }
}

function createWatcher(vm, expOrFn, handler, options) {
    //如果属性值是一个对象,则取对象的handler属性作为回调
    if(isPlainObject(handler)) {
        options = handler;
        handler = handler.handler;
    }
    //如果属性值是一个字符串,则从组件实例上寻找
    if(typeof handler === &#39;string&#39;) {
        handler = vm[handler];
    }
    //为属性创建侦听器
    return vm.$watch(expOrFn, handler, options)
}
Copy after login

computed

computed is essentially a lazy-evaluated observer with cacheability. Only when dependencies change, the first time The new value will be calculated only after accessing the computed attribute

The following will be explained around this sentence.

As mentioned in the above code, when the data in the calculated attribute exists in data and props, you will be warned, which means that this approach is wrong. So generally, we will declare data directly in calculated properties. In the same code snippet, if the defined computed property is not on the component instance, the defineComputed function will be run to perform data hijacking on the data. Let's take a look at what is done in the defineComputed function.

function defineComputed(target, key, userDef) {
//是不是服务端渲染
var shouldCache = !isServerRendering();
//如果我们把计算属性的值写成一个函数,这时函数默认为计算属性的get
if(typeof userDef === &#39;function&#39;) {
sharedPropertyDefinition.get = shouldCache ?
//如果不是服务端渲染,则默认使用缓存,设置get为createComputedGetter创建的缓存函数
createComputedGetter(key) :
//否则不使用缓存,直接设置get为userDef这个我们定义的函数
userDef;
//设置set为空函数
sharedPropertyDefinition.set = noop;
} else {
//如果我们把计算属性的值写成一个对象,对象中可能包含set、get和cache三个字段
sharedPropertyDefinition.get = userDef.get ?
shouldCache && userDef.cache !== false ?
//如果我们传入了get字段,且不是服务端渲染,且cache不为false,
//设置get为createComputedGetter创建的缓存函数
createComputedGetter(key) : 
//如果我们传入了get字段,但是是服务端渲染或者cache设为了false,设置get为userDef这个我们定义的函数
userDef.get :
//如果没有传入get字段,设置get为空函数
noop;
//设置set为我们传入的传入set字段或空函数
sharedPropertyDefinition.set = userDef.set ?
userDef.set :
noop;
}
//虽然这里可以get、set都可以设置为空函数
//但是在项目中,get为空函数对数据取值会报错,set为空函数对数据赋值会报错
//而computed主要作用就是计算取值的,所以get字段是必须的

//数据劫持
Object.defineProperty(target, key, sharedPropertyDefinition);
}
Copy after login

In the previous article vue responsive system--observe, watcher, dep, I mentioned in the introduction about Watcher that when the calculated attribute watcher is instantiated, it will Set options.lazy to true. This is the key to lazy evaluation of calculated properties and being cacheable. Of course, the premise is that cache is not false.

If the cache is not false, the createComputedGetter function will be called to create the getter function computedGetter of the calculated attribute.

Let’s look at a piece of code first

function createComputedGetter(key) {
    return function computedGetter() {
        var watcher = this._computedWatchers && this._computedWatchers[key];
        if(watcher) {
            if(watcher.dirty) {
            //watcher.evaluate中更新watcher的值,并把watcher.dirty设置为false
            //这样等下次依赖更新的时候才会把watcher.dirty设置为true,
            //然后进行取值的时候才会再次运行这个函数
                watcher.evaluate();
            }
            //依赖追踪
            if(Dep.target) {
                watcher.depend();
            }
            //返回watcher的值
            return watcher.value
        }
    }
}

//对于计算属性,当取值计算属性时,发现计算属性的watcher的dirty是true
//说明数据不是最新的了,需要重新计算,这里就是重新计算计算属性的值。
Watcher.prototype.evaluate = function evaluate() {
    this.value = this.get();
    this.dirty = false;
};

//当一个依赖改变的时候,通知它update
Watcher.prototype.update = function update() {
    //三种watcher,只有计算属性 watcher的lazy设置了true,表示启用惰性求值
    if(this.lazy) {
        this.dirty = true;
    } else if(this.sync) {
        //标记为同步计算的直接运行run,三大类型暂无,所以基本会走下面的queueWatcher
        this.run();
    } else {
        //将watcher推入观察者队列中,下一个tick时调用。
        //也就是数据变化不是立即就去更新的,而是异步批量去更新的
        queueWatcher(this);
    }
};
Copy after login

When options.lazy is set to true ( Only the options.lazy of the calculated attribute watcher is set to true). Every time a dependency is updated, the run function will not be actively triggered, but watcher.dirty will be set to true. In this way, when the calculated property is evaluated, the computedGetter function will be run. The computedGetter function has a judgment about watcher.dirty. When watcher.dirty is true, watcher.evaluate will be run to update the value and watcher. dirty is set to false, thus completing the lazy evaluation process. As long as the dependency is not updated later, update will not be run and watcher.dirty will not be set to true. Then watcher.evaluate will not be run to update the value when the value is obtained again, thereby achieving the cache effect.

In summary, we understand that when the cache is not false, the computed properties are lazy evaluated and cacheable, and the cache defaults to true, and we mostly use this default value, so we say computed Essentially, it is a lazy-evaluating observer with cacheability. Only when the dependency changes and the computed attribute is accessed for the first time, the new value will be calculated .

Related recommendations:

2020 front-end vue interview questions summary (with answers)

vue tutorial Recommendation: The latest 5 vue.js video tutorial selections in 2020

For more programming-related knowledge, please visit: Programming Teaching! !

The above is the detailed content of Detailed explanation of data initialization (initState) in vue. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
vue
source:segmentfault.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template