【大前端1-拉钩教育作业】关于 vue 源码的简答题

## 简答题

 

##### 1、请简述 Vue 首次渲染的过程

 

  • - 在首次渲染之前,首先进行Vue初始化,初始化实例成员和静态成员
  • - 当初始化结束之后,要调用 Vue 的构造函数 new Vue(),在构造函数中调用了 _init() 方法,这个方法相当于我们整个 Vue 的入口
  • - 在_init方法中,最终调用了 $mount ,一共有两个 $mount,第一个定义在entry-runtime-with-compiler.js文件中,也就是我们的入口文件$mount,这个 $mount() 的核心作用是帮我们把模板编译成 render 函数,但它首先会判断一下当前是否传入了 render 选项,如果没有传入的话,它会去获取我们的 template 选项,如果 template 选项也没有的话,他会把 el 中的内容作为我们的模板,然后把模板编译成render函数,它是通过 compileToFunctions() 函数,帮我们把模板编译成 render 函数的,当把 render 函数编译好之后,它会把 render 函数存在我们的 options.render 中。
  • - 接着会调用 src/platforms/web/runtime/index.js 文件中的 $mount 方法,在这个中首先会重新获取 el ,因为如果是运行时版本的话,是不会走entry-runtime-with-compiler.js这个入口中获取 el ,所以如果是运行时版本的话,我们会在runtime/index.js的 $mount() 中重新获取el。
  • - 接下来调用 mountComponent() ,这个方法在src/core/instance/lifecycle.js中定义的,在 mountComponent() 中,首先会判断render选项,如果没有render选项,但是我们传入了模板,并且当前是开发环境的话会发送一个警告,目的是如果我们当前使用运行时版本的Vue,而且我们没有传入 render ,但是传入了模版,告诉我们运行时版本不支持编译器。接下来会触发 beforeMount 这个生命周期中的钩子函数,也就是开始挂载之前。
  • - 然后定义了 updateComponent(),在这个函数中,调用 vm._render 和 vm._update ,vm._render 的作用是生成虚拟DOM,vm._update 的作用是将虚拟DOM转换成真实DOM,并且挂载到页面上
  • - 创建Watcher对象,在创建Watcher时,传递了updateComponent这个函数,这个函数最终是在Watcher内部调用的。在 Watcher 内部会用了get方法,当 Watcher 创建完成之后,会触发生命周期中的 mounted 钩子函数,在 get 方法中,会调用 updateComponent()

 

##### 2、请简述 Vue 响应式原理

 

  • - Vue的响应式是从Vue的实例init()方法中开始的,在init()方法中先调用initState()初始化Vue实例的状态,在initState方法中调用了initData(), initData()是把data属性注入到Vue实例上,并且调用observe(data)将data对象转化成响应式的对象。
  • - observe是响应式的入口, 在observe(value)中,首先判断传入的参数value是否是对象,如果不是对象直接返回。再判断value对象是否有__ob__这个属性,如果有说明做过了响应式处理,则直接返回,如果没有,创建observer对象,并且返回observer`对象。
  • - 在创建observer对象时,给当前的value对象定义不可枚举的__ob__属性,记录当前的observer对象,然后再进行数组的响应式处理和对象的响应式处理,数组的响应式处理就是拦截数组的几个特殊的方法,push、pop、shift等,然后找到数组对象中的__ob__对象中的dep,调用dep的notify()方法,再遍历数组中每一个成员,对每个成员调用observer(),如果这个成员是对象的话,也会转换成响应式对象。对象的响应式处理,就是调用walk方法,walk方法就是遍历对象的每一个属性,对每个属性调用defineReactive方法
  • - defineReactive会为每一个属性创建对应的dep对象,让dep去收集依赖,如果当前属性的值是对象,会调用observe。defineReactive中最核心的方法是getter 和 setter。getter 的作用是收集依赖,收集依赖时, 为每一个属性收集依赖,如果这个属性的值是对象,那也要为子对象收集依赖,最后返回属性的值。在setter 中,先保存新值,如果新值是对象,也要调用 observe ,把新设置的对象也转换成响应式的对象,然后派发更新(发送通知),调用dep.notify()
  • - 收集依赖时,在watcher对象的get方法中调用pushTarget,记录Dep.target属性,访问data中的成员的时候收集依赖,defineReactive的getter中收集依赖,把属性对应的 watcher 对象添加到dep的subs数组中,给childOb收集依赖,目的是子对象添加和删除成员时发送通知。
  • - 在数据发生变化的时候,会调用dep.notify()发送通知,dep.notify()会调用watcher对象的update()方法,update()中的调用的queueWatcher()会去判断watcher是否被处理,如果这个watcher对象没有的话添加到queue队列中,并调用flushScheduleQueue(),flushScheduleQueue()触发beforeUpdate钩子函数调用watcher.run():run()-->get() --> getter() --> updateComponent()
  • - 然后清空上一次的依赖
  • - 触发actived的钩子函数
  • - 触发updated钩子函数

 

##### 3、请简述虚拟 DOM 中 Key 的作用和好处

作用

  • - 在 v-for 的过程中,为每一个节点设置 key ,以便它能够跟踪每个节点的身份,在进行比较的时候,会基于 key 的变化重新排列元素顺序,从而重用和重新排序现有元素,并且会移除 key 不存在的元素,方便让 vnode 在 Diff 的过程中找到对应的几点,然后成功复用。

 

好处

  • - 可以减少 DOM 的操作,根据索引,进行删除、添加等操作时更加快捷,减少 Diff 的渲染所需要的时间,提升了性能

 

##### 4、请简述 Vue 中模板编译的过程

 

  • - 在entry-runtime-with-compiler的$mount中,会对vue实例传入的参数进行处理。如果不存在render且template存在就会对其进行模板编译处理将其转换为render(返回vNode的函数)
  • - 这里面render函数是由compileToFunctions函数返回的,这个函数最终是由src\platforms\web\compiler\to-function.js中的createCompileToFunctionFn函数执行返回的,在这个函数中我们通过compile函数获得编译对象{render,staticRenderFns},字符串形式的js代码,最后将其转换为返回vNode的函数js方法返回(就是render函数)
  • - 在compile中会合并选项,调用baseCompile进行编译,返回编译好的对象
  • - baseCompile
    •   - parse:将模板转换为ast抽象语法树,以树形结构描述代码结构
    •   - optimize:优化语法树,标记模板的静态内容(静态节点及静态根节点),在patch时可以跳过静态根节点
    •   - generate:将语法树生成字符串形式的js代码
  • - baseCompile执行完会返回一个对象里面包含ast语法树,字符串形式的渲染函数render、静态渲染函数(staticRenderFns),回到上一级compile函数中它会被作为返回值返回,createCompileToFunctionFn返回一个compileToFunctions函数,在这个中会对返回值进行处理将render,staticRenderFns转化为js方法并返回,这两个方法就是我们在$mount中通过compileToFunctions函数解构赋值的
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值