React 與 Vue 框架的設(shè)計(jì)思路大 PK
正文如下

本文是第十七屆 - 前端早早聊框架專場(chǎng),也是早早聊第 122 場(chǎng),來自開課吧 - 大圣 的分享

關(guān)于我
大家好我是花果山的大圣,今天很榮幸,有機(jī)會(huì)跟大家分享一下很多年輕人感興趣的話題《 Vue 和 React 設(shè)計(jì)思想 PK》,個(gè)人水平有限,如果有理解不到位的請(qǐng)傾盆,大家看完后并且再去 Vue 和 React 源碼里探索一番,一定會(huì)有所收獲, 如果沒時(shí)間的話,還可以跟我一起早起學(xué)習(xí)
Github B站 掘金


框架總覽
前端框架繁多,在學(xué)習(xí)的時(shí)候也會(huì)陷入困惑,我們應(yīng)該抓住最主流的內(nèi)容 Vue/React,深入底層,嘗試揣摩框架作者的設(shè)計(jì)思路,開闊自己的視野,大家也不要把自己限制在框架之中,認(rèn)為工作中用到 Vue,就覺得 React 學(xué)起來沒用,有些時(shí)候我們學(xué)習(xí)競(jìng)品的框架,是為了更好的認(rèn)識(shí)自己在用的框架,廢話不多說,由于 Vue 本身是個(gè)中庸的框架,再揪出設(shè)計(jì)思路理念比較極致的 Angular 和 Svelte,我們先從視圖層最火的四大框架看一下

下載量

對(duì)比維度
我們從多個(gè)維度去對(duì)比前端的框架,就能看清楚現(xiàn)在各個(gè)框架的現(xiàn)狀,我們學(xué)習(xí)每個(gè)框架的設(shè)計(jì)范式,并且嘗試打破局限,就像豬八戒一樣,出了高老莊,一路好風(fēng)光


框架發(fā)展
字符串模板
想看清現(xiàn)在視圖層的現(xiàn)狀,要簡(jiǎn)單的看下之前框架的發(fā)展路線,JQuery 時(shí)代的渲染層,大部分都是基于字符串的模板,典型的框架就是 Underscore,baiduTemplate。大致的原理就是把 template 解析成一個(gè)函數(shù),缺點(diǎn)也很明顯,就是每次數(shù)據(jù)變化,模板內(nèi)部要全部重新渲染


然后剛才我說的四個(gè)框架占領(lǐng)了現(xiàn)在的 Web 領(lǐng)域,核心的目標(biāo)都是一樣的,為了做出性能更好的 Web 應(yīng)用,為此各路大神八仙過海,各顯神通有這么幾個(gè)宏觀的維度
原生 VS 抽象
原生的就是 JavaScript 本身,比如 JQuery 基本沒有太多的抽象,一個(gè) $ 打天下,React 抽象程度稍微復(fù)雜一些,需要理解 Component, State, Hooks, JSX 等概念就可以上手了,抽象比較多的就是 Angular,上手就需要了解十幾個(gè)概念,學(xué)習(xí)曲線很陡峭, Vue 就處在 React 和 Angular 中間,了解完 data,methods,單文件組建后就可以上手了

運(yùn)行時(shí) VS 預(yù)編譯
另外一個(gè)維度就是運(yùn)行時(shí)和預(yù)編譯這個(gè)維度,所謂運(yùn)行時(shí),在瀏覽器內(nèi)存里進(jìn)行的任務(wù),React 的 Runtime 比較重一些,數(shù)據(jù)發(fā)生變化后,并沒有直接去操作 dom,而是生成一個(gè)新的虛擬 dom,并且通過 diff 算法得出最小的操作行為,全部都是在運(yùn)行時(shí)來做的
這個(gè)維度的另外一個(gè)極端,也就是重編譯的框架,在上線之前經(jīng)過通過工程化的方式做了預(yù)處理,典型代表就是Svelte,基本上是一個(gè) Compiler Framework,寫的是模板和數(shù)據(jù),經(jīng)過處理后,基本解析成了原生的 dom 操作,Svelte 的性能也是最接近原生 js 的


