前言
今天下午在阅读Vue3,Component相关源码时,发现了这么一段注释。(源码地址 91行:packages/runtime-core/src/componentProxy.ts)
This getter gets called for every property access on the render context during render and is a major hotspot. The most expensive part of this is the multiple hasOwn() calls. It’s much faster to do a simple property access on a plain object, so we use an accessCache object (with null prototype) to memoize what access type a key corresponds to.
大致意思是如下:
在渲染期间,对渲染上下文进行访问时,hasOwn()
操作很昂贵。而在普通对象上进行属性访问的操作,速度会快很多。所以在Vue3中使用accessCache对象,对对象进行缓存。
实验
那么Object.prototype.hasOwnProperty
操作是有多昂贵,值得尤大进行优化。我使用下面的代码,进行了实验。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const obj = {
name: 'Natalie portman'
}
const accessCache = { ...obj }
const hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (val, key) => hasOwnProperty.call(val, key)
let start = new Date().getTime()
for (let i = 0; i < 5000000; i++) {
hasOwn(obj, 'name')
}
console.log(`duration: ${new Date().getTime() - start}`)
start = new Date().getTime()
for (let i = 0; i < 5000000; i++) {
accessCache.name
}
console.log(`duration: ${new Date().getTime() - start}`)
// duration: 35
// duration: 4
在进行500万次,读取属性操作时,两者的性能相差了大约9倍。
当Vue的组件树很大时,挂载的属性很多时。使用accessCache
对象,对Object.prototype.hasOwnProperty操作进行缓存,应该还是很有必要的。
1 | function Test(){ |
原因
查询了相关资料,大致原因如下:
Chrome的V8引擎,会维护一个全局的缓存。一旦高速缓存被填充,它总是会在随后被重复命中。这意味着val[key]
属性查找,将始终在编译时处理,而不会进行运行时。
而V8引擎不会对,hasOwnProperty
或者key in value
进行任何缓存,总是进入运行时。