0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

前端框架的Signals有何優(yōu)勢(shì)?

OSC開源社區(qū) ? 來源:OSCHINA 社區(qū) ? 2023-10-11 11:04 ? 次閱讀

作者|jump--jump

Signals 在目前前端框架的選型中遙遙領(lǐng)先!

國慶節(jié)前最后一周在 Code Review 新同學(xué)的 React 代碼,發(fā)現(xiàn)他想通過 memo 和 useCallback 只渲染被修改的子組件部分。事實(shí)上該功能在 React 中是難以做到的。因?yàn)?React 狀態(tài)變化后,會(huì)重新執(zhí)行 render 函數(shù)。也就是在組件中調(diào)用 setState 之后,整個(gè)函數(shù)將會(huì)重新執(zhí)行一次。

React 本身做不到。但是基于 Signals 的框架卻不會(huì)這樣,它通過自動(dòng)狀態(tài)綁定和依賴跟蹤使得當(dāng)前狀態(tài)變化后僅僅只會(huì)重新執(zhí)行用到該狀態(tài)代碼塊。

個(gè)人當(dāng)時(shí)沒有過多的解釋這個(gè)問題,只是匆匆解釋了一下 React 的渲染機(jī)制。在這里做一個(gè) Signals 的梳理。

優(yōu)勢(shì)

對(duì)比 React,基于 Signals 的框架狀態(tài)響應(yīng)粒度非常細(xì)。這里以 Solid 為例:

import { createSignal, onCleanup } from "solid-js";

const CountingComponent = () => {
  // 創(chuàng)建一個(gè) signal
  const [count, setCount] = createSignal(0);

  // 創(chuàng)建一個(gè) signal
  const [count2] = createSignal(666);

  // 每一秒遞增 1
  const interval = setInterval(() => {
    setCount((c) => c + 1);
  }, 1000);

  // 組件銷毀時(shí)清除定時(shí)器
  onCleanup(() => clearInterval(interval));

  return (
    
count: {count()} {console.log("count is", count())}
count2: {count2()} {console.log("count2 is", count2())}
); };
上面這段代碼在 count 單獨(dú)變化時(shí),只會(huì)打印 count,壓根不會(huì)打印 count2 數(shù)據(jù)。 控制臺(tái)打印如下所示:

count is 0

count2 is 666

count is 1

count is 2

...

從打印結(jié)果來看,Solid 只會(huì)在最開始執(zhí)行一次渲染函數(shù),后續(xù)僅僅只會(huì)渲染更改過的 DOM 節(jié)點(diǎn)。這在 React 中是不可能做到的,React 是基于視圖驅(qū)動(dòng)的,狀態(tài)改變會(huì)重新執(zhí)行整個(gè)渲染函數(shù),并且 React 完全無法識(shí)別狀態(tài)是如何被使用的,開發(fā)者甚至可以通過下面的代碼來實(shí)現(xiàn) React 的重新渲染。

const [, forceRender] = useReducer((s) => s + 1, 0);

除了更新粒度細(xì)之外,使用 Signals 的框架心智模型也更加簡(jiǎn)單。其中最大的特點(diǎn)是:開發(fā)者完全不必在意狀態(tài)在哪定義,也不在意對(duì)應(yīng)狀態(tài)在哪渲染。如下所示:

import { createSignal } from "solid-js";

// 把狀態(tài)從過組件中提取出來
const [count, setCount] = createSignal(0);
const [count2] = createSignal(666);

setInterval(() => {
  setCount((c) => c + 1);
}, 1000);

// 子組件依然可以使用 count 函數(shù)
const SubCountingComponent = () => {
  return 
{count()}
; }; const CountingComponent = () => { return (
count: {count()} {console.log("count is", count())}
count2: {count2()} {console.log("count2 is", count2())}
); };