Vue 依然處于比較中庸的地位,在運(yùn)行時(shí)和預(yù)編譯取了一個(gè)很好地權(quán)衡,保留了虛擬 dom,通過響應(yīng)式控制虛擬 dom 的顆粒度,在預(yù)編譯里又做了足夠多的性能優(yōu)化,做到了按需更新,這個(gè)一會(huì)再細(xì)聊
框架設(shè)計(jì)的維度
Vue 和 React
然后我們揪出來 Vue 和 React,有一些更細(xì)化維度

可變數(shù)據(jù) VS 不可變數(shù)據(jù)
Vue1 就是把響應(yīng)式數(shù)據(jù)玩出了花,通過攔截操作,修改一個(gè)數(shù)據(jù)的同時(shí)收集依賴,然后數(shù)據(jù)修改的時(shí)候去通知更新 dom,體驗(yàn)很是舒爽,我們修改了一個(gè) JavaScript 的對(duì)象,視圖層就修改好了, 這是 Vue 的黑魔法,React 的虛擬 Dom 創(chuàng)建之日期,就是通過計(jì)算新老數(shù)據(jù)的 diff,去決定操作那些 dom,所以每次修改數(shù)據(jù),需要生成一份新的數(shù)據(jù),說不上優(yōu)劣之分,只不過路線不同

這大概就是 Vue 和 React 修改數(shù)據(jù)的代碼對(duì)比



權(quán)衡
隨著應(yīng)用越來越復(fù)雜,React15 架構(gòu)中,dom diff 的時(shí)間超過 16.6ms,就可能會(huì)讓頁面卡頓,Vue1 中的監(jiān)聽器過多,也會(huì)讓性能雪崩,為了解決這個(gè)問題,Vue 選擇了權(quán)衡,以組件作為顆粒度,組件層面用響應(yīng)式通知,組件內(nèi)部通過 dom diff 計(jì)算 ,既控制了應(yīng)用內(nèi)部 Watcher 的數(shù)量,也控制了 dom diff 的量級(jí)。看到這段實(shí)現(xiàn)的時(shí)候,不僅高呼,真是妙啊

registerComponentHook(componentId, 'lifecycle', 'attach', () => {
callHook(vm, 'beforeMount')
const updateComponent = () => {
vm._update(vm._vnode, false)
}
new Watcher(vm, updateComponent, noop, null, true)
vm._isMounted = true
callHook(vm, 'mounted')
})
預(yù)編譯和運(yùn)行時(shí)
相關(guān)概念剛才已經(jīng)科普了,在 Vue 和 React 中的體現(xiàn),主要體現(xiàn)在 JSX 和 template 的區(qū)別上,React 是完全的 JSX,可以 JSX 在里面寫 JavaScipt,所以特點(diǎn)就是足夠的動(dòng)態(tài),與之對(duì)應(yīng)的就是 Vue 的 template,template 的特點(diǎn)是語法受限,可以執(zhí)行的語法技術(shù) v-if v-for 等指定的語法,雖然不夠動(dòng)態(tài),但是由于語法是可便利的,所以可以再預(yù)編譯層面做更多的預(yù)判,讓 Vue 在運(yùn)行時(shí)有更好的性能
順便放兩張尤大的 ppt 的圖,Vue3 通過在預(yù)編譯階階段做靜態(tài)標(biāo)記的優(yōu)化,做到了按需更新
純靜態(tài)的元素標(biāo)記,直接越過 diff 階段 比如 <p>hello</p>靜態(tài)的屬性也會(huì)標(biāo)記,在 diff 的時(shí)候越過這個(gè)屬性的判斷 事件函數(shù)傳遞的時(shí)候回加上緩存 v-if和v-for內(nèi)部通過 block+ 數(shù)組的方式維護(hù)動(dòng)態(tài)元素






