alien-signalsについてまとめる

記事書く目的でスクラップしていく

alien-signalsとは何か?

Johnson Chu氏が作成した軽量のSignalsライブラリ。

これが生まれた背景として
- Vue 3.4のリアクティビティ・システムの最適化にて経験を積んだ
- Vue 3.5がPreactに似たプルベースのアルゴリズムに切り替わった
- Vue.jsとは別にpush-pullベースのリアクティビティライブラリ(alien-signals)を研究しはじめる
というのがあった。

そもそもリアクティブ・リアクティビティってなんだよってところから

Vue.jsのリアクティビティーに関する解説

リアクティビティーとは、宣言的な方法で変化に対応できるようにするプログラミングパラダイムです。

例ではスプレッドシートが挙げられているけどフォームの自動計算とかもありそう。
1つの金額が変わったら合計金額が変わる、みたいな。

リアクティビティを実現するためにJavaScriptでは何が必要になるのか、という話

/**
副作用(side effect、略してエフェクト)を扱う関数
=購読者(subscriber)
*/
function update() {
A2 = A0 + A1 /** A0とA1はエフェクトの依存関係 */
}

上記のupdate関数だけじゃ足りなくてそれを呼び出せるメソッドも必要
whenDepsChange(update)
ここではA0とA1の変数を読み込んで、それぞれが変更された場合に検知してupdateへ通知するような仕組み。

VueでのAPIに照らし合わせるとこういう感じになる
import { ref, watchEffect } from 'vue'
const A0 = ref(0)
const A1 = ref(1)
const A2 = ref()
watchEffect(() => {
// A0 と A1 を追跡
A2.value = A0.value + A1.value
})
// エフェクトをトリガー
A0.value = 2
実際はcomputedを使ってA2の値を見る感じになる。

リアクティビティって別にフォーム入力だけに限った話ではないよな

リアクティビティとはそもそも何なのか?の解説記事

え、Ember…(?)

Autotracking is Ember’s new reactivity system, which is what allows Ember to know when stateful values (such as
@tracked
properties) have changed. This was a massive update under the hood, and involved completely rewriting some of Ember’s oldest abstractions on top of this new core.

お、computedがある
class OctaneGreeter {
@tracked name = 'Liz';
get greeting() {
return `Hi, ${this.name}!`;
}
}
class ClassicGreeter {
name = 'Liz';
@computed('name')
get greeting() {
return `Hi, ${this.name}!`;
}
}

EmberによるAutotrackingの詳細記事

Autotrackingの仕組みはEmber Octaneってのに入ったらしくEmber 3.13かららしい。2019年だ。

リアクティビティを構成するものには以下の2つが含まれている
- 宣言型(Declarative)
- 状態(State)

let a = 1;
let b = 2;
function aPlusB() {
return a + b;
}
あっ!この辺のコードさっき見た気がするぞ!

EmberConf2024にてTC39 Signalsに関する発表があった

Angular Japan User GroupでのSignalsについて触れた回

プッシュ型とプル型という更新手段があるという話

- プッシュ型(データが変更された際に依存先に通知する)
- プル型(依存先が必要になった際にデータを取りに行く)

Signalsとかalien-signalsはこの両方を実現したプッシュ・プル型を採用している

オブザーバパターンやね