上述代碼依然可以正常運(yùn)行。因?yàn)樗腔跔顟B(tài)驅(qū)動(dòng)的。開發(fā)者在組件內(nèi)使用 Signal 是本地狀態(tài),在組件外定義 Signal 就是全局狀態(tài)。

Signals 本身不是那么有價(jià)值,但結(jié)合派生狀態(tài)以及副作用就不一樣了。代碼如下所示:

import {
  createSignal,
  onCleanup,
  createMemo,
  createEffect,
  onMount,
} from "solid-js";

const [count, setCount] = createSignal(0);

setInterval(() => {
  setCount((c) => c + 1);
}, 1000);

// 計(jì)算緩存
const doubleCount = createMemo(() => count() * 2);

// 基于當(dāng)前緩存
const quadrupleCount = createMemo(() => doubleCount() * 2);

// 副作用
createEffect(() => {
  // 在 count 變化時(shí)重新執(zhí)行 fetch
  fetch(`/api/${count()}`);
});

const CountingComponent = () => {
  // 掛載組件時(shí)執(zhí)行
  onMount(() => {
    console.log("start");
  });

  // 銷毀組件時(shí)執(zhí)行
  onCleanup(() => {
    console.log("end");
  });

  return (
    
Count value is {count()}
doubleCount value is {doubleCount()}
quadrupleCount value is {quadrupleCount()}
); };
從上述代碼可以看到,派生狀態(tài)和副作用都不需要像 React 一樣填寫依賴項(xiàng),同時(shí)也將副作用與生命周期分開 (代碼更好閱讀)。

實(shí)現(xiàn)機(jī)制

細(xì)粒度,高性能,同時(shí)還沒有什么限制。不愧被譽(yù)為前端框架的未來。那么它究竟是如何實(shí)現(xiàn)的呢? 本質(zhì)上,Signals 是一個(gè)在訪問時(shí)跟蹤依賴、在變更時(shí)觸發(fā)副作用的值容器。 這種基于響應(yīng)性基礎(chǔ)類型的范式在前端領(lǐng)域并不是一個(gè)特別新的概念:它可以追溯到十多年前的 Knockout observables 和 Meteor Tracker 等實(shí)現(xiàn)。Vue 的選項(xiàng)式 API 也是同樣的原則,只不過將基礎(chǔ)類型這部分隱藏在了對(duì)象屬性背后。依靠這種范式,Vue2 基本不需要優(yōu)化就有非常不錯(cuò)的性能。

依賴收集

React useState 返回當(dāng)前狀態(tài)和設(shè)置值函數(shù),而 Solid 的 createSignal 返回兩個(gè)函數(shù)。即:

type useState = (initial: any) => [state, setter];

type createSignal = (initial: any) => [getter, setter];
為什么 createSignal 要傳遞 getter 方法而不是直接傳遞對(duì)應(yīng)的 state 值呢?這是因?yàn)榭蚣転榱司邆漤憫?yīng)能力,Signal 必須要收集誰對(duì)它的值感興趣。僅僅傳遞狀態(tài)是無法提供 Signal 任何信息的。而 getter 方法不但返回對(duì)應(yīng)的數(shù)值,同時(shí)執(zhí)行時(shí)創(chuàng)建一個(gè)訂閱,以便收集所有依賴信息。

模版編譯

要保證 Signals 框架的高性能,就不得不結(jié)合模版編譯實(shí)現(xiàn)該功能,框架開發(fā)者通過模版編譯實(shí)現(xiàn)動(dòng)靜分離,配合依賴收集,就可以做到狀態(tài)變量變化時(shí)點(diǎn)對(duì)點(diǎn)的 DOM 更新。所以目前主流的 Signals 框架沒有使用虛擬 DOM。而基于虛擬 DOM 的 Vue 目前依靠編譯器來實(shí)現(xiàn)類似的優(yōu)化。 下面我們先看看 Solid 的模版編譯:

const CountingComponent = () => {
  const [count, setCount] = createSignal(0);
  const interval = setInterval(() => {
    setCount((c) => c + 1);
  }, 1000);

  onCleanup(() => clearInterval(interval));
  return 
Count value is {count()}
; };

