フロントエンドの将来のフレームワークの選択

序文

私たちがよく知っている 3 つの主要なフレームワークは、vue の応答性の高い仮想 dom 処理から、仮想 dom 処理の非同期更新レンダリングの下で​​の React のファイバー アーキテクチャ、そして angular の独自に設計された dom 更新戦略、依存性注入などに至るまでです。次に、フロントエンドの今後の枠組みと展開について簡単に説明します。

3つのフレームワークの特徴

宣言型、仮想 DOM、コンポーネント化

React、angular、vue の 3 つのフレームワークは、ループと表示をテンプレートで宣言的に定義するという点で似ており、dom を命令的に変更する必要はありません。元の dom 更新戦略は考慮されなくなり、仮想 dom と実際の dom の比較が使用されるため、大規模なシナリオでのオンデマンド更新ノードに非常に役立ちます。同時に、フレームワークはすべてコンポーネントベースの開発を指向しているため、コードの再利用の問題をより効率的に解決できます。

フロントエンドフレームワークのトレンド

image.png

明らかな傾向を持つ 3 つのコンパイル フェーズ フレームワーク、Svelte、Solid、Qwik があることがわかります。

洗練されたフロントエンドフレームワーク

Svelte の言語はネイティブ JS に非常に似ており、そのパフォーマンスはネイティブ JS と何ら変わりません。Svelte は、多重化ノードがあまり必要でない場合に、フレームワークのランタイム レベルで仮想 dom 比較のパフォーマンスの問題を解決します。直接コンパイルできます。リアルドム加工。中心となるのは静的分析コンパイラで、どの変数が変更されるかを知らせ、必要に応じてノードを更新するだけです。Svelte の具体的な使い方を見てみましょう。

<script>
  let count = 0;
  const increment = () => {
    count += 1;
  };
</script>

<button on:click={increment}>
  count is {count}
</button>

コンパイル後の内容を見てみましょう

image.png

このブロックを見ると、実際、p 関数は値を更新し、c 関数は dom を作成し、d 関数は dom をアンインストールしていることがわかります。本質的に、Svelte は実際に宣言的な処理を実現するのに役立ちます。では、データの変更をどのように監視するのでしょうか? Svelte は実際にコンパイラーを使用して、変数の割り当て、更新、および変更を検出します。変更が検出されると、対応する変更されたコード フラグメントがすぐに実行されます。

強固なフロントエンドフレームワーク

Solid は React に似て書かれています。最大の違いは、仮想 dom がないことと、React のような一方向のデータ フローがあることです。vite を通じて Solid テンプレート プロジェクトを開始するだけです。ローカル サービスの実行後、コンパイル前に次のようになることを確認できます。

import { createSignal } from 'solid-js'
import './App.css'

function App() {
  const [count, setCount] = createSignal(0)

  return (
    <div class="card">
      <button onClick={() => setCount((count) => count + 1)}>
        count is {count()}
      </button>
      <p>
        hello solid !
      </p>
    </div>
  )
}

export default App

image.png

コンパイル後、静的な HTML 文字列がテンプレートを介して渡され、実際の dom が返され、さまざまなノード位置にすぐに照合でき、クリック イベントが el2 にバインドされ、テキスト ノードが$insert に挿入されます。

那么solid是怎么监听然后更新模板的dom元素呢,答案是我们代码的createSignal方法

信号 Signal

Solid的createSignal是一种函数式编程范式,其基本原理是返回一个数组,包含一个getter函数和一个setter函数。其主要用途是实现响应式数据流,即当setter函数更新数据时,会自动触发与之相关的视图更新。

具体来说,createSignal会创建一对getter和setter函数,getter函数用于获取当前数据值,setter函数用于更新数据值,并通知所有监听该数据的视图进行更新。Solid在内部使用了一些技术(如ES6的Proxy)来实现数据的响应式更新,保证了视图和数据的实时同步。

除了createSignal外,Solid还提供了一些响应式编程相关的API,如createMemo、createEffect等,用于实现类似Vue.js的单向数据流和响应式UI更新。

Qwik 全栈框架

Qwik主要解决了在服务端渲染的dom,在客户端也要修改它返回渲染的dom(这个过程为水合也就是hyration),客户端同时会去比对服务端的dom结构,并对代码做重新渲染,那么同一代码片段渲染了两次的性能损耗是很大的问题。

Qwik的做法是将全部的渲染逻辑放在了服务端,那么我们在页面如何做交互呢,控制服务端返回的字符串渲染动态的的dom呢,答案是Qwik直接编译出不同的代码片段,我们每一个行为,比如你定义的click事件,他会单独生成一个js文件,用户在触发这个事件后,我们可以直接请求服务端获取click的代码片段。所以Qwik会产出大量的交互的js文件,所以他是细粒度的按需加载。

我们看下具体的用法:

import { component$, useSignal } from '@builder.io/qwik'
import './app.css'

export const App = component$(() => {
  const count = useSignal(0)

  return (
    <>
      <h1>Vite + Qwik</h1>
        <button onClick$={() => count.value++}>count is {count.value}</button>
    </>
  )
})

image.png

我们在渲染静态dom的入口看看,这是一个类似react的createElement的编译函数。我们可以看到这个事件方法的文件是懒加载的,我们点击按钮后就会返回App_component__Fragment_div_button_onClick_Atxt02dBaJI这个事件方法的文件。

image.png

那么Qwik是如何修改变更的变量并把订阅的变量更新呢,然后同步渲染视图呢?答案其实也是跟solid的signal思路是一样的,都是通过proxy来监听,但是在useLexivcalScope中我们会得到序列化的json,里面会存有count变量,并定义了依赖集合subMap, 通过proxy代理count,一旦count写入变化,就会触发set并更新subMapp里面的依赖变量,然后更新视图。

所以Qwik项目一般主页会请求完整的html结构,和交互js。所以性能是要比nextjs等ssr框架是要更好的。

前端的未来——编译器

我们可以看到大量的框架在走向编译的阶段,而不是运行时。也就是我们用构建换运行时的时间,同时我们也在构建阶段做优化。这样我们完全可以使用rust、go等设计的编译器,带来更快的性能提升。比如之前的swc、rspack、esbuild。

おすすめ

転載: juejin.im/post/7253610755126427705