vue

173 阅读3分钟

环境准备及打包调试

依赖安装

git clone https://github.com/vuejs/vue
安装依赖 npm i
安装rollup npm i -g rollup
修改dev脚本添加sourceMap
"dev": "rollup -w -c scripts/config.js --sourcemap"

dist/vue.runtime.common/esm.js

runtime: 仅包含运行时,包含vue运行核心代码,没有模板编译器
umd:用于浏览器script标签,默认包含运行时和编译器
commonJs:cjs规范适用于旧版打包
esm:ES Model规范用语现代打包器

initMixin(Vue)

initLifecycle(vm)

组件实例里面常用属性初始化,parent/parent/root/children/children/refs的初始化

initEvents(vm)

更新组件传递的需要处理的事件

initRender(VM)

slots/scopeSlots插槽初始化/slots/scopeSlots插槽初始化/createElement函数声明,attrs,attrs,listeners响应化处理

callHook(vm, 'beforeCreate')

initInjection(vm)

inject数据响应化处理

initState(vm)

执行数据状体初始化

stateMixin() 状态混入

定义data,data,props两个实例属性和setset、delete、$watch三个实例方法

eventsMixin()

实现事件相关实例api:on,on,emit,off,off,once

lifecycleMixin()

实现组件生命周期相关的三个核心实例api:_update,forceUpdate,forceUpdate,destory _update是组件更新周期中的关键方法,组件出发更新该函数会调用,它执行vnode的diff和patch等操作

renderMixin()

实现$nextTick,_render()

数据响应式

vue一大特点是数据响应式,数据的变化会作用于UI而不是DOM,原理上讲是利用了js语言特性Object.defineProperty()通过定义对象属性set方法拦截对象属性变更,从而将数值的变化转换为UI的变化

Observe

返回一个Observer实例,根据数据类型执行对应的数据响应化操作

Dep

管理一组watcher,包括watcher实例的增删及通知更新

watcher

watcher解析一个表达式并收集依赖,当数值变化时触发回调函数,每个组件会有对应的watcher,数值变化会触发其update函数导致重新渲染

watcher:组件生成/创建watch/renderwatcher,mountComponent跟组件会明确的创建一次watcher

Vue中数据响应化

  • defineReactive中的getter和setter对应订阅和发布行为
  • Dep的角色相当于主题Subject,维护订阅者,通知观察者更新
  • watcher的角色相当于Observe,执行更新
  • 但Vue里面的Observe不是上面所说的观察,它和data中对象一一对应,有内嵌的对象就会有childObserver与之对应

数组响应化

数组数据变化的侦测跟对象不同,我们操作数组通常使用push、pop、splice等方法,此时没有办法得知数据变化,所以vue中采取的策略是拦截这些方法通知dep、

拦截器 为数组原型中的7个可以改变内容的方法定义拦截器

Vue异步更新队列

Vue在更新DOM时是异步执行的,只要侦听到数据变化,vue讲开启一个队列,并缓冲在同一事件循环中发生的所有数据变更,如果同一个watcher呗触发多次,只会被推入到队列中一次,这种缓冲时去重对于避免不必要的计算和DOM操作是非常主要的。在下一个事件循环tick中,vue刷新队列并执行实际工作。vue在内部对异步队列尝试使用原生的promise、mutationObserver和setinmmediate,如果执行环节不支持,则会采用settimeout(fn,0)代替

queueWatcher 执行watcher入队操作,若存在重复id则跳过

// 刷新队列
if(!waiting){
	waiting = true
	nextTick(flushSchedulerQueue)
}

nextTick(flushSchedulerQueue) nextTick按照特定异步策略执行队列刷新操作

Observe、Dep、Watcher

调用mountComponent时会实例化一个renderWatcher。initData对数据做响应化时,利用defineProperty 的get拦截器Dep进行收集,一个watcher对应着N个Observer实例,因此数据更新时相当于n个watcher都会更新。如果同一个watcher呗触发多次,只会被推入到队列中一次