# fed-e-task-03-02 **Repository Path**: lv_jing0359/fed-e-task-03-02 ## Basic Information - **Project Name**: fed-e-task-03-02 - **Description**: 拉勾大前端作业:Part3 - 模块二 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-12-06 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 一、简答题 ### 1、请简述 Vue 首次渲染的过程。 - Vue 初始化,初始化实例成员和静态成员 - 调用 Vue 的构造函数 new Vue() - Vue 的构造函数 中调用了 this._init() - _init 方法中调用了 $mount:vm.$mount - 入口文件 src/platforms/web/entry-runtime-with-compiler.js 中调用 $mount,把模板编译成 render 函数 - 通过 compileToFunctions() 生成 render 渲染函数 - 将 render 函数编译完成后,将 render 函数存到 options,render 中:options.render = render - vm.$mount() - 调用 src/platforms/web/runtime/index 中的 $mount 方法,重新获取 el - mountComponent(this,el) - 在 src/core/instance/lifecycle.js 中定义 - 判断当前是否有 render 选项,如果没有但是传入了模板,开发环境下会发送警告 - 触发 beforeMount 这个生命周期中的钩子函数 - 定义了 updateComponent 函数,这个函数中调用了 render 和 update 方法,生成虚拟 DOM,并把虚拟 DOM 转化为真实 DOM,并且挂载到页面上来 - 创建 Watcher 实例,传入了 updateComponent 函数,调用 get() 方法 - 触发 mounted 这个生命周期中的钩子函数,挂载结束 - 返回 vue 实例:return vm - watcher.get() - 创建完 watch 会调用一次 get - 调用 updateComponent() 方法 - updateComponent() 中调用 render 和 update 这两个方法 ### 2、请简述 Vue 响应式原理。 - initState() --> initData()--> observe() - initState() 初始化 Vue 实例的状态 - initData() 把 data 属性注入到 Vue 实例上 - observe() 把 data 对象转化成响应式对象 - observe(value) - scr/core/observer/index.js - 接收一个 value 参数,这个 value 就是需要响应式处理的对象 - 判断 value 是否为对象,如果不是对象直接返回 - 判断 value 对象是否有 __ob__,如果有直接返回,如果没有,创建 observer 对象 - 返回 observer 对象 - Observer - src/core/observer/index.js - 给 value 对象定义不可枚举的 _ *ob_* 属性,记录当前的 observer 对象 - 进行数组的响应化处理和对象的响应化处理 - defineReactive - src/core/observer/index.js - 为每一个属性创建 dep 对象 - 如果当前属性的值为对象,调用 observe - 定义 getter - 收集依赖,为每一个属性及子属性收集依赖 - 返回属性的值 - 定义 setter - 保存新值 - 如果新值是对象,调用 observe - 派发更新,调用 dep.notify() - 依赖收集 - 执行 watcher 对象的 get() 方法,在 get 方法中调用 pushTarget 记录 Dep.target 属性 - 访问 data 中的成员的时候收集依赖,defineReactive 的 getter 中收集依赖 - 把属性对应的 watcher 对象添加到 dep 的 subs 数组中 - 给 childOb 收集依赖,目的是子对象添加和删除成员时发送通知 - Watcher - 数据发生变化时,调用 dep.notify() 发送通知,调用 watcher 的 update 方法 - watcher 的 update 方法中会调用 queueWatcher() 判断 watcher 是否被处理,如果没有,添加到 queue 队列中,并调用 flushSchedulerQueue(),刷新任务队列 - flushSchedulerQueue() - 触发 beforeYpdate 钩子函数 - 调用 watcher.run(): run() --> get() --> getter --> updateComponent - 清空上一次的依赖 - 触发 actived 钩子函数 - 触发 updated 钩子函数 ### 3、请简述虚拟 DOM 中 Key 的作用和好处。 答:在 updateChildren 中比较子节点的时候,没有设置 key 时,会做三次更新 DOM 操作和一次插入 DOM 的操作,而设置了 key 以后,因为 oldVnode 的子节点的 b,c,d 和 newVnode 的 x,b,c 的 key 相同,所以只做比较,没有更新 DOM 的操作,当遍历完毕后,会再把 x 插入到 DOM 上DOM 操 作只有一次插入操作。 ### 4、请简述 Vue 中模板编译的过程。 - compileToFunctions(template, ...) - 首先从缓存中加载编译好的 render 函数 - 若缓存中没有,调用 compile(template, options) 开始编译 - compile(template, options) - 合并 options - 调用 baseCompile(template.trim(), finalOptions) - baseCompile(template.trim(), finalOptions) - parse():把 template 转换成 AST tree - optimize() - 标记 AST tree 中的静态 sub trees - 检测到静态子树,设置为静态,不需要在每次重新渲染的时候重新生成节点 - patch 阶段跳过静态子树 - generate():AST tree 生成 js 的创建代码 - compileToFunctions(template, ...) - 继续把上一步中生成的字符串形式的 js 代码转换为函数 - createFunction() - render 和 staticRenderFns 初始化完毕,挂载到 Vue 实例的 options 对应的属性中