對(duì)應(yīng)編譯后的的組件代碼。

const _tmpl$ = /*#__PURE__*/ _$template(`
Count value is `); const CountingComponent = () => { const [count, setCount] = createSignal(0); const interval = setInterval(() => { setCount((c) => c + 1); }, 1000); onCleanup(() => clearInterval(interval)); return (() => { const _el$ = _tmpl$(), _el$2 = _el$.firstChild; _$insert(_el$, count, null); return _el$; })(); };

執(zhí)行 _tmpl$ 函數(shù),獲取對(duì)應(yīng)組件的靜態(tài)模版

提取組件中的 count 函數(shù),通過 _$insert 將狀態(tài)函數(shù)和對(duì)應(yīng)模版位置進(jìn)行綁定

調(diào)用 setCount 函數(shù)更新時(shí),比對(duì)一下對(duì)應(yīng)的 count,然后修改對(duì)應(yīng)的 _el$ 對(duì)應(yīng)數(shù)據(jù)

其他

大家可以看一看使用 Signals 的主流框架:

Vue Ref

Angular Signals

Preact Signals

Solid Signals

Qwik Signals

Svelte 5 (即將推出)

不過目前來看 React 團(tuán)隊(duì)可能不會(huì)使用 Signals。

Signals 性能很好,但不是編寫 UI 代碼的好方式

計(jì)劃通過編譯器來提升性能

可能會(huì)添加類似 Signals 的原語

PREACT 作者編寫了@preact/signals-react 為 React 提供了 Signals。不過個(gè)人不建議在生產(chǎn)環(huán)境使用。

編輯:黃飛

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • API
    API
    +關(guān)注

    關(guān)注

    2

    文章

    1461

    瀏覽量

    61488
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4235

    瀏覽量

    61965
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4670

    瀏覽量

    67760
  • Signals
    +關(guān)注

    關(guān)注

    0

    文章

    2

    瀏覽量

    1001

原文標(biāo)題:聊聊前端框架的未來Signals

