持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情
vue的响应式过程
vue在初始化的时候,在beforeCreated和created之间按顺序进行初始化响应式数据,包括props,methods,data,computed,watch,在初始化data的过程中会调用observer方法来绑定数据劫持判断是否已经有了ob属性并且ob属性是observer对象实例有了就直接返回,不然就new一个observer实例。
在new实例的时候会先定义一个不可枚举的ob属性用来标识,然后判断是否为数组,数组的话则进行遍历数组的内容调用observer方法,对象则遍历每一个属性调用defineReactive方法将属性变成响应式属性,在渲染的时候触发数据绑定的getter方法,判断当前是否存在watcher,存在则添加订阅的watcher,在添加watcher则会先判断是否已经存在watcher然后再添加进dep。
在当前渲染watcher结束时,会判断是否之前保存的watcher是否还在本轮的订阅数组中,如果不在则将其移出,以节约性能,避免修改一个当前不需要渲染的数据时也触发了渲染,在修改数据的时候触发绑定setter方法,在做一些判断值是否相同之后,如果新值为一个对象的话,则调用observer方法进行数据绑定,然后调用dep.notify方法通知watcher。
notify方法里面会遍历之前收集的watcher,然后调用queueWatcher方法将他们添加进执行队列当中,会先判断当前watcher是否已经在队列中,如果在队列中则跳过,如果不在则添加进队列中,然后通过nextTick调用flushSchedulerQueue方法,在flushSchedulerQueue方法中会将队列中的watcher进行排序,以让id小的先执行,方便实现几个目的:
1.以让父组件先于子组件渲染。
2.userwatcher先于renderwatcher执行因为父组件和userwathcer先创建。
3.如果父组件渲染执行中销毁了子组件,则可以跳过该子组件的渲染。
然后调用run方法,触发getter方法计算值,如果是userwatcher则调用回调函数,如果是渲染watcher则会将当前渲染watcher添加进栈,然后再触发watcher的getter回调函数,也就是传入updateComponent进行更新视图,然后将当前watcher移除出栈,并清理订阅(因为在本次渲染中又会触发数据的getter函数重新进行订阅)
watch和comouted
computed和watch的区别,computed是监听多个属性,watch则是监听一个属性,watch是立即执行,computed则是触发getter的时候才执行,