年关将近,业务较忙,基本都是凌晨1-2点下班,早上10点半就上班了,一直没有多余的时间学习,今天周日就抽空来回顾一下 11月24号在杭州 举办vueConf大会的视频,然后总结一下vuejs作者 尤雨溪对vue3.0最新进展的介绍。
作者一开始就提到了vue3.0的新特性:
- 更快
- 更小
- 更易于维护
- 更好的多端渲染支持
- 新功能
下面就依次举具体例子介绍:
模板编译和virtual DOM runtime 性能方面的优化
1、思想:编译时的优化来减少运行时的开销;如runtime时diff的静态内容直接在编译时就确定好,这样每次在virtual DOM diff时就直接跳过这一段静态内容
我们知道vue的性能主要是消耗在virtual DOM diff这块,作者也明确指出这一块的优化还有很多空间, 所以3.0版本的virtual DOM是完全重构的,在更多的细节方面下功夫以致于初始渲染/更新提速达100%
// 如下面的模板
<template>
<comp></comp>
<div>
<span></span>
</div>
</template>
// 编译成渲染函数
render() {
const Comp = resolveComponent('Comp', this)
return crateFragment([
createComponetVNode(Comp, null, null, 0 /* no children */),
createElementVNode('div', null, [
createElementVNode('span', null, null, 0 /* no children */)
], 2 /* single vnode child */)
], 8 /* mutiple non-keyed children */)
}
上面的代码说明了经过渲染函数生成的代码里面可以做一些优化
- 模板里面有组件,也有原生HTML标签,我们可以在编译时直接做判断,如果它是组件就生成对应的virtual DOM 代码, 如果它是原生HTML标签就直接生成对应的virtual DOM代码,这样就不用每次在运行时去做判断,这就是所谓的component fast path。
- 同时在生成的virtual DOM里面的函数调用要尽可能的形状一致,就是说生成的函数参数个数要一致,这样就可以让js引擎去优化,这是比较底层的优化方法。
- 同样在代码里面还可以生成一些hint(提示),直接生成一个数字告诉它这个div里面有几个节点,这样就省去了很多运行时成本。
优化slots的生成
<Comp>
<div>{{hello}}</div>
</Comp>
模板编译后:
render(){
return h(Comp, null, {
default: () => [h('div', this.hello)]
}, 6 /* compiler generated slots */)
}
同样看上面的代码,vue2.x版本的slot每次hello更新都要先更新父组件,然后父组件生成新的slot,这就是关联更新,也就是说为了更新一个hello就触发了两个组件更新。新的solts生成机制里面,所有的slot跟scope slot一样统一生成一个函数,这个函数等于可以说是一个lazy的函数,当你把函数传给子组件的时候,由子组件来决定什么时候调用者函数,当子组件来调用这个函数的时候,就是说这个函数是子组件的依赖而不是父组件的依赖了,当hello变动时,子组件调用这个函数,这样只有子组件重新渲染,这样的话就把父组件和子组件的依赖彻底分开了,这样在整个应用中就可以得到一个组件级别的依赖收集,可以进一步避免不必要的重新渲染,不用你像react那样去操心去手动优化过度重绘这个问题。
静态内容提取
<div class='static'>
<span>static</span>
</div>
在模板中有许多这种不会变的静态内容,可以在编译时直接缓存起来,每次virtual DOM更新时直接忽略这部分内容,也省去了diff的时间
内联事件函数提取
// 2.x的写法会造成子组件不必要的重渲
<comp @click='count++'></comp>
// 3.0的改进点
<comp @clcik='count++'></comp>
import { getBoundMethod } from 'vue'
function __fn1() {
this.count++
}
render(){
return h(comp, {
onEvent: getBoundMethod(__fn1, this)
})
}
上面的代码在每次渲染函数执行时都会生成一个新的内敛函数,而导致子组件的不必要更新,所以,目前在用vuejs2.x版本在写代码时尽量绑定具体函数名而不是用内敛的写法。那么3.0的改进点就是把这些内敛函数抽出来在内部维护;所以在3.0你可以放心用内敛写法而不用担心造成不需要的子组件重渲。
基于Proxy的新数据监听系统,全语言特性支持 + 更好的性能
- 对象属性的增加 / 删除
- 数组 index / length 更改
- Map, Set, WeakMap, WeakSet
- classes
我们知道2.x的数据监听系统是基于Object.defineproperty()这个方法来进行get 、set拦截处理的,新的数据监听系统将会用Proxy来做。因为Proxy自带lazy特性,不会一开始就把所有定义在data函数中的数据进行绑定监听,它会‘按需’来实现数据监听,当你有大量数据在初始化时,性能会有一个大大的提升,作者实测提升将近一倍。全语言特性支持是指支持数组的index、length的更改也能进行监听从而进行响应式数据绑定,在2.x的版本中,我们在data中定义一个数组list,在模板中去v-for遍历渲染,当我们在操作时去更改list[index]的内容是不会被监听到的,更改list.length也不会被监听到,我们需要通过另外的方法,如Vue.$set(list,index,value)。至于 Map, Set, WeakMap, WeakSet,这些数据类型在2.0中也没有支持,同样在写vue组件时我们一般用export default {} ,以对象的形式去写的,3.0会支持class的写法,像react的组件就是class写法。
所有的这些性能优化加起来就达到了一个效果:速度提升一倍,内存占用减半!
更小
vue的runtime将会变得更小,现在2.x也不大,gzip后20+kb。但是呢,它还可以变得更小!怎么做?没错就是:tree-shaking。3.0的代码组织结构更加便于tree-shaking,让我们没有用到的代码在最后编译的时候把它扔掉。如一些内置组件transition,component,一些指令v-model, v-for, 还有一些内置工具函数 asyncCompenet等,这些都可以做成按需引入!作者介绍在所有这些不相干的代码去掉之后,gzip之后只有10kb+!!!
更易于维护
这点其实说针对vue开发团队而言的,同样对于想要看vue源码的同学也是友好的。首先vue3.0的代码从flow迁移到typescript上了,用typescript完全重写了。我感觉未来用typescript写库或者框架是一种趋势的感觉。所以typescript学起来啊,老铁们。当然这对于用户代码没有任何影响,你以前用es6写vue,也可以继续用,只不过对typescript写vue项目的同学更加友好了。代码重构提现在以下几点:
- 内部模块解耦
- 编译器重构,插件化设计
更好的多端渲染支持
目前国内的小程序一大堆,这确实给开发者带来很大的不必要学习成本,微信搞一个,支付宝搞一个,然后你百度又来一个快应用啥的。vue3.0将会提供一个custom render API: createRender。 createRender函数更好的支持开发者去用vue语法去写支持多端的代码,让你learn once, write more!
其他
- 更好的错误堆栈信息提示
- vue hooks 大概率取代mixins
- time slicing support,把js代码切成一块块去执行,避免大规模计算导致浏览器长时间处于block状态。这是一个非常好的优化,类似于节流的概念,每一帧只做16-17ms的事情。
- ie支持,会有一个专门的版本自动降级为用Object.defineproperty()的get 、set拦截处理的数据,并对一些新的ie不支持的用法做出警告。
网友评论