天天看點

InfernoJS:性能秒殺React/Vue/Preact等一衆熱門前端架構!

作者:進階前端進階

大家好,很高興又見面了,我是"進階前端‬進階‬",由我帶着大家一起關注前端前沿、深入前端底層技術,大家一起進步,也歡迎大家關注、點贊、收藏、轉發,您的支援是我不斷創作的動力。

InfernoJS:性能秒殺React/Vue/Preact等一衆熱門前端架構!

今天給大家帶來的主題是 InfernoJS,即一個速度極快、類似 React 的庫,用于在用戶端和伺服器上建構高性能使用者界面。話不多說,直接進入正題!

1.什麼是 InfernoJS

InfernoJS 是一個速度極快、類似 React 的庫,用于在用戶端和伺服器上建構高性能使用者界面。InfernoJS 項目的主要目标是為 Web 應用程式提供最快的運作時性能(幾乎與原生 JS 持平),尤其擅長渲染實時資料界面或大型 DOM 樹。

InfernoJS:性能秒殺React/Vue/Preact等一衆熱門前端架構!

同時,InfernoJS 性能是通過多重優化實作的,例如:

  • InfernoJS 基于自己的 JSX 插件建立單态(monomorphic) createVNode 調用,而不是 createElement
  • InfernoJS 的 diff 過程使用按位标志來記憶對象的形狀
  • 僅在需要時對子節點進行标準化
  • 在編譯時使用特殊的 JSX 标志來優化應用程式級别的運作時性能
  • 許多微觀優化

目前 InfernoJS 在 Github 上通過 MIT 協定開源,有超過 16k 的 star、0.7k 的 fork、10k 的項目依賴量、代碼貢獻者 200+,是一個值得關注的前端優質開源項目。

2.InfernoJS 有什麼特點

InfernoJS 具有以下明顯特征:

  • 元件驅動+單向資料流架構、同時采用類似 React 的 API、概念群組件生命周期事件
  • 部分合成事件系統(synthetic event system),标準化事件以獲得更好的跨浏覽器支援
  • InfernoJS 的 linkEvent 功能消除了使用箭頭函數或綁定事件回調的需要
  • 通過 inferno-server 在用戶端和伺服器上實作同構渲染
  • 與 React 和 Preact 不同,InfernoJS 在函數元件上有生命周期事件、支援用于 input/select/textArea 元素的受控元件
  • 可以使用 createPortal API 在目前 html 層次結構之外渲染元件,同時支援舊版浏覽器,無需任何 polyfills
  • 函數元件的 defaultHooks,這樣可以避免每次使用時重新定義生命周期事件
  • InfernoJS 支援使用字元串 <div style="background-color: red"></div> 或使用對象文字文法 <div style={{"background-color": "red"}}></div> 設定樣式
  • 從 v6 版本開始支援 Fragment、createRef 和 forwardRef API (v6),而 v8 版本開始支援 componentDidAppear、componentWillDisappear 和 componentWillMove ,類和函數元件回調以簡化動畫工作。

3.InfernoJS 與其他架構不同

3.1 InfernoJS 與 React

根據 InfernoJS 的官方描述,InfernoJS 和 React 的不同主要包含以下幾個核心點:

  • Inferno 沒有像 React 那樣的完全合成的事件系統(Fully Synthetic Event System),Inferno 隻有一個部分合成的事件系統。
  • Inferno 不支援 React Native, Inferno 僅為考慮到 DOM 的浏覽器/伺服器而設計。
  • Inferno 不支援舊字元串引用,請使用 createRef 或回調 ref API
  • Inferno 提供函數元件的生命周期事件, 對于那些喜歡輕量級元件而不是 ES2015 類的人來說,這是一個重大的利好。
  • Inferno 樣式是使用 CSS 屬性名稱 [background-color: blue] 而不是 [backgroundColor: blue] 設定的。 通過 inferno-compat 包支援駝峰命名風格。

3.2 InfernoJS 與 Preact

根據 InfernoJS 的官方描述,InfernoJS 和 Preact 的不同主要包含以下幾個核心點:

  • Inferno 有一個部分合成事件系統,通過委托某些事件來獲得更好的性能。
  • Inferno 在渲染、更新和從 DOM 中删除元素方面比 Preact 快得多。
  • Inferno 完全支援“input”/“select”/“textarea”元素的受控元件,進而可以防止出現許多邊界情況。 Preact 将事實來源推向 DOM 本身。
  • Inferno 提供函數元件的生命周期事件,對于那些喜歡輕量級元件而不是 ES2015 類的人來說,這是一個重大利好。

4.InfernoJS 的性能表現

InfernoJS架構最引以為傲的就是獨特的性能優勢,接下來一起看看 InfernoJS 在多個性能對比測試中的資料表現。當然,對于性能的對比資料大家需要辯證的來看,畢竟架構隻是決定應用性能的一部分,還有很大一部分依賴于寫業務代碼的實際開發者。