時(shí)間切片
Vue3 通過靜態(tài)標(biāo)記 + 響應(yīng)式 + 虛擬 dom 的方式,控制了 diff 的顆粒度,讓 diff 的時(shí)間不會(huì)超過 16ms,但是 React 自上而下的 diff 過程,項(xiàng)目大了之后,一旦 diff 的時(shí)間超過 16.6ms,就會(huì)造成卡頓,對(duì)此 React 交出的解決方案就是時(shí)間切片
簡(jiǎn)單的來說就是把 diff 的任務(wù)按照元素拆開,利用瀏覽器的空閑時(shí)間去算 diff,React 把各種優(yōu)化的策略都留給了開發(fā)者,Vue 則是幫開發(fā)者做了很多優(yōu)化的工作




設(shè)計(jì)思想演進(jìn)
組合優(yōu)于集成
這個(gè)思想設(shè)計(jì)模式里面就有定論,也是現(xiàn)在 hooks 和 composition 大行其道的原因,代碼寫出來也會(huì)更加易于維護(hù),這個(gè)圖可以很好地體現(xiàn)出可維護(hù)性上的變化

跨端
剛才我們講了 Svelte 可以做到直接編譯成 JavaScript,性能接近原生,這么優(yōu)秀的思想,為什么 Vue 還要保留虛擬 dom 這個(gè)額外的 runtime 損耗呢,我覺得比較重要的一個(gè)答案就是跨端
虛擬 dom 除了可以用來計(jì)算最小的 diff 之外,另外一個(gè)重要的功能就是可以用 JavaScript 的對(duì)象來去描述一個(gè) dom,這就是一個(gè)普通的對(duì)象,在跨端領(lǐng)域意義重大,視圖層返回的是一個(gè)對(duì)象,渲染層可以調(diào)用不同平臺(tái)的渲染 api 去繪制即可

復(fù)習(xí)
如上所述,請(qǐng)認(rèn)真學(xué)習(xí)框架,并不只是為了面試,而是框架里的優(yōu)秀思想和設(shè)計(jì)模式,匯集了頂尖開發(fā)者團(tuán)隊(duì)最優(yōu)秀的思想, 多學(xué)習(xí)別人優(yōu)秀的代碼,開闊自己的視野, 閉門造車你會(huì)發(fā)現(xiàn),很多自己的頓悟只是別人的基礎(chǔ)


推薦書
最后推薦一本對(duì)我漲薪幫助最大的書《算法》第四版
算法和數(shù)據(jù)結(jié)構(gòu)一直都是前端工程師進(jìn)階的攔路虎之一,這塊內(nèi)容比較成體系,JavaScript 相關(guān)的算法書過于簡(jiǎn)單,只能入門,不能幫你學(xué)會(huì)算法, 教材《算法導(dǎo)論》從數(shù)學(xué)的角度去推導(dǎo)算法,又太難,所以我推薦這本《算法》第四版,內(nèi)容詳實(shí)有插畫,幫助系統(tǒng)的構(gòu)架算法知識(shí)體系,書里用的是 Java,學(xué)習(xí)的時(shí)候正好用 JavaScript 實(shí)現(xiàn)一遍書里的例子,學(xué)完絕對(duì)是一個(gè)新的段位
當(dāng)然,我最大的愛好除了王者,就是看書了,其實(shí)有很多書可以推薦,比如
JavaScript 進(jìn)階的紅黃綠三套書 怎么和 HR 談錢的《談判是什么》和《優(yōu)勢(shì)談判》 和產(chǎn)品經(jīng)理吹牛逼必備壇子 《浪潮之巔》《硅谷之謎》 《軟技能2》 。。。。
以后有機(jī)會(huì)再給大家推薦,感謝大家的支持 ,我是大圣, 下期再見
