preface
Wathcer, as we know in Vue, is a listener that listens for changes in response to data, when you want to do something expensive when the data changes, such as an asynchronous request. This is when you use a listener.
First let’s take a look at the initializing watch source code!
function Vue(){
/ / initializes the attributes, data, computed, props, watch and so on
initState(this)}function initState(vm) {
/ /...
if (opts.watch) {
initWatch(this, vm.$options.watch); }}function initWatch(vm, watch) {
// Walk through the watch, adding subscribers to each watch is user-watcher
for (var key in watch) {
varwatchOpt = watch[key]; createWatcher(vm, key, handler); }}function createWatcher(vm, expOrFn, handler, options) {
// The hander is not the same as the watch
if (isPlainObject(handler)) {
options = handler;
handler = handler.handler;
}
if (typeof handler === 'string') {
handler = vm[handler];
}
//expOrFn is a key, handler is a listener callback for that key, which will be discussed many times
return vm.$watch(expOrFn, handler, options)
}
Copy the code
Watch is first traversed, followed by adding a user-watcher to each listening attribute, in which the exported parameter expOrFn is key,handler is the listening callback of this key, the value of handler may have several cases, listing our possible watch forms.
watch:{
name: {handler(){},},name(){},
name:"getNameWatch"
}
Copy the code
If it is an object, it assigns the handler of that object to handler. If it is a function, it assigns the handler directly, and the string assigns the vm.getNameWatch to handler.
Ok, now let’s see what happens to $Watcher.
Vue.prototype.$watch = function (expOrFn, cb, options) {
//
var watcher = new Watcher(vm, expOrFn, cb, options);
// Execute the listener wather immediately
if(options.immediate) { cb.call(vm, watcher.value); }};Copy the code
Let’s quickly move on to new Watcher(), which is the user-watcher added to each of the listener properties, and look at the source code for Watcher. I’ll list the important source code for this knowledge so I don’t have to bother with the other code.
var Watcher = function (vm, key, cb, opt) {
this.vm = vm;
this.deep = opt.deep;
this.cb = cb;
// Set the listener callback for this key
this.getter = parsePath(expOrFn);
};
// this.get executes this.getter().
this.value = this.get();
};
Copy the code
function parsePath(path) {
var segments = path.split('. ');
return function (obj) {
for (var i = 0; i < segments.length; i++) {
if(! obj) {return
}
obj = obj[segments[i]];
}
return obj
}
}
Copy the code
ParsePath basically returns an anonymous function that gets the value of the listening key from the VM, so dependency collection occurs. Look at the subsequent execution, after which the value is assigned to this.getter, after which this.get() is executed to this.getter(), which will collect the dependency on the listening property. Having said that, it’s a little bit more of a process.
We already know that parsePath returns a listening callback for this listening property. Next, execute the this.get() method.
Watcher.prototype.get = function get() {
// Set the current user-watcher to dep.target
pushTarget(this);
// Pass the VM in, perform the listening callback, and then trigger its dependency collection user-watcher if there is a dependent response in the callback.
value = this.getter.call(vm, vm);
var vm = this.vm;
if (this.deep) {
traverse(value);
popTarget();
}
return value
};
Copy the code
value = this.getter.call(vm, vm); Target is user-watcher and will be collected in the subs array.
$watch = new Watcher(); $watch = new Watcher(); Check whether immediate is true. The handler callback for the key is executed immediately. And initWatch is done.
Updates are then sent and executed when the response data changesupdate
The user-Watcher listening callback will be executed la la la!
Thank you for reading, hope there is a wrong place to give advice, exchange, progress together.