4.1 用戶端/服務端渲染

該基準測試由 Marko.js 建立,用于比較各種架構的用戶端渲染性能 ,數字顯示每秒操作數,越高越好。

InfernoJS:性能秒殺React/Vue/Preact等一衆熱門前端架構!

從上圖來看,InfernoJS 一騎紅塵,超過了 Marko.js、Preact、React、Vue 等一衆前端熱門架構。

InfernoJS:性能秒殺React/Vue/Preact等一衆熱門前端架構!

在服務端渲染方面,InfernoJS 稍遜于 Marko.js,但是依然遙遙領先 Preact、React、Vue 等架構。

4.2 JS 架構對比

js-framework-benchmark 是一個簡單的基準測試,比較了幾個 JavaScript 架構的各種典型應用程式操作。 基準測試建立一個包含随機條目的大表,并測量各種操作的時間 ,數字越低越好。

InfernoJS:性能秒殺React/Vue/Preact等一衆熱門前端架構!

如上圖所示,在架構性能對比上,InfernoJS 僅次于 Vanilla JS、遠遠高于其他前端頂級架構,比如:Vue、Svelte、Preact、Angular、Marko.js、React 等等。

4.3 UI 渲染

UI Benchmark 被認為是對庫中整體 UI 性能的更準确測試。 測試在啟用完整渲染時間和 5 次疊代的情況下運作。 在得出進一步的結論之前,請閱讀 UI Benchmark 的注意事項和規定 , 數字越低越好。

InfernoJS:性能秒殺React/Vue/Preact等一衆熱門前端架構!

結果表明,在 UI 渲染性能上,InfernoJS 依然是排名第一,比 Vanilla JS、React、Preact、DIO、ivi 等更快。

5.使用 InfernoJS

正如上面所說,Inferno 在元件設計方面有意保留了與 React 相同的設計思想,即單向資料流和關注點分離。

在下面的示例中,通過 Inferno JSX Babel 插件使用 JSX 來提供表達 Inferno 虛拟 DOM 的簡單方法。 不需要強制開發者使用 JSX,還可以使用諸如 hyperscript 或 createElement 等方法 (就像 React 一樣)。 但是請記住,編譯時優化僅适用于 JSX。

import { render } from "inferno";
const message = "Hello world";
render(<MyComponent message={message} />, document.getElementById("app"));           

此外,Inferno 還使用了像 React 這樣的 ES6 元件:

import { render, Component } from "inferno";

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 0,
    };
  }
  render() {
    return (
      <div>
        <h1>Header!</h1>
        <span>Counter is at: {this.state.counter}</span>
      </div>
    );
  }
}
render(<MyComponent />, document.getElementById("app"));           

由于性能是 InfernoJS 的一個重要方面,是以下面示例展示如何進一步優化應用程式。

在下面的示例中,通過使用 JSX $HasVNodeChildren 和 $HasTextChildren 來預定義子形狀編譯時間來優化比較過程。 在 MyComponent 渲染方法中,有一個包含 JSX 表達式節點作為其内容的 div。 由于 Javascript 的動态特性,變量節點可以是任何東西,Inferno 需要經曆規範化過程以確定沒有嵌套數組或其他無效資料。

Inferno 提供了一個名為 ChildFlags 的功能,供應用程式開發人員預先定義 vNode 子節點的形狀。 在此示例中,它使用 $HasVNodeChildren 告訴 JSX 編譯器,該 vNode 僅包含單個元素或元件 vNode。

import { createTextVNode, render, Component } from "inferno";

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 0,
    };
  }
  _getText() {
    return "Hello!";
  }
  render() {
    const node =
      this.state.counter > 0 ? (
        <div>0</div>
      ) : (
        <span $HasTextChildren>{this._getText()}</span>
      );

    return (
      <div>
        <h1>Header!</h1>
        <div $HasVNodeChildren>{node}</div>
      </div>
    );
  }
}
render(<MyComponent />, document.getElementById("app"));           

要解除安裝 inferno 應用程式,開發者需要在根元素上渲染 null。 渲染 null 将觸發整個 vDOM 樹的解除安裝生命周期 Hooks 并删除全局事件偵聽器。 解除安裝未使用的 vNode 樹以釋放浏覽器記憶體非常重要。

import { createTextVNode, render, Component } from "inferno";
const rootElement = document.getElementById("app");
// Start the application
render(<ExampleComponent />, rootElement);
// Tear down
render(null, rootElement);           

關于 InfernoJS 的更多示例可以參考文末資料,本文不再過度展開。

參考資料

https://www.infernojs.org/

https://github.com/infernojs/inferno

https://www.zhihu.com/question/65824137/answer/235159117

https://survivejs.com/blog/inferno-interview/

https://www.infernojs.org/benchmarks

https://infernojs.github.io/inferno/

https://www.infernojs.org/docs/guides/alternatives-to-jsx