vue加载过程(初始化-->编译加载-->收集依赖-->渲染dom)

161 阅读2分钟

1.初始化过程:

参考文章:blog.csdn.net/weixin_4329…

image.png

首先会创建vue实例new Vue();调用初始化方法_init();生成唯一标识_uid;合并传入的选项options;初始化代理initProxy,判断如果支持proxy (hasProxy) 就用proxy,不支持就用 defineProperty();然后确定父子组件关系,并初始化组件实例相关属性($parent,$children,$root,$refs,_watcher等);初始化父组件传递过来的自定义事件;初始化render方法;后面会执行beforecreate生命周期钩子函数;初始化inject让组件可以访问到父组件传递的依赖;初始化data,递归遍历每一个属性,添加代理并创建dep实例,使其变为响应式数据;初始化props、methods、computed、props并挂载到this上;执行created生命周期;然后执行$mount开始编译挂载

image.png 2.编译加载过程:

watcher、dep、observe解读参考文章:
响应式源码分析:zhuanlan.zhihu.com/p/575403904
Dep,Observer和Watcher:www.jianshu.com/p/eb7fa2dab…
依赖收集的时机:zhuanlan.zhihu.com/p/392285475

总体流程图: image.png 依赖收集:

image.png 渲染Watcher派发更新流程: image.png 1.先确定挂载的目标元素,且必须保证该元素不能为 html,body 这类跟节点,判断选项中是否有 render 这个属性(默认我们使用的是 runtime-only**只包含运行时版**(对应js文件vue.runtime.js),单文件组件SFC会通过vue-loader、vue-template-compiler在打包阶段将.vue文件解析生成组件选项对象,template内容会解析成render函数)的版本,有render属性会跳过模板编译阶段,调用挂载函数$mount,直接进入挂载过程。当传入template模板选项时(即在不使用外置编译器:vue-loader的情况下,使用 runtime+compile完整版本时,runtime-only版本不支持template属性写法),会先进入解析编译阶段,首先将模板使用正则匹配的方法解析生成ast(抽象语法树),然后根据ast生成render函数,然后再调用$mount方法,进入挂载阶段。

单文件组件SFC会通过**vue-loader、vue-template-compiler**在打包阶段将.vue文件解析生成组件选项对象,template内容会解析成render函数 image.png

2.$mount实际会执行mountComponent方法,先调用beforeMount生命周期钩子,然后定义updateComponent方法,然后生成一个watcher实例,watcher接受一个回调函数,传入上面定义的updateComponent方法,(会在初始化和数据更新时执行,回调函数里会执行vm._update(vm._render(), hydrating)方法,通过patch方法将render函数生成的虚拟dom转换成真实dom)

image.png 3.在watcher构造函数中,会将传入的updateComponent赋值给this.getter,然后执行this.get方法(依赖收集就是发生在这个get方法中),get方法中,会调用pushTarget设置Dep.target = this(当前实例),然后调用this.getter(即updateComponent),执行vm._update(vm._render(), hydrating)方法

image.png image.png 4.先调用_render()方法生成虚拟dom,在这个过程中会调用_c(createElement)、_v(createTextVNode)、_s(toString)方法去访问绑定的变量,触发绑定变量的getter函数
5.getter中会去判断Dep.target是否存在,上面pushTarget已经设置过,这时候会执行depend,触发Watcher实例的addDep,在addDep方法中会首先判断newDepIds中是否存在该dep实例的id是否存在,不存在将dep.id存入newDepId数组中,并将这个Watcher实例添加到dep的subs数组中,至此依赖收集完成。

Watcher类addDep方法: image.png

Dep类addSub、depend方法: image.png

6.然后通过patch方法将render函数生成的虚拟dom转换成真实dom,触发mounted生命钩子

image.png