前端进阶之路 - part3 - 【Vue】

305 阅读4分钟

Vue首次渲染过程

首先进行Vue的初始化,也就是初始化Vue的实例成员以及静态成员。

当初始化结束之后,开始调用构造函数,在构造函数中调用this._init(),这个方法相当于我们整个Vue的入口。

在_init()中最终调用了this.mount(),共有两个mount(),共有两个mount(),第一个mount()entryruntimewithcompiler.js入口文件的mount()是entry-runtime-with-compiler.js入口文件的mount(),这个$mount()的核心作用是帮我们把模板编译成render函数,但它首先会判断一下我们当前是否传入了render选项,如果没有传入的话,它会去获取我们的template选项,如果template选项也没有的话,他会把el中的内容作为我们的模板,然后把模板编译成render函数,它是通过compileToFunctions()函数,帮我们把模板编译成render函数的,当把render函数编译好之后,它会把render函数存在我们的options.render中。

那接下来会调用runtime/index.js中的mount()方法,这个方法中,首先会重新获取我们的el,因为如果是运行时版本的话,是不会entryruntimewithcompiler.js这个入口中获取el,所以如果是运行时版本的话,我们会在runtime/index.jsmount()方法,这个方法中,首先会重新获取我们的el,因为如果是运行时版本的话,是不会entry-runtime-with-compiler.js这个入口中获取el,所以如果是运行时版本的话,我们会在runtime/index.js的mount()中重新获取el。

接下来调用mountComponent(),mountComponent()是在src/core/instance/lifecycle.js中定义的,在mountComponent()中,首先会判断render选项,如果没有但是传入了模板,并且当前是开发环境的话会发送警告,警告运行时版本不支持编译器。

接下来会触发beforeMount这个生命周期中的钩子函数,也就是开始挂载之前。

然后定义了updateComponent(),在这个方法中,定义了_render和_update,_render的作用是生成虚拟DOM,_update的作用是将虚拟DOM转换成真实DOM,并且挂载到页面上来。

再接下来就是创建Watcher对象,在创建Watcher时,传递了updateComponent这个函数,这个函数最终是在Watcher内部调用的。在Watcher创建完之后还调用了get方法,在get方法中,会调用updateComponent()。

然后触发了生命周期的钩子函数mounted,挂载结束,最终返回Vue实例。

响应式处理过程

initState() --> initData() --> observe()

observe(value)

位置:src/core/observer/index.js 功能: 判断value是否是对象,如果不是对象直接返回 判断value对象是否有__ob__,如果有直接返回 如果没有,创建observer对象 返回observer对象

Observer

位置:src/core/observer/index.js 功能: 给value对象定义不可枚举的__ob__属性,记录当前的observer对象 数组的响应式处理 对象的响应式处理,调用walk方法

defineReactIve

位置:src/core/observer/index.js 功能: 为每一个属性创建dep对象 如果当前属性的值是对象,调用observe 定义getter 收集依赖 返回属性的值 定义setter 保存新值 如果新值是对象,调用observe 派发更新(发送通知),调用dep.notify()

收集依赖

在watcher对象的get方法中调用pushTarget记录Dep.target属性 访问data中的成员的时候收集依赖,defineReactive的getter中收集依赖 把属性对应的watcher对象添加到dep的subs数组中 给childOb收集依赖,目的是子对象添加和删除成员时发送通知

Watcher

dep.notify()在调用watcher对象的update()方法 queueWatcher()判断watcher是否被处理,如果没有的话添加到queue队列中,并调用flushScheduleQueue() flushScheduleQueue() 触发beforeUpdate钩子函数 调用watcher.run(): run() --> get() --> getter() --> updateComponent 清空上一次的依赖 触发actived的钩子函数 触发updated钩子函数

虚拟dom的作用

避免直接操作DOM,提高开发效率 作为一个中间层可以跨平台 虚拟DOM不一定可以提高性能 首次渲染的时候会增加开销 复杂视图情况下提升渲染性能

什么是虚拟dom

虚拟DOM就是使用JavaScript对象描述真实DOM Vue中的虚拟DOM借鉴Snabbdom,并添加了Vue的特性,例如指令和组件机制

虚拟 DOM 中 Key 的作用和好处

  1. 以便它能够跟踪每个节点的身份,在进行比较的时候,会基于 key 的变化重新排列元素顺序。从而重用和重新排序现有元素,并且会移除 key 不存在的元素。方便让 vnode 在 diff 的过程中找到对应的节点,然后成功复用.
  2. 可以减少 dom 的操作,减少 diff 和渲染所需要的时间,提升了性能。

Vue 中模板编译的过程

  1. 模板编译的主要目的是将模板(template)转换为渲染函数(render)
  2. 编译的入口函数:调用 compileToFunctions( template, {}, this) , 返回 { render,staticRenderFns },作用:把 template 转换成 render 函数

createCompiler( baseOptions ):

a:定义 compile(template,option)函数

b:生成 compileToFunctions

c:返回 { compile,compileToFunctions }

createCompilerCreator(function baseCompile(){}):

a:传入了 baseCompile( template,options ) 函数

b:baseCompile:核心函数:解析 parse;优化 optimize;生成 generate;

c:返回 createCompiler 函数