Vue 3.0 性能晋升次要是通过哪几方面体现的?
- 响应式零碎的降级
Vue 2.0 应用 defineProperty
- defineProperty 代理对象中的某个属性
- 初始化时将 data 中的数据进行解决,如果属性时 object 类型还须要递归解决
Vue 3.0 应用 Proxy 对象重写响应式零碎
- Proxy 代理整个对象
- 调用时递归
- 能够监听动静新增的属性
- 能够监听删除的属性
- 能够监听数组的索引和 length 属性
- 编译优化
- Vue 2.0 中通过标记动态根节点,优化 diff 过程
Vue 3.0 中标记和晋升所有的动态根节点,diff 只须要比照动静节点内容
- Fragments
- 动态晋升
- Patch flag
- 缓存事件处理函数
- 源码体积优化
Vue 3.0 中移除了一些不罕用的 API
- inline-tempalte、filter
- Tree-shaking
Vue 3.0 所采纳的 Composition Api 与 Vue 2.x应用的Options Api 有什么区别?
- Vue 2.0 Options Api
在一个vue
文件中应用data
、methods
、computed
、watch
定义属性和办法,独特解决页面逻辑
问题:当组件开始变得更大时,逻辑关注点的列表也会增长。尤其对于那些一开始没有编写这些组件的人来说,这会导致组件难以浏览和了解。
// src/components/UserRepositories.vueexport default { components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList }, props: { user: { type: String, required: true } }, data () { return { repositories: [], // 1 filters: { ... }, // 3 searchQuery: '' // 2 } }, computed: { filteredRepositories () { ... }, // 3 repositoriesMatchingSearchQuery () { ... }, // 2 }, watch: { user: 'getUserRepositories' // 1 }, methods: { getUserRepositories () { // 应用 `this.user` 获取用户仓库 }, // 1 updateFilters () { ... }, // 3 }, mounted () { this.getUserRepositories() // 1 }}
- Vue 3.0 Composition Api
在 Composition API 中,代码是依据逻辑性能来组织的,一个性能的所有 API 会放在一起(高内聚,低耦合)
// src/components/UserRepositories.vueimport { toRefs } from 'vue'import useUserRepositories from '@/composables/useUserRepositories'import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'import useRepositoryFilters from '@/composables/useRepositoryFilters'export default { components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList }, props: { user: { type: String, required: true } }, setup(props) { const { user } = toRefs(props) const { repositories, getUserRepositories } = useUserRepositories(user) const { searchQuery, repositoriesMatchingSearchQuery } = useRepositoryNameSearch(repositories) const { filters, updateFilters, filteredRepositories } = useRepositoryFilters(repositoriesMatchingSearchQuery) return { // 因为咱们并不关怀未经过滤的仓库 // 咱们能够在 `repositories` 名称下裸露过滤后的后果 repositories: filteredRepositories, getUserRepositories, searchQuery, filters, updateFilters } }}
Proxy 绝对于 Object.defineProperty 有哪些长处?
- defineProperty 代理对象中的某个属性,Proxy 代理整个对象
- defineProperty 无奈监控到数组下标的变动, Proxy 能够
Vue 3.0 在编译方面有哪些优化?
- Vue 2.0 中通过标记动态根节点,优化 diff 过程
Vue 3.0 中标记和晋升所有的动态根节点,diff 只须要比照动静节点内容
- Fragments
- 动态晋升
- Patch flag
- 缓存事件处理函数
Proxy 和 Reflect 中的 receiver 指向问题?
Proxy 中的 receiver 指向 proxy 实例
const proxy = new Proxy({}, { get: function(target, key, receiver) { return receiver; }});proxy.getReceiver === proxy // true
Reflect 中的 receiver
- 如果属性部署了读取函数(getter),则读取函数的 this 绑定 receiver。
var myObject = { foo: 1, bar: 2, get baz() { return this.foo + this.bar; },};var myReceiverObject = { foo: 4, bar: 4,};Reflect.get(myObject, 'baz', myReceiverObject) // 8
- Reflect.set 一旦传 receiver,就会将属性赋值到 receiver 下面(即obj),导致触发 defineProperty 拦挡
let p = { a: "a", }; let handler = { set(target, key, value, receiver) { console.log("set"); Reflect.set(target, key, value, receiver); }, defineProperty(target, key, attribute) { console.log("defineProperty"); Reflect.defineProperty(target, key, attribute); }, }; let obj = new Proxy(p, handler); obj.a = "A"; // set // defineProperty
Vue.js 3.0 响应式零碎的实现原理?
Vue 3.0 的响应式零碎是独立的模块,能够齐全脱离 Vue 而应用,而贯通整个响应式零碎得无非是 reactive、effect 办法
reactive:通过 Proxy 设置 get、set、deleteProperty 代理,返回对象的响应式正本。
- get:收集依赖,递归将代理对象转成响应式对象
- set:更新值并触发更新
- deleteProperty:删除并触发更新
- effect:立刻执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时从新运行该函数
依赖收集-track
当 effect 被立刻执行时,触发代理对象的 getter 办法,get 办法外部会调用 track 办法将属性与对应的 effect 函数建设依赖关系
let activeEffect = nullfunction effect(callback) { activeEffect = callback callback() activeEffect = null}let targetMap = new WeakMap()function track(target, key) { if(!activeEffect) return let depsMap = targetMap.get(target) if (!depsMap) targetMap.set(target, (depsMap = new Map())) let dep = depsMap.get(key) if (!dep) depsMap.set(key, (dep = new Set())) dep.add(activeEffect)}
触发更新-trigger
更新/删除属性时触发代理对象的 setter 办法,set 外部调用 trigger 办法进行更新操作。
trigger 会去依赖记录中查找对应字段依赖的 effect 并顺次执行
function trigger(target, key) { let depsMap = targetMap.get(target) if (!depsMap) return const dep = depsMap.get(key) if (dep) { dep.forEach(effect => { effect() }) }}