Preface
Interview questions:
vue
middlecreated
、watch(immediate: true)
andcomputed
What is the execution order?
Let’s take a look at a simple example:
// import Vue from "vue"; new Vue({ el: "#app", template: `<div> <div>{{computedCount}}</div> </div>`, data() { return { count: 1, } }, watch: { count: { handler() { ('watch'); }, immediate: true, } }, computed: { computedCount() { ('computed'); return + 1; } }, created() { ('created'); }, });
The execution order of the current example is:watch
--> created
--> computed
。
Why?
existnew Vue
During the instantiation process, the initialization method will be executedthis._init
, which has the code:
._init = function (options) { // ... initState(vm); // ... callHook(vm, 'created'); // ... if (vm.$) { vm.$mount(vm.$); } } function initState (vm) { vm._watchers = []; var opts = vm.$options; if () { initProps(vm, ); } if () { initMethods(vm, ); } if () { initData(vm); } else { observe(vm._data = {}, true /* asRootData */); } if () { initComputed(vm, ); } if ( && !== nativeWatch) { initWatch(vm, ); } }
I looked at the code and found out that I had executed it firstinitComputed(vm, )
, and then executeinitWatch(vm, )
, execute againcallHook(vm, 'created')
, then why notcomputed
--> watch
--> created
Woolen cloth?
Don't worry, listen to my story.
1. About initComputed
const computedWatcherOptions = { lazy: true } function initComputed (vm: Component, computed: Object) { // $flow-disable-line const watchers = vm._computedWatchers = (null) // computed properties are just getters during SSR const isSSR = isServerRendering() for (const key in computed) { const userDef = computed[key] const getter = typeof userDef === 'function' ? userDef : // ... if (!isSSR) { // create internal watcher for the computed property. watchers[key] = new Watcher( vm, getter || noop, noop, computedWatcherOptions ) } // component-defined computed properties are already defined on the // component prototype. We only need to define computed properties defined // at instantiation here. if (!(key in vm)) { defineComputed(vm, key, userDef) } else if (.NODE_ENV !== 'production') { // ... } } }
ByinitComputed
When initializing the computed attribute, the current component is processed through traversal.computed
. First, when instantiating the computed attribute,{ lazy: true }
Passed in as parameters and instantiatedWatcher
In-housegetter
It's in the current examplecomputedCount
function; secondly, bydefineComputed(vm, key, userDef)
The way to the current component instancevm
The above iskey
conductuserDef
handling. Specifically:
export function defineComputed ( target: any, key: string, userDef: Object | Function ) { const shouldCache = !isServerRendering() if (typeof userDef === 'function') { = shouldCache ? createComputedGetter(key) : createGetterInvoker(userDef) = noop } // ... (target, key, sharedPropertyDefinition) } function createComputedGetter (key) { return function computedGetter () { const watcher = this._computedWatchers && this._computedWatchers[key] if (watcher) { if () { () } if () { () } return } } }
From the above, it can be seen that here(target, key, sharedPropertyDefinition)
The way to change the functioncomputedGetter
Asget
Function, only whenkey
The internal logic will be triggered when access is made. Internal logic()
for:
evaluate () { = () = false }
get
There are main logic in it:
value = (vm, vm)
HereThat's in the current example:
computedCount() { ('computed'); return + 1; }
That is, only when obtainingcomputedCount
It will trigger whencomputed
The calculation is to performvm.$mount(vm.$)
The stage will be executed('computed')
。
2. About initWatch
function initWatch (vm: Component, watch: Object) { for (const key in watch) { const handler = watch[key] if ((handler)) { for (let i = 0; i < ; i++) { createWatcher(vm, key, handler[i]) } } else { createWatcher(vm, key, handler) } } } function createWatcher ( vm: Component, expOrFn: string | Function, handler: any, options?: Object ) { if (isPlainObject(handler)) { options = handler handler = } if (typeof handler === 'string') { handler = vm[handler] } return vm.$watch(expOrFn, handler, options) }
ByinitWatch
When initializing the listener, ifwatch
is an array, then traversal executioncreateWatcher
, otherwise it will be executed directlycreateWatcher
. ifhandler
When it is an object or a string, it is processed and finally passed into it as a parameter.vm.$watch
In the middle, specifically:
.$watch = function ( expOrFn: string | Function, cb: any, options?: Object ): Function { const vm: Component = this if (isPlainObject(cb)) { return createWatcher(vm, expOrFn, cb, options) } options = options || {} = true const watcher = new Watcher(vm, expOrFn, cb, options) if () { try { (vm, ) } catch (error) { handleError(error, vm, `callback for immediate watcher "${}"`) } } return function unwatchFn () { () } }
Get it hereoptions
There will beimmediate: true
key value, and pass = true
set upuser
fortrue
, then pass it as a parameter to performWatcher
Instantiation of .
In the current examplefor
true
, so it will be executed(vm, )
, that is,vm
As the main body, execute immediatelycb
. In the current examplecb
that ishandler
:
handler() { ('watch'); },
Here is the explanation of the current example('watch')
It is the first to execute.
Then, the execution is completedinitComputed
andinitWatch
Afterwards, it will passcallHook(vm, 'created')
Execute to life cycle('created')
Now.
Last passedvm.$mount(vm.$)
When rendering the page, you will create it firstvNode
, you need to obtaincomputedCount
the value ofget
The subsequent logic of the function is finally executed('computed')
。
P.S. Why does the watch in vue execute after mounted
First, when calling mounted, it will enter the defineReactive function, then call the set method in the function, pass the new value assigned in mounted, and send the message to the subscriber by calling ( ), and then update the subscriber's list.
Only then will the watch be rendered and the class that enters the Watcher
Summarize
about
vue
middlecreated
andwatch
The execution order is relatively simple, andcomputed
It is throughFor the current
vm
Define it and then create it latervNode
The execution of the stage is triggeredget
Function, finally executed to calculate attributescomputed
Corresponding logic.
This is the article about the detailed explanation of the execution order of created, watch and computed in vue. This is the end. For more related contents of vue created, watch and computed execution order, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!