年關(guān)將近竿滨,業(yè)務(wù)較忙于游,基本都是凌晨1-2點(diǎn)下班,早上10點(diǎn)半就上班了倾剿,一直沒(méi)有多余的時(shí)間學(xué)習(xí)蚌成,今天周日就抽空來(lái)回顧一下 11月24號(hào)在杭州 舉辦vueConf大會(huì)的視頻凛捏,然后總結(jié)一下vuejs作者 尤雨溪對(duì)vue3.0最新進(jìn)展的介紹坯癣。
作者一開(kāi)始就提到了vue3.0的新特性:
- 更快
- 更小
- 更易于維護(hù)
- 更好的多端渲染支持
- 新功能
下面就依次舉具體例子介紹:
模板編譯和virtual DOM runtime 性能方面的優(yōu)化
1最欠、思想:編譯時(shí)的優(yōu)化來(lái)減少運(yùn)行時(shí)的開(kāi)銷(xiāo)窒所;如runtime時(shí)diff的靜態(tài)內(nèi)容直接在編譯時(shí)就確定好吵取,這樣每次在virtual DOM diff時(shí)就直接跳過(guò)這一段靜態(tài)內(nèi)容
我們知道vue的性能主要是消耗在virtual DOM diff這塊皮官,作者也明確指出這一塊的優(yōu)化還有很多空間, 所以3.0版本的virtual DOM是完全重構(gòu)的捺氢,在更多的細(xì)節(jié)方面下功夫以致于初始渲染/更新提速達(dá)100%
// 如下面的模板
<template>
<comp></comp>
<div>
<span></span>
</div>
</template>
// 編譯成渲染函數(shù)
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 */)
}
上面的代碼說(shuō)明了經(jīng)過(guò)渲染函數(shù)生成的代碼里面可以做一些優(yōu)化
- 模板里面有組件悠反,也有原生HTML標(biāo)簽斋否,我們可以在編譯時(shí)直接做判斷茵臭,如果它是組件就生成對(duì)應(yīng)的virtual DOM 代碼, 如果它是原生HTML標(biāo)簽就直接生成對(duì)應(yīng)的virtual DOM代碼舅世,這樣就不用每次在運(yùn)行時(shí)去做判斷旦委,這就是所謂的component fast path雏亚。
- 同時(shí)在生成的virtual DOM里面的函數(shù)調(diào)用要盡可能的形狀一致缨硝,就是說(shuō)生成的函數(shù)參數(shù)個(gè)數(shù)要一致评凝,這樣就可以讓js引擎去優(yōu)化追葡,這是比較底層的優(yōu)化方法。
- 同樣在代碼里面還可以生成一些hint(提示),直接生成一個(gè)數(shù)字告訴它這個(gè)div里面有幾個(gè)節(jié)點(diǎn)宜肉,這樣就省去了很多運(yùn)行時(shí)成本匀钧。
優(yōu)化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,這就是關(guān)聯(lián)更新,也就是說(shuō)為了更新一個(gè)hello就觸發(fā)了兩個(gè)組件更新酿炸。新的solts生成機(jī)制里面,所有的slot跟scope slot一樣統(tǒng)一生成一個(gè)函數(shù)扁眯,這個(gè)函數(shù)等于可以說(shuō)是一個(gè)lazy的函數(shù),當(dāng)你把函數(shù)傳給子組件的時(shí)候,由子組件來(lái)決定什么時(shí)候調(diào)用者函數(shù)绣版,當(dāng)子組件來(lái)調(diào)用這個(gè)函數(shù)的時(shí)候胶台,就是說(shuō)這個(gè)函數(shù)是子組件的依賴而不是父組件的依賴了,當(dāng)hello變動(dòng)時(shí),子組件調(diào)用這個(gè)函數(shù)杂抽,這樣只有子組件重新渲染概作,這樣的話就把父組件和子組件的依賴徹底分開(kāi)了,這樣在整個(gè)應(yīng)用中就可以得到一個(gè)組件級(jí)別的依賴收集默怨,可以進(jìn)一步避免不必要的重新渲染,不用你像react那樣去操心去手動(dòng)優(yōu)化過(guò)度重繪這個(gè)問(wèn)題骤素。
靜態(tài)內(nèi)容提取
<div class='static'>
<span>static</span>
</div>
在模板中有許多這種不會(huì)變的靜態(tài)內(nèi)容匙睹,可以在編譯時(shí)直接緩存起來(lái),每次virtual DOM更新時(shí)直接忽略這部分內(nèi)容济竹,也省去了diff的時(shí)間
內(nèi)聯(lián)事件函數(shù)提取
// 2.x的寫(xiě)法會(huì)造成子組件不必要的重渲
<comp @click='count++'></comp>
// 3.0的改進(jìn)點(diǎn)
<comp @clcik='count++'></comp>
import { getBoundMethod } from 'vue'
function __fn1() {
this.count++
}
render(){
return h(comp, {
onEvent: getBoundMethod(__fn1, this)
})
}
上面的代碼在每次渲染函數(shù)執(zhí)行時(shí)都會(huì)生成一個(gè)新的內(nèi)斂函數(shù)痕檬,而導(dǎo)致子組件的不必要更新,所以送浊,目前在用vuejs2.x版本在寫(xiě)代碼時(shí)盡量綁定具體函數(shù)名而不是用內(nèi)斂的寫(xiě)法梦谜。那么3.0的改進(jìn)點(diǎn)就是把這些內(nèi)斂函數(shù)抽出來(lái)在內(nèi)部維護(hù);所以在3.0你可以放心用內(nèi)斂寫(xiě)法而不用擔(dān)心造成不需要的子組件重渲。
基于Proxy的新數(shù)據(jù)監(jiān)聽(tīng)系統(tǒng)唁桩,全語(yǔ)言特性支持 + 更好的性能
- 對(duì)象屬性的增加 / 刪除
- 數(shù)組 index / length 更改
- Map, Set, WeakMap, WeakSet
- classes
我們知道2.x的數(shù)據(jù)監(jiān)聽(tīng)系統(tǒng)是基于Object.defineproperty()這個(gè)方法來(lái)進(jìn)行g(shù)et 闭树、set攔截處理的,新的數(shù)據(jù)監(jiān)聽(tīng)系統(tǒng)將會(huì)用Proxy來(lái)做荒澡。因?yàn)镻roxy自帶lazy特性报辱,不會(huì)一開(kāi)始就把所有定義在data函數(shù)中的數(shù)據(jù)進(jìn)行綁定監(jiān)聽(tīng),它會(huì)‘按需’來(lái)實(shí)現(xiàn)數(shù)據(jù)監(jiān)聽(tīng)单山,當(dāng)你有大量數(shù)據(jù)在初始化時(shí)碍现,性能會(huì)有一個(gè)大大的提升,作者實(shí)測(cè)提升將近一倍米奸。全語(yǔ)言特性支持是指支持?jǐn)?shù)組的index昼接、length的更改也能進(jìn)行監(jiān)聽(tīng)從而進(jìn)行響應(yīng)式數(shù)據(jù)綁定,在2.x的版本中悴晰,我們?cè)赿ata中定義一個(gè)數(shù)組list慢睡,在模板中去v-for遍歷渲染,當(dāng)我們?cè)诓僮鲿r(shí)去更改list[index]的內(nèi)容是不會(huì)被監(jiān)聽(tīng)到的膨疏,更改list.length也不會(huì)被監(jiān)聽(tīng)到一睁,我們需要通過(guò)另外的方法,如Vue.$set(list,index,value)佃却。至于 Map, Set, WeakMap, WeakSet者吁,這些數(shù)據(jù)類(lèi)型在2.0中也沒(méi)有支持,同樣在寫(xiě)vue組件時(shí)我們一般用export default {} 饲帅,以對(duì)象的形式去寫(xiě)的复凳,3.0會(huì)支持class的寫(xiě)法,像react的組件就是class寫(xiě)法灶泵。
所有的這些性能優(yōu)化加起來(lái)就達(dá)到了一個(gè)效果:速度提升一倍育八,內(nèi)存占用減半!
更小
vue的runtime將會(huì)變得更小赦邻,現(xiàn)在2.x也不大髓棋,gzip后20+kb。但是呢惶洲,它還可以變得更邪瓷!怎么做恬吕?沒(méi)錯(cuò)就是:tree-shaking签则。3.0的代碼組織結(jié)構(gòu)更加便于tree-shaking,讓我們沒(méi)有用到的代碼在最后編譯的時(shí)候把它扔掉铐料。如一些內(nèi)置組件transition渐裂,component豺旬,一些指令v-model, v-for, 還有一些內(nèi)置工具函數(shù) asyncCompenet等,這些都可以做成按需引入柒凉!作者介紹在所有這些不相干的代碼去掉之后族阅,gzip之后只有10kb+!!!
更易于維護(hù)
這點(diǎn)其實(shí)說(shuō)針對(duì)vue開(kāi)發(fā)團(tuán)隊(duì)而言的,同樣對(duì)于想要看vue源碼的同學(xué)也是友好的扛拨。首先vue3.0的代碼從flow遷移到typescript上了耘分,用typescript完全重寫(xiě)了。我感覺(jué)未來(lái)用typescript寫(xiě)庫(kù)或者框架是一種趨勢(shì)的感覺(jué)绑警。所以typescript學(xué)起來(lái)啊求泰,老鐵們。當(dāng)然這對(duì)于用戶代碼沒(méi)有任何影響计盒,你以前用es6寫(xiě)vue渴频,也可以繼續(xù)用,只不過(guò)對(duì)typescript寫(xiě)vue項(xiàng)目的同學(xué)更加友好了北启。代碼重構(gòu)提現(xiàn)在以下幾點(diǎn):
- 內(nèi)部模塊解耦
- 編譯器重構(gòu)卜朗,插件化設(shè)計(jì)
更好的多端渲染支持
目前國(guó)內(nèi)的小程序一大堆,這確實(shí)給開(kāi)發(fā)者帶來(lái)很大的不必要學(xué)習(xí)成本咕村,微信搞一個(gè)场钉,支付寶搞一個(gè),然后你百度又來(lái)一個(gè)快應(yīng)用啥的懈涛。vue3.0將會(huì)提供一個(gè)custom render API: createRender逛万。 createRender函數(shù)更好的支持開(kāi)發(fā)者去用vue語(yǔ)法去寫(xiě)支持多端的代碼,讓你learn once, write more批钠!
其他
- 更好的錯(cuò)誤堆棧信息提示
- vue hooks 大概率取代mixins
- time slicing support,把js代碼切成一塊塊去執(zhí)行宇植,避免大規(guī)模計(jì)算導(dǎo)致瀏覽器長(zhǎng)時(shí)間處于block狀態(tài)。這是一個(gè)非常好的優(yōu)化埋心,類(lèi)似于節(jié)流的概念指郁,每一幀只做16-17ms的事情。
- ie支持拷呆,會(huì)有一個(gè)專(zhuān)門(mén)的版本自動(dòng)降級(jí)為用Object.defineproperty()的get 闲坎、set攔截處理的數(shù)據(jù),并對(duì)一些新的ie不支持的用法做出警告茬斧。