為什麼inferno.js這麼快?

最近在做各個框架的性能測試,發現inferno.js速度快的可怕,幾乎已經和原生js持平了,其他框架或多或少的要和它有一定的性能差距,這是因為什麼呢?

主要是兩個測試,一個是js-repaint-perfs,見下圖;

一個是js-framework-benchmark,見Interactive Results


這個問題挺有意思。

我們先來看看 inferno.js 是什麼:

An extremely fast, React-like JavaScript library for building modern user interfaces

好吧,注意用詞 :extremely;

同時還有:

Inferno is an insanely fast, 9kb React-like library for building high-performance user interfaces on both the client and server.

這時候的用詞:insanely;

當然,最基本的是 React-like,如果你還不了解它是什麼,可以自己先看下,不再過多介紹。

對於其高性能的展現以及 benchmark,其官方從四個維度展示了樣例:

  • Virtual DOM Benchmark
  • UI Bench
  • dbmonster
  • JS Web Frameworks Benchmark - Round 6

自從誕生起,inferno.js 的定位就是高性能,高效率。作為 react-like 類庫,做到高效的最重要一環當然就是對於 virtual dom 的 diff,這個 diff 演算法的優劣,以及虛擬 dom 相關周邊的一切(包括 batching 等)非常重要。

這方面內容,我覺得 @司徒正美 非常有發言權。

如果司徒大大有時間,可以親自來說說。下面回答前半部分內容,源自司徒正美的積累和分享(出處:去哪兒網迷你React的研發心得 - javascript魔法師 - SegmentFault)。

虛擬DOM庫是分為兩大派系:演算法派與擬態派。

最開始出現的是 virtual-dom (Matt-Esch/virtual-dom) 這個庫。它的實現是非常學院風格,通過深度優先搜索與 in-order tree 來實現高效的 diff。它與React後來公開出來的演算法是很不一樣。

因為我們知道 React diff 演算法的一個核心假設就是逐層,從上到下一級一級的比較。DFS 演算法顯然和這個假設是相違背的。不過 virtual-dom 這個庫文件組織良好,代碼注釋清晰,有時間還是建議看一下的。

然後是 cito.js (joelrich/citojs) 的橫空出世,這對今後所有虛擬DOM的演算法都有重大影響。它採用兩端同時進行比較的演算法,將diff速度拉高到幾個層次。

緊隨其後的是 kivi.js,在 cito.js 的基礎上提出兩項優化方案,

  • 使用 key 實現移動追蹤;
  • 基於key的編輯長度矩離演算法應用(演算法複雜度 為O(n^2));

但這樣的 diff 演算法太過複雜了,於是後來者 snabbdom 將 kivi.js 進行簡化,去掉編輯長度矩離演算法,調整兩端比較演算法。速度略有損失,但可讀性大大提高。再之後,就是著名的 vue2.0 把 sanbbdom 整個庫整合掉了。當然這都是後話。

緊接著,我們的主角就要上場了:演算法派的老大是 inferno,它使用多種優化方案將性能提至最高,最終其作者便邀請進 react core team,負責 react 的性能優化。

從下圖中,可以看到 inferno.js 的衍生思路:

繼承自 cito.js,如果你有細心看上面一段,就會明白 inferno.js 所謂「師承」的基礎。

另外,當然還有很多細節,進行了更大程度的優化。總結一下,包括但不限於:

  • Inferno 避免使用存在 prototype/constructors 的對象,而是支持對象字面量形式,保證對象本身擁有最小化的屬性。同時採用特有的 utility/helper 函數,對這些對象進行訪問或 mutate;這樣的做法對於不支持 JIT (just in time) 編譯的情況,或者手機低電量的情況,能夠顯著提升效率;
  • 與其維護兩套 virtual DOM 進行 diff,inferno 直接將當前 virtual dom 和真實 dom 對象 diff。對於性能的提升也是一定程度上有幫助的;
  • Inferno 試圖最大化重複利用對象屬性、對象本身、DOM 節點。這種例子非常的多,就不列舉了,源碼裡面都可以發現。感興趣可以再問,我展開來說。
  • Inferno 避免過多的操作 DOM。同時避免使用類似諸如 childNodes 和 innerHTML 的 DOM API,它們的共同特點都是開銷大。同理,在清除 DOM 節點內容時,更高效的做法永遠是:textContent("");
  • 一系列關於 JIT 編譯的優化和最佳實踐。說多了有些無聊,不再詳細介紹。同樣感興趣可以再問,我展開來說。
  • 另外一個爆點就是 Inferno 使用了自己的 event system 來處理事件。這樣做可以自己把控是否需要代理事件,還是使用 inline event;合適的事件代理能帶來性能和內存使用的極大提升。
  • 最後提一下 Inferno 對於使用 key 子節點的演算法優化吧。React 在這方面並沒有做到極致。使用動態規劃等演算法,在對於存在 key 的子節點位置變換(增刪亂序)等還是比較有必要的。

還有業務代碼要做,PM 要來改需求了。先說這麼多吧,相關細節還有很多非常有趣的。

另外題主對於這個問題有疑問,說明對於前端性能關注比較多。

我覺得這是非常好的習慣,同時建議下可以先自己找一下答案。

比如在 Inferno.js GitHub 倉庫中 (infernojs/inferno),搜索關於 performance 的 issues,我看到一共有 102 條之多:

每一個 issue 的討論,自己看下來都會有收穫。

然後就是看源碼,很多東西都會讓我這種菜鳥開眼界,嘆為觀止的。期待大佬們的補充。


有興趣的朋友可以看下這篇 inferno 作者 Dominic Gannaway 的專訪:Inferno - Blazing fast, React-like UI library - Interview with Dominic Gannaway。


光快沒有用啊 最重要的是 又好用又快

但是任何框架 基本都會往 強大而臃腫發展。然後直到某天 被其他框架代替。


不錯不錯,我選擇riot


成功人士才關注跑分,失敗人士只關注開發效率(文檔清晰/坑少/生態良好/代碼量少/可讀性好)。

所以我用Django……


語言在他們而言是工具 在我們而言是一門學問mmm


誰主張,誰舉證。你的證據在哪裡?都沒有證據,你如何讓別人相信你這個inferno.js比別的框架快。

這個典型的例子就是「不看場景談框架性能」,都是耍流氓。


推薦閱讀:

tabris.js這個框架使用起來怎樣?
為什麼一直沒有出現一個可以把現代 CSS 編譯為支持老版本瀏覽器 CSS 的編譯工具?

TAG:前端開發 | JavaScript | React |