Q. Push型とPull型についてを初学者向けに伝えるとしたらどのようなものでたとえられますか?
A.はい、Push型とPull型のリアクティビティーについて、初学者の方にもわかりやすいように例えを使ってご説明しますね。
リアクティビティーとは、データの変更に応じて、関連する部分が自動的に更新される仕組みのことです。Push型とPull型は、この更新がどのように行われるかの違いを表しています。
Push型
Push型は、データ(状態)が変更されたときに、その変更を 関係のあるものに直接「お知らせする」 イメージです。
例えるなら、速達郵便のようなものです。あなたが何か情報を更新したとします。すると、その情報を受け取る必要のある人たち(例えば、画面にその情報を表示している部分)に、すぐに「情報が変わりました!」という手紙(更新通知)が届けられます。受け取った側は、その通知を受け取ったら、新しい情報に基づいて自分自身を更新します。
- データが変更されたら、すぐに関連する部分に通知が届きます
- 関係のあるものが能動的に更新を受け取ります
Pull型
Pull型は、データ(状態)が変更されても、関係のあるものはすぐに通知を受け取りません。代わりに、必要なときに 自分から「情報はないかな?」と確認しに行く」 イメージです。
例えるなら、掲示板のようなものです。あなたが何か情報を更新して掲示板に貼り出したとします。しかし、その情報を知りたい人たちは、定期的にその掲示板を見に行かなければ、情報の更新に気づきません。掲示板を見に行ったときに初めて、「あっ、新しい情報が出ている!」と気づき、その情報に基づいて行動します。
- データが変更されても、関連する部分はすぐには更新されません
- 関係のあるものが、必要なタイミングで情報の更新を確認しに行きます
Push-Pull型
最近の多くのリアクティブシステムでは、この二つの良いところを取り入れたPush-Pull型が使われることが多いです。
これは、データが変更されたときに、まずは「変更があったよ!」という 軽いお知らせ(Push)だけを送り、実際にその新しい情報を必要になったタイミングで取りに行く(Pull) というイメージです。
例えるなら、メール通知とWebサイトのようなものです。あなたが何か情報を更新すると、「更新がありました」というメール(軽いお知らせ)が届きます。メールを受け取った人は、興味があれば、その情報の詳細が載っているWebサイト(詳細な情報源)を見に行く(情報をPullする)という流れです。
- 変更があったことは素早く伝わるが、詳細な情報の更新は必要な時まで遅らせることで、無駄な処理を減らすことができます
これらの例えで、Push型とPull型のリアクティビティーの違いが少しでもイメージできたなら幸いです。多くの現代的なフレームワークは、効率性を高めるためにPush-Pull型のアプローチを採用していることが多いことも覚えておくと良いでしょう。
by NotebookLM

各フレームワークにおけるリアクティブシステムの取り入れ
by NotebookLM

Ember
Autotracking モデルを採用し、コンポーネントの初期状態や引数の状態をレンダリング。@tracked デコレータを使用して、変更を追跡し再レンダリングをトリガーするプロパティを明示的にマーク。

Svelte
コンパイラベースのアプローチを取り、DOM へのマウント後のライフサイクル (onMount)、DOM 要素への参照 (bind:this)、イベントディスパッチ (createEventDispatcher)、コンポーネント間のメソッド公開 (export const)、リアクティブステートメント ($) など、きめ細かいリアクティビティと効率的な更新を実現するための仕組みを提供。
- 例:
onMount()
は、コンポーネントが DOM にマウントされた直後にコールバックを実行 - 例:
bind:this={nameEl}
を使用して、input を nameEl 変数にバインド - 例:
export const greet = (name) => alert(Hello, ${name}!);

Vue.js
リアクティブな JavaScript オブジェクト(Proxy ベース)を使用し、状態が変更されるとビューを更新。ref、computed、watchEffect などの API を提供。
- 例:
const A2 = computed(() => A0.value + A1.value)

Preact
「Signals」と呼ばれるリアクティビティプリミティブを導入。シグナルの .value プロパティにアクセスすると、そのシグナルの値が変更されたときにコンポーネントが自動的に再レンダリングされる。
- 例:
const count = signal(0);

最も重要なアイデアや事実
- リアクティビティは、現代のフロントエンドフレームワークにおける重要な概念であり、状態の変化に応じて UI を効率的に更新するための基盤となる。
- 複数の主要なフレームワークが、それぞれ独自の方法でリアクティビティを実現しているが、近年「Signals」というパターンに収束する傾向が見られる。
- Signals は、きめ細かい依存関係の追跡と効率的な更新を可能にし、パフォーマンスと開発体験の向上に貢献する可能性がある。
- TC39 における Signals の標準化の動きは、JavaScript エコシステム全体に大きな影響を与える可能性があり、フレームワーク間の相互運用性や開発の共通理解を促進することが期待される。
- Angular における Signals の導入は、Zone.js への依存度を下げ、よりシンプルで効率的なリアクティブプログラミングモデルを提供する可能性がある。また、RxJS との連携も考慮されている。
- Ember の Autotracking のように、フレームワークは開発者が宣言的に派生状態を記述し、状態間の依存関係を意識せずにリアクティブな挙動を得られるような仕組みを提供している。
by NotebookLM

記事としてまとまったのでクローズ
Webフロントエンドでのリアクティビティからalien-signalsを知ろう