2019 JSConf.Asia尤雨溪:在框架設計中尋求平衡

特別說明

這是一個由 simviso 團隊對 JSConf.Asia 中關於 前端框架設計取捨 相關話題進行翻譯的文檔,內容並非直譯,其中有一些是筆者自身的思考。而分享者正是 Vue.js 的作者 @尤雨溪,Vue 倉庫地址:github.com/vuejs/vue

讓我們一起來了解下在當前框架三足鼎立的局勢下,如何直接透過框架本身瞭解到更多有關框架設計中的的權衡,以及 Vue 是如何進行取捨的。

視頻地址:

  • 【國外前沿技術分享-前端-中文字幕】尤雨溪:在框架設計中尋求平衡 上(https://www.bilibili.com/video/av61099876)
  • 【國外前沿技術分享-前端-中文字幕】尤雨溪:在框架設計中尋求平衡 下(https://www.bilibili.com/video/av62104134)

視頻翻譯版權歸 simviso 所有

一、前言

大家好,很高興來到這裏。你今天過得怎麼樣? OK

我很肯定你已經看過很多講座了,也知道今天這次課程,希望這次不會太無聊,但是還是要給那些不認識我的人簡單地介紹一下我自己。

我的名字叫 Evan You,我的推特賬號是 Youyuxi,我的中文名字就是 Youyuxi。從2016年開始我就是一個獨立的開源開發者。

也就是說我現在已經獨立開源三年了,主要從事 Vue.js。

你們中有多少人在真正的使用它?

很好

它從 2013 年開始作爲我的一個業餘項目 ,我從 2016 年開始全職維護它。在多年的框架設計工作中,我學到了很多東西,這也給了我很多關於內部設計的觀點。人們在構建正確的框架時做出的一些權衡決策。

你們中有多少人還記得 2013年 的那段時間,那時可能每天都會有一個新的 JavaScript 框架出現,NBC 有一個類似 40,50個框架的列表,這些框架都在構建相同的東西,Vue 差不多是從它們的時代開始的,當時我只是在研究一些現有的解決方案,並試圖找出如果我構建這樣的東西,我會怎麼做。

但很明顯,我對應該做什麼的想法隨着時間的推移而發生了很大變化。

但今天我將討論其中的一些發現,特別是前端框架設計。

二、框架取捨

我敢打賭,很多人都在使用框架,即使你不使用 Vue,也可能使用 React、Angular 或其他框架。

很難想象,在沒有這樣工具的情況下就去構建一個複雜的前端應用程序。

當然,你仍然可以使用普通的 JavaScript 去做這些事,只是那樣將花費我們更多的時間。

我猜當大多數人在面對這些框架的時候,會疲於對這些框架進行比較。

每當媒體給我推送關於框架比較的文章時,比如《2019最好用的7個新框架》,我通常會說:“咦~”

這不是因爲說:“啊,我寫了 Vue,我想讓人用它,我不想聽到有人說它的壞話”

而是因爲大多數時候,這些文章只關注 github 的 star 數,npm下載量,stackoverflow 問題統計等這些可以隨時隨地通過 Google 查找到的內容。

但是,這些統計數據在某種程度上還是有用的,比如對於市場營銷來說。

但是如果你嘗試去做一個技術決策,並且嘗試去和市面上已經成熟的技術去競爭的話,那麼這些數字在某個閾值上的相關性會越來越小。

比如,我們在生產環境使用的東西,你知道的大部分可能都過了 10000 個 star 了。

但這個門檻真的那麼重要嗎?一個庫到底有幾千 star?

這並不重要,相反你應該更關心的是一些內部技術決策,比如導致這些框架的延遲發佈的真實原因是什麼。

所以在我們深入研究之前,我們先退一步思考下所有的這些框架的共同目標,我們都在努力實現的同一目標。所有框架的作者們都在朝着“讓你們儘量能更高效地構建 Web 應用程序”這一目標而努力,那麼爲什麼我們還要有這些不同比較的競爭的想法呢,這到底是好還是壞呢?

所以爲什麼我們有這麼多不同的框架,而且每個框架都有很多的追隨者呢?

就像 React 和 Angular 各自都有超過 50 萬的用戶。

我認爲不能單純的以一個好與壞來評價一個框架。

人們往往會問一些問題,比如哪個框架更好,請別再問這個了。

因爲我們很難簡單地去評定一個框架要優於另一個框架。

我們都知道軟件設計在於取捨,事實上我們現在的前端框架設計有太多的地方需要進行取捨,尤其是在 Web 中。

因爲 Web 是一個充滿多樣化元素的平臺。

我們可以在 Web 上構建各種有趣的事情,無論是最簡單的頁面還是到你所每天使用的複雜程序。

因此,爲了適應所有這些情況,框架制定者必須在多方面進行取捨。

今天我會將其中的一些拿出來聊聊,希望能對你在這塊的看法有所幫助。但是由於時間原因,我肯定不能非常深入的去講解每種情況。

所以,我只會專注其中的一部分。

第一:職責範圍。從本質說是指這個框架可以爲你做多少事情。

第二:渲染機制。當你在使用一個框架的時候,你會如何表達你的視圖層,框架如何處理代碼?它是如何將實際渲染東西展示到頁面上的?

第三:狀態機制。可變和不可變,髒檢查和依賴追蹤,響應式和類響應式。實際上,我沒有時間去深入研究這個,這個或許可以在下次分享中好好談論下。

三、職責範圍

這次,我深入探討下職責範圍。看看一個框架能爲我們做什麼事情。

我們將它一分爲二,從你們的角度來看,這個框架或庫能做一些特有的小事情,從我們的角度來看,我們會有很多整體性的考量,拿框架來說,我會盡量提供儘可能多的特性。

1、React & Angular

舉一些大家可能比較熟悉的代表性的例子,React 接近於原生庫,Angular 則提供更多抽象概念。

很少有人會去說清楚原理,這個庫(React)專注於提供一個非常基礎的 UI 模型,它專注於提供更底層的原生實現,基於此你可以構建出一套屬於自己的抽象。

有意縮小職責範圍(設計理念),這也是React整個生態系統非常活躍的原因所在,React的社區環境就像個商城(系統),圍繞着 React 的核心模型自底向上建立起來的一整套生態系統。

另外一方面,像 Angular 以及其他的一些框架,如 Ember、 aralia 這種,則更像是大教堂吧。

它們則是自上而下進行設計的,在設計過程中,用戶可能會遇到的問題都被考慮在內。

例如你們在日常開發中會經常遇到的表單驗證,動畫效果等等。

爲了讓框架可以給我們提供一個解決方案,在這個框架設計之初,我們就要以自上而下的方式來對它進行設計,即我們需要去思考如何將所有事情放到一起去工作。

有意擴大職責範圍(設計理念),這個設計理念就是當你嘗試解決一個問題時,你在框架內就能找到解決方案。

我們把這稱之爲大小職責範圍(這裏指兩種設計理念),而這也沒有好壞之說。

我想再次強調下。

2、Small Scope

優點

小的職責範圍(設計理念)它的好處在於,剛開始的時候需要理解的概念很少。

而且它具有更好的靈活性。由於框架、庫只提供了部分底層的原生實現,所以當你需要一個組件類的話,它得有一些 Props,然後你可以通過 Props 來傳遞數據,返回 VDOM 節點。

最重要的是,你可以構建任意複雜的系統。

React 有一個非常活躍的生態系統,我們能看到它擁有一些非常靈活的工具,然後,我們可以基於它們發揮出更大的創造力,而這些很棒的想法都來自 React,React 社區。

另外,有意縮小職責範圍,也可以讓團隊擁有更小的維護層面,以便他們可以專注於他們認爲重要的事情。

這樣團隊可以專注於探索一些比較有創意的點子,這也是爲什麼 React 可以花這麼多時間來做 concurrent mode、suspense、React Hooks 以及在過去幾周或幾個月內一直在創造的所有的這些有趣的東西。

實際上他們在這些事情的開發上已經花了好幾年了,只不過因爲它們的粒度比較小,正是因爲這樣他們才能更加專注於這個事情上。

缺點

當然,小範圍的設計也是有一些明顯的缺點的。

首先第一點,當你想用一個簡單的概念去解決一個本來就很複雜的問題的時候你需要做更多的鑽研工作。

我特別喜歡 Steele 這個傢伙在一場演講中說的一句話:“培養一種語言”。在演講期間,他給自己制定了一條規則,他在演講期間必須使用單音節詞,如果你想用任何類似於多音節詞的話,他必須先用單音節詞來定義它。

他只有非常有限的、非常原始的一些東西,去構建一些複雜的想法。

所以你可以想象一下那次演講是怎麼回事。

在他每次想要說出自己喜歡的一句話之前,他都要翻出一些幻燈片然後找出一堆單詞,然後繼續。這有點像用非常低級的原始語言去構建一個非常複雜的生產級別的應用程序。

你必須構建大量的抽象概念,以便在此過程中提高自己的效率。

正因爲如此,模式自然會隨着時間的推移而出現。

當我們說 React 是真的容易上手的時候,我們是否有些忽略了你或多或少需要學習 Redux 的事實。在你認爲自己是一名真正的 React 開發人員之前,你必須先去了解 HOC 高階組件、render props。然後現在,你又要去學習 Hooks 以及在 JS 中使用 CSS 的各種方式。

儘管這些模式隨着時間的推移而出現,但它們卻變成了半需要的狀態。如果你不瞭解這些,你真的可以稱自己是一名 React 開發人員嗎?

而這些東西往往沒有官方文檔。如果你去 React 官方網站,它是不會告訴你某個 CSS 和 JS 的解決方案的,你必須自己去研究並學習它。

這就是爲什麼使用者真的需要有自主學習能力的原因所在。

現如今,生態系統發展太快可能會導致碎片化和使用者的不斷流失。我相信早期 Flux 思想的追隨者,會發現每天都有一個新的 Flux 方案具體實現,然後每個 Flux 的具體實現都會對應新的 CSS/JS 的實現。

這樣很好,同時好處就是總會有新的想法出現。同樣,我們也在努力尋找最佳方案。

但是,這對於那些只想跟在後面去使用的人來說是不好的,你會不斷的有FOMO思想(Fear of Missing Out,害怕錯過),總是怕錯過下個最好的東西。

3、Large Scope

我們已經說完了小職責範圍(設計理念)的缺點。現在讓我們來談談大職責範圍的一些優點。

優點

最明顯的優點是可以通過構建抽象概念來解決最常見的問題。

如果你只是想做一些開發,我只需要一個路由、一些動畫以及一個 HTTP 客戶端來獲取一些數據。

像 Angular 這樣的框架則提供了所有你需要的東西,來實現這一目標。

事實就是你不必到處查資料,你只要照着它的文檔去用框架,你就可以搞定這些事。

集中式的設計確保了它本身與其生態系統的一致性。

當你遇到一個具體問題的時候,你不必去找一些不同的解決方案,你只需要看看框架它讓你做什麼,最大的可能就是它(框架)對此已經有解決方案。所以你壓根不必去挖掘所謂的10種不同的解決方案,然後找出對你案例最佳的那一個。

缺點

現在來說下缺點,這樣的缺點就是會有一個更高的學習門檻。

爲了將一個像素放到屏幕中,你必須跳過一些步驟才能做到,這對於初學者來說是一個很大的障礙。對於那些不適應的人,我這裏不說那些適應的人哈,如果你沒有類似使用 Java 或者 C# 等語言經驗的話,而是僅僅只學過 HTML/CSS 以及 JavaScript 的話,當你看到 Angular 文檔的時候,你可能會覺得有點不可思議。

對我來說也是如此。

然後,如果內置的解決方案是不適合當前用例的話,它則會變得不靈活。有時候你可能覺得我只是想用另外一種方式來做,但是我卻沒方法來將其替換。

最後,一個職責範圍大且成型的框架會使得引入一些底層新想法的成本更高,因爲太多的地方都要保持其一致性。

然後當你想嘗試用一個底層想法的時候,它會影響到你項目中的每個組件(牽一髮而動全身)。

所以要做這種 “改變”,就變成了一件很困難的事情。而如果你在 React 的生態系統中說,我引入 Hooks 會讓 Redux 更加冗餘,那麼朋友,這並不是一個真正的問題,因爲 React 它的核心團隊實際上並不會負責這些解決方案。

就是這樣,okay。

4、漸進式框架 Vue

這正是 Vue 所處的位置。但在我們深入瞭解 Vue 現在正在做的事情之前,我想強調的是,我並不是說 Vue 比這兩個框架都好。

因爲處於中間位置不一定就是最好的。如果 NG 和 React 在某個功能的封裝程度上差異很大,Vue 要做的就是去縮小差異,然後你會發現實際上 Vue 並沒有做到最佳。

所以,這就好像我們稍微推遲去尋求我們所認爲的最佳平衡點。而每一個選擇都會適用於不同人羣的需要。

它並不像一件東西一樣,可以適用於所有人。

所以我所說的 Vue 在職責範圍這個問題的處理方式上,你可能知道我們都叫 Vue 是一個漸進式框架。

優點

職責範圍漸進意味着框架使用分層設計,它允許以漸進的方式選擇特性。也就是說,如果你不需要路由,如果你不需要狀態管理,甚至如果你不需要構建步驟。你可以使用沒有任何特性的 Vue,你只需要將 vuejs 拉到你的頁面中,然後你就可以立即開始做一些事情。

對於初學者來講,一個需要翻越的學習障礙,就是剛開始學習時就要求你從屏幕中獲取一個像素並移除它。

所以,低的學習門檻對我們來真的很重要,這也是 Vue 的一個使命:允許更多的人蔘與 Web 開發,允許人們學習它(Vue)並專注於開發,而不是讓你學習一堆在你當前開發可能不需要的概念。

但是對於當前的這些問題,我們仍然有通過文檔去提供解決方案。當你的用例變得更復雜的時候,當你要構建更復雜的東西的時候,這時你意識到自己需要一個路由。然後你就開始翻閱文檔,你會發現,okay,我確實可以使用路由去做這個。

但與此同時,路由它又並不是必需的。並且,如果你願意的話,你自己也能實現一個路由,因爲你能看到 Vue 的路由是如何構建的,並且它的核心實現是非常乾淨的, 所以如果你願意的話,是可以用自己的方式去構建一個的。

缺點

它並不完美,因爲作爲中間者,我們需要去權衡兩者的利弊。

所以首先,儘管我們會採用新增模塊(集成 router、vuex 等),但我們仍然需要負責維護它們(router、vuex 等)

所以,我們分享了大職責範圍下統一維護面的問題,我們要想從根本上改變一些東西,我們必須確保整個生態系統的一致性。

這個維護負擔幾乎與大職責範圍相同,同時也因爲我們提供了這些預置的解決方案。

我們的生態系統可能不會像小職責範圍那樣多樣化。因爲小職責範圍喜歡把問題拋給社區。而在我們的案例中,很多用戶很滿意我們的解決方案,同時自己也不用再花費時間去找答案。

這就是職責範圍的問題,希望你現在已經有所瞭解了,我認爲這就是 React、Vue 和 Angular 之間最根本的區別。

這是它的準確定位,也定義了我們不同的用戶羣。

很多時候,我們都是在有意決定所擴展的領域。作爲框架設計者,我們知道我們正在駕馭不同的領域。這是件好事,因爲在整個階段,不同的開發人員需要不同的解決方案,以及擁有覆蓋整個主要框架的規範,確保每個人都得到他們想要的。

四、渲染機制

OK,現在我們來談談渲染機制。

也就是說你該如何通過框架來表現自己的UI結構以及該框架是如何進行渲染的。

首先,從操作層面來講它真的很複雜,它不僅僅是一件事,它包含了很多層面。

簡單點來講,可以將它看成 JSX 與 Templates,即動態渲染函數和基於靜態字符串的複雜的 Vue 表達式。然後就是表現力和原生性能,以及運行時調度和提前優化。

有些人對此會有很強烈的意見,但我個人認爲他們本質上是很相似的,他們只是對同一個底層理念的不同策略表達。

可以說更多的是技術上的權衡。

一方面,當然是 JSX React 以及所有使用 VDOM 的 react-like 庫,比如 pre-act、 stencil, infernal 等。

另一方面,則是基於模板的解決方案。我稍後會討論 Vue,但更具代表性的基於模板的解決方案有 Svelte,還有就是 ember。

可以看到,那個 logo 實際上是 glimmer.js 的 logo,也就是說,glimmer 是 Ember 裏的渲染引擎,同樣也是 Angular 的渲染引擎。

這些主要是基於模板的,它們將模板編譯成相對較低級別的指令來進行內容渲染。

1、JSX / VDOM 優點

現在我們來談談 JSX 和 VDOM 的一些優點。

我們喜歡 JSX 或 VDOM 最重要的原因就是它們具有 JavaScript 的完整表現力。

你無須在意語法,你有一種可供你使用的語言,你就可以有完整的體驗,你可以做任何你想做的事。

不僅這樣,你還可以在你的組件上構建任意複雜的邏輯。

它真的很強大、不做約束,也因爲這個特點,很多人喜歡上了 React 。

它還允許你在渲染組件時將視圖層視爲數據。它會返回一些東西,返回節點表示當前狀態的VDOM 節點,這個數據可以用於很多有意思的地方。

它對於我們構建測試方案很有用,你可以根據虛擬Dom獲取快照,你可以將它渲染到需要替換的目標,也就是我們一直在做的事情,比如將它渲染到終端、PDF、Canvas、WebGL,以及任何你能想到的你可以渲染的東西。

因爲視圖就是是數據,而你可以對數據做任何操作。

2、JSX / VDOM 缺點

目前,VDOM 本身成本真的很高。

想一想,當我們剛出來的時候,很多人都認爲,這不是很慢嗎?答案是 Yes,我們很慢,但速度卻足夠快!

但是,仍然從純粹的技術角度來看,你做了很多多餘的工作。想想這個簡單的模板,它只需要更新其中單個消息綁定就可以完成大量的工作。

我們必須遍歷整個 VDOM 節點並且做 Diff,在這個過程中,一直以遞歸的方式向下傳遞,直到你以某種方式更新它。

因此,標準 VDOM 不同的代價是相對於視圖的總大小,而不是可能改變的節點數量。

即使你只有一個節點,也可能會觸發 這個VDOM 的 Diff 算法。

正是由於渲染函數的動態特性使得它難以優化。

關於動態性,我的意思是你可以寫這樣的代碼。

你可以使用一個 for 循環來構建一個 children 數組,然後將它交給你的父節點,以及接下來進行你想要做的其他事情,也就是說你可以先創建一個父節點,然後通過往它的 children 中添加元素來進行改變。

你在使用 JavaScript 的時候,編譯器不可能hold住所有可能發生的事情,因爲 JavaScript 太過於動態化。

在這塊我們已經做了很多嘗試,但從本質上來說,我們很難通過這種方式對其提供安全的優化。

因爲它不是你簡簡單單做足夠多的條件預斷就可以的,你對用戶意圖做的預判越多,代碼越容易優化,這對於Javascript來講實在太難了。

最後,React 對於這塊的解決方案就是不把重心放在加快 VDOM 本身的速度,而是如何提高感知性能。

因此,React 引入了運行時調度併發時間切片的概念,但是這種運行時調度方案,整個 fiber,幾乎和我們管理自己的堆棧一樣,比如進入和退出渲染,所有的東西都需要很長的運行時間。

這意味着無論你何時加載 React,都必須去加載那些用於處理複雜的運行時調度工作的所有必需代碼。

這就像加載幾個20、30KB 大小的 JavaScript 一樣。

反過來,這也會讓你的初始化加載受到一點影響。

3、模板編譯優點

另一方面,如果你是在模板中編譯的渲染代碼,通常它可以生成一個更加直接的渲染指令,並且具有更好的原生性能。原因就是:根據定義,模板是一種非常有約束的語言,你只能以某種方式去編寫模板。

例如,當你寫出這樣的代碼的時候,我們可以立刻告訴你,這些 p 標籤的順序是不會變的,這個 id 是不會變的,這些 class 也不會變的,唯一會變的就是這個。

靜態(編譯)和非常嚴格的限制實際上是允許編譯器對你的意圖做更多的預判,從而給它更多的空間去做執行優化。

我們來看看 SVELTE 編譯代碼時會做什麼。

其他所有內容都是靜態的,只有 name 可能會發生改變,這個 p 是一個 update 函數,它唯一做的事情就是當 name 發生變更的時候對它(name)進行更新。

將 SVELTE 與 VDOM Diff 算法所做的事情相比較的話,它只有到達一定量級纔會更快。

所以說,根據策略的不同,模板編譯或者基於通用編譯的方法也可以使 runtime baseline 更輕量,因爲它不需要所有的複雜運行時調度來嘗試讓事情看起來更快,因爲它本身已經很快了。

所以 SVELTE 可以產出一個非常輕量的輸出,而不需要一個很重的 baseline runtime 來適應所有可能的 runtime 行爲。

4、模板編譯缺點

現在來看看模板編譯的缺點。很顯然,你會受限於模板語法,從而失去 JavaScript 的表達能力。

所以,當你想去構建一個真正複雜的組件的時候,你會想我要可以在模板裏這樣做多好,然而編譯器對此並不支持。

很不走運,如果你選擇完整的編譯路線,那就沒有退路,因爲級別越低的編譯輸出,實際上你越難將你的自定義操作與它進行掛鉤。

就好比 opa 編譯器,你是無法深入到彙編去看看爲什麼會這樣,就好比你無法使用 C 語言去調試你的彙編代碼。

更輕量的 runtime、更輕量的 baseline runtime,也可能是以每個模板更詳細的輸出作爲代價。因爲當你試圖去生成儘可能高效的代碼時,有時你必須直接在輸出的時候編碼更多信息。

例如,SVELTE 生成的代碼其實是以命令式的形式通過逐行插入創建了所有元素,並且它們有一個單獨的函數進行更新操作。

相比之下,基於 VDOM,結果是你只需要一行,而這(一行)只是一個返回 VDOM 結構的表達式。

如果在運行時編譯,則會產生運行時編譯成本。

因此,對於生產用例來說,最有可能的情況是你需要用戶事先編譯,這樣對於構建步驟來說是一個硬性要求,這是不可避免的,要麼在運行中進行編譯,要麼在預構建中進行編譯,其中涉及我們現在或多或少習慣的所有node.js工具鏈。但如果你能避免的話,對於初學者來說是件好事。

OK,因此,Vue 又一次夾在中間,我想再次強調,這不是說 Vue 是最好的。

但是,Vue 的渲染機制獨特之處在於,如果你真的將模板結合到 VDOM 中,那麼我們可以同時擁有 VDOM 和模板編譯。

所以我們可以充分利用這兩點。

我們有做過性能測試:在編譯步驟中產生的特別優化,我們不做渲染功能,稍後我將詳細介紹這一點。

在 vue2.x 版本,我們實際上還沒有充分利用這個機會,當前 vue 2.x 中的 VDOM 性能這塊表現平平。

但我會談下 3.0 對這點所做的事,讓它可以更快。

還有表現力,你可以跳過模板層直接進入渲染函數,直接利用JavaScript來執行任意複雜的邏輯。

因此,當你感覺自己受到模板約束時,這會爲你提供一條出路。

缺點是,儘管我們現在確實很快,我們可能永遠不會比 SVELTE 感覺起來快。因爲 SVELTE 的輸出是最普通的 JavaScript。然而,爲了兼容手寫的渲染函數,Vue 仍然需要維護 VDOM,這樣一來常量則必不可少。另一方面,它也會產生分歧,即我到底應該使用哪一種方式?

因此,很多用戶雖然可以使用渲染函數,但他們可能從未使用過它。

現在讓我們把它放到我們通過文件做的事情上,將 Vue 的模板編譯成 VDOM,其運行速度比普通的 VDOM 要快。

這就是我們剛纔已經討論過的,這個模板只有一個節點會改變。理想狀態下我們只需直接更新 message 字符串,節點結構是靜態的,並且從來不會發生變化,只有一個動態節點。

所以,如果我們研究這個模板可以看出它是個非常簡單的例子。

當我們有類似於 v-if 這樣的東西時,它會變得有點複雜,我們稱之爲 JSX 中的結構指令,它相當於是根據條件返回不同結果判斷的三元表達式。

現在,這會創建一個動態節點結構,因爲該節點可能存在或可能不存在。

爲了處理這種簡單的 VDOM Diff 算法,假設節點列表已經改變,那麼我們需要對兩個子數組進行 Diff 操作。

但是如果我們嘗試將其拆分,會看到 v-if 將模板拆分爲兩個嵌套塊。

我們來思考一下,如果將 v-if 本身看作一個節點,外部塊則會有一個靜態節點內容、節點結構。

在 v-if 內部,它也是靜態的。我們有兩個靜態塊,在每個塊內,你無需對節點順序進行 Diff 操作,你唯一要做就是這個塊內部進行數組的扁平化操作。

同理,對於每個 v-for 迭代我們也可以將其看成一個靜態塊。

因此,如果你有更多像 v-if 、內嵌 v-for 的寫法,你只是在進一步將代碼拆分成嵌套塊。

所以,我們最終得到一種我稱之爲 Block Tree(區塊樹)的東西,這只是一種玩法。

但 Block Tree 是一個嵌套塊的塊列表,因爲每個塊中都有一個完全靜態的節點結構,所有沒有必要使用遞歸到下層去對子列表進行 Diff 操作。

在每個塊中,你只有一個單一扁平化數組節點可能會發生改變,我們還提供了其它組織上的提示。例如,如果一個節點只有一個動態 class 綁定,我們有條捷徑,即你只需直接設置 class,然後就可以繼續執行,而不必對 Props 進行 Diff 操作。

所以,對於同一模板的 Diff,vue2.x 版本和 vue3.x 版本的做法會有明顯的區別。vue2.x 版本我們需要做一個完整的 Diff 操作,vue3.x 版本我們就只需通過使用一個單一扁平化數組(包含一個動態文本節點),而你唯一需要做的事情就是比較文本是否發生了改變。

對此,我們做了一個簡單的基準測試(benchmark), 做 1000 個 v-for 列表迭代,每個塊有 12 個 dom 節點,總共 12000 個 dom 節點,每次迭代都會動態綁定一些類或者文本。

然後我們在頁面上做了 4000 個動態綁定,然後對其更新。我們做了 100 次運行,在目前 2.6 的版本,更新時間要 36ms,而在目前 3.0 的版本中,使用新的編譯策略,只需要大概 5.4ms,比之前快了6倍多。

注意,(數據)僅限於這個基準測試。真實的應用中你可能會有一個不同的數字,但或多或少,它都會更快,這是一個基準。

五、狀態

然後,在狀態機制這塊,我可能沒有時間去真正深入研究這個問題,它可能會是另外一個演講的話題。

六、總結

但是還是總結一下,當你試圖去設計一個框架時,最佳平衡點在哪?

或許這個問題應該重新表述下。是否存在一個完美的平衡點?它又是否是一個單一的完美的平衡點,甚至是以 JS 開發人員作爲一個整體的最佳平衡點?

因爲像我們所有人一樣,都在努力去優化我們正在構建的一些特定又不同的東西。

比如說 SVELTE,它的優勢在於當你構建一些小的東西時,它可以產出非常輕量級的代碼。它也非常快,消耗內存也非常少,所以它甚至可以像嵌入式設備一樣使用。

但是如果在你自己的使用場景中,你可能會有一個更復雜的實現,你會有更多的組件,你想要 JavaScript 的表現力,同時你也需要模板提供更多的性能,那麼(這種場景下)你可以使用 Vue。如果你不是很在意一些極端的性能,然後說我就是喜歡 React 的生態系統,那麼你可以使用 React。

你也可以選擇所有這些(框架)。我認爲這樣很好,框架領域能像一個多維空間,有多個不斷變化的實體,就像把每個框架都想象成一個試圖尋求平衡點的實體。相信我們總是會有很多人去努力找出什麼是最佳的做事方式。

作爲一個開發人員,你可能會在這些實體之間遊移不定,然後你可能會被其中的一個吸引過去,有時你有可能只是在周圍跳來跳去,然後試着去找出最適合你的一個。我認識這是件好事。

但是作爲一個使用者,嘗試在這個多維空間中找到正確方法是非常困難的。

但是如果你想正確的選擇框架,難的就是你必須瞭解框架所做的一些內部權衡,你必須知道這個框架朝着哪個方向發展,並且知道它與你構建的東西是否一致。

希望通過這次演講所闡述的話題能夠幫助到你,即當你嘗試在未來選擇框架、或者當你告訴別人應該如何選擇框架時,能給予你幫助。

謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章