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.vue
export 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.vue
import {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 = null
function 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()
})
}
}