文章出處:【微信號(hào):OSC開源社區(qū),微信公眾號(hào):OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    賽靈思基于FPGA平臺(tái)的PFM電機(jī)控制方案優(yōu)勢(shì)?

    PFM為什么是一種比PWM更好的電機(jī)控制算法?賽靈思基于PFM算法的電機(jī)控制方案到底優(yōu)勢(shì)?詳見本文分析...
    發(fā)表于 07-23 10:18 ?2175次閱讀

    ARM-based相比ARM cortex優(yōu)勢(shì)

    你看好ARM-based架構(gòu)嗎 相比ARM cortex優(yōu)勢(shì) ARM其他還有什么架構(gòu)啊,感覺曝光的好少。。
    發(fā)表于 04-24 06:55

    在電機(jī)控制上28069比28335優(yōu)勢(shì)

    在我的認(rèn)識(shí)中28069與28335在硬件上的主要差別在于28069比28335多了vcu和cla兩個(gè)模塊,請(qǐng)問:1.在電機(jī)控制上28069比28335優(yōu)勢(shì)?2.在controlSUITE/development_kits/H
    發(fā)表于 11-29 20:25

    主流web前端技術(shù)框架

    BootstrapBootstrap是一款很受歡迎的前端框架,基于HTML、CSS、JavaScript設(shè)計(jì)的,簡(jiǎn)單靈活,使得Web開發(fā)更加快捷,Bootstrap中包含了豐富的Web組件和13個(gè)jquery插件
    發(fā)表于 03-28 16:56

    labview操作者框架有什么優(yōu)勢(shì)

    labview操作者框架采用的面向?qū)ο缶幊?,到?b class='flag-5'>有什么優(yōu)勢(shì)呢?目前不知道這個(gè)框架優(yōu)勢(shì)
    發(fā)表于 05-21 14:45

    請(qǐng)問如何看待svelte這個(gè)前端框架

    如何看待 svelte 這個(gè)前端框架?看了下。十分精簡(jiǎn)。思路也很獨(dú)特。
    發(fā)表于 06-01 05:55

    微內(nèi)核什么時(shí)候發(fā)布?微內(nèi)核優(yōu)勢(shì)?

    想了解下微內(nèi)核什么時(shí)候發(fā)布的?微內(nèi)核優(yōu)勢(shì)
    發(fā)表于 10-10 10:09

    學(xué)好前端必須要弄懂的框架!

    間過度框架,對(duì)“新手”極其友好,學(xué)習(xí)了jQuery框架的思想,再開始學(xué)習(xí)Vue 和 React就簡(jiǎn)單了。為了讓更多同學(xué)能輕松學(xué)會(huì)前端框架,信盈達(dá)小編給大家分享一個(gè)jQuery
    發(fā)表于 06-30 16:57

    學(xué)好前端必須要弄懂的框架!

    間過度框架,對(duì)“新手”極其友好,學(xué)習(xí)了jQuery框架的思想,再開始學(xué)習(xí)Vue 和 React就簡(jiǎn)單了。為了讓更多同學(xué)能輕松學(xué)會(huì)前端框架,信盈達(dá)小編給大家分享一個(gè)jQuery
    發(fā)表于 07-06 11:18

    網(wǎng)表仿真與RTL仿真相比優(yōu)勢(shì)

    網(wǎng)表仿真與RTL仿真相比優(yōu)勢(shì)?“線與”邏輯是什么?
    發(fā)表于 11-04 06:23

    目前流行的前端開發(fā)框架是什么

    00. 目錄文章目錄00. 目錄01. 概述02. 跨多平臺(tái)開發(fā)框架03. 移動(dòng)端混合開發(fā)框架04. 前端開發(fā)框架05. 附錄01. 概述作為前端
    發(fā)表于 11-08 06:52

    Android框架里的相關(guān)默認(rèn)權(quán)限操作作用

    Android框架里的相關(guān)默認(rèn)權(quán)限操作作用?
    發(fā)表于 02-17 06:23

    前端開發(fā)】一篇文章概括目前流行的前端開發(fā)框架

    00. 目錄文章目錄00. 目錄01. 概述02. 跨多平臺(tái)開發(fā)框架03. 移動(dòng)端混合開發(fā)框架04. 前端開發(fā)框架05. 附錄01. 概述作為前端
    發(fā)表于 11-03 11:36 ?25次下載
    【<b class='flag-5'>前端</b>開發(fā)】一篇文章概括目前流行的<b class='flag-5'>前端</b>開發(fā)<b class='flag-5'>框架</b>

    騰訊開源的前端框架介紹

    ? 今天推薦兩個(gè)騰訊開源的前端框架,分別是 wujie(無界)和 Omi。 wujie(無界) 無界微前端是一款基于 Web Components + iframe 微前端
    的頭像 發(fā)表于 06-17 14:44 ?1850次閱讀
    騰訊開源的<b class='flag-5'>前端</b><b class='flag-5'>框架</b>介紹

    四線制測(cè)電阻優(yōu)勢(shì)?與二線制測(cè)電阻區(qū)別?

    前言四線測(cè)試法被認(rèn)為是目前為止最好的消除引線電阻引入誤差(或?qū)⑵浣抵磷钚〉模┑臏y(cè)試方案。那么,四線測(cè)試法優(yōu)勢(shì)?它的原理是什么?與二線制測(cè)電阻
    的頭像 發(fā)表于 05-12 09:43 ?1.8w次閱讀
    四線制測(cè)電阻<b class='flag-5'>有</b><b class='flag-5'>何</b><b class='flag-5'>優(yōu)勢(shì)</b>?與二線制測(cè)電阻<b class='flag-5'>有</b><b class='flag-5'>何</b>區(qū)別?