アーカイブ

Webフロントエンドでの​リアクティビティから​alien-signalsを​知ろう

出典元: zenn.dev

近年のWebフロントエンド開発において「リアクティビティ」という概念が非常に重要になっています。今回は、このリアクティビティにまつわる歴史を辿りつつ、2025年の1月にv1.0となったリアクティビティライブラリである「alien-signals」についてを解説していきます。

リアクティビティとは何を実現するものか

そもそも「リアクティビティ」とは何かについてを説明します。

リアクティビティを日本語にすると「反応性」と訳されることがあります。この「反応性」とは、ある状態の変化に対してシステムが適切な対応をすることを指します。

Webフロントエンドにおける「反応性」は、アプリケーションの状態(データ)が変化した際に、その変化を検知し、関連するUIや他の状態を自動的に更新する仕組みのことです。

リアクティビティシステムイベント発生状態変更UI更新操作入力状態 (データストア)表示・変更ユーザー

分かりやすい例としてあげられるのがスプレッドシートのようなUIです。あるセルの値が変更されると、そのセルの値を参照している他のセルも自動的に再計算され表示が更新されます。

列A、B、Cと行0、1、2を持つスプレッドシート表。セルA0には1、セルA1には2、セルA2には3が入っています。その他のセルは空白です。
スプレッドシートのサンプル
列A、B、Cと行0、1、2を持つスプレッドシート表。セルA0には1、セルA1には2、セルA2には数式「= A0 + A1」が表示されています。その他のセルは空白です。
セルA2には数式が挿入されている
列A、B、Cと行0、1、2を持つスプレッドシート表。セルA0には1、セルA1には3、セルA2には4が入っています。その他のセルは空白です。
セルの値が変更されるとそれを参照するセルも変更される

MVCアプリケーションで、モデルの変更を監視しているビューが自動的に更新される仕組みも同様のものと言えます。

リアクティブプログラミングについて

このリアクティビティについての源泉を知るために、リアクティブプログラミングについても触れておきましょう。

リアクティブプログラミングは非同期でのデータの流れ(ストリーム)を扱うプログラミングスタイルです。一般には「Publish-Subscribe(通称Pub-Sub)」モデルを採用してデータストリームを扱っています。これはGoFのオブザーバーパターン1に代わるものとされています。

発行通知トピックを購読PublisherEvent BrokerSubscriber

リアクティブプログラミングが有用な例として、とあるデータの更新が終わった際に特定のUIを更新したり、とあるユーザーが通知を実施した際に他のユーザー全員に通知を届けたい場合が挙げられます。

Webフロントエンドにおけるリアクティブプログラミングの歴史において、Knockout observablesやMeteor Tracker、RxJSのようなライブラリが基礎を築いていました。状態管理ライブラリであるMobX2やXStateも、背後では同様の原理に基づいてオブジェクトのプロパティの変化を監視し、関連する部分を更新していました。

これらの先駆的な技術を背景に、現代の主要なフロントエンドフレームワークは、より洗練されたリアクティビティの仕組みをコア機能として取り込むようになりました。

Push型、Pull型、Push-Pull型

リアクティブプログラミングにおいては、状態の変化を依存している部分にどのように伝えるかによって、主にPush型、Pull型、Push-Pull型に分類できます。次にそれぞれの特徴を見ていきます。

Push型

Pull型

Push-Pull型

近年ではPull型やPush-Pull型のアプローチが、パフォーマンスと効率性の観点から多くのリアクティブプログラミングで採用される傾向にあります。これにより、不要な計算を避け、必要な時だけ最新の状態を反映させることが可能になり、よりスムーズなアプリケーション体験を提供できます。

Signalsというインターフェイス

リアクティブプログラミングにおいて近年注目を集めているのが、「Signals(シグナル)」 というインターフェイスです。Signalsの基本的な機能は以下のとおりです。

それぞれのAPIは異なりますが、Solidをはじめ、AngularPreactQwikSvelte 5からのリアクティビティ(Runes)など、多くのモダンなフレームワークがSignalsを採用しています。

Vue.jsでのComposition APIである ref も、Signalsと似た概念として設計されています。PreactとQwikでは shallowRef と似たような形で設計されております(.value プロパティでアクセス、値を通じて作用している部分)。SolidとAngularは異なるAPIを提供していますが、いずれも shallowRef を活用して再現できます。詳しくはAPI 設計のトレードオフの章をご参照してください。

alien-signalsとは?

alien-signalsのロゴ

このようなSignalsの潮流の中で登場したのが alien-signals です。alien-signalsは、非常に軽量なリアクティブライブラリであることを特徴としています。

https://github.com/stackblitz/alien-signals

このライブラリが生まれた背景として、作者であるJohnson氏がVue 3.4のリアクティビティシステムの最適化に関わったことが挙げられます。その後、Vue 3.5がPreactに似たPull型のアルゴリズムに切り替わったことを受け、Vue.jsとは別のリアクティビティライブラリを研究しはじめたことが、alien-signalsの開発のきっかけとなりました。

このライブラリではPush-Pull型を採用しています。さらにVue 3.6からはalien-signalsの実装がリアクティブプログラミングの基盤として取り入れられることになりました。

alien-signalsの特徴

値を保持する signal、算出された値として計算する computed、リアクティブな処理を定義する effect、そして effect の有効範囲を管理する effectScope など、Signalsの基本的なAPIを提供しています。

import { signal, computed, effect } from 'alien-signals';

const count = signal(1);
const doubleCount = computed(() => count() * 2);

effect(() => {
  console.log(`Count is: ${count()}`);
}); // Console: Count is: 1

console.log(doubleCount()); // 2

count(2); // Console: Count is: 2

console.log(doubleCount()); // 4

signal でリアクティブな値 count を作成し、effect 内でその値を監視しています。count の値が変更されると、effect 内の処理が自動的に再実行されます。

import { signal, effect, effectScope } from 'alien-signals';

const count = signal(1);

const stopScope = effectScope(() => {
  effect(() => {
    console.log(`Count in scope: ${count()}`);
  }); // Console: Count in scope: 1
});

count(2); // Console: Count in scope: 2

stopScope();

count(3); // No console output

effectScope を使うことで、effect のライフサイクルを管理できます。

内部の処理では、propagate 関数による変更の伝播、checkDirty 関数によるダーティチェックなど、再帰呼び出しを避けるための最適化が施されており、効率的な更新を実現しています。

また、createReactiveSystem() を使うことで、alien-signalsのコアアルゴリズムを再利用して、独自のSignals APIの構築も可能です。

const system = createReactiveSystem({
  updateComputed(computed: Computed) {
    return computed.update();
  },
  notifyEffect(watcher: subtle.Watcher) {
    if (watcher.flags & alien.SubscriberFlags.Dirty) {
      watcher.run();
      return true;
    }
    return false;
  },
});

派生プロジェクト

alien-signalsは、現在さまざまなフレームワークや言語で派生して実装が進められています。2025年3月時点での派生プロジェクトは以下の通りです。

TC39への標準化提案

Signalsは、現在Ecma Internationalの技術委員会39(通称TC39)にてECMAScriptでの標準化提案が進められています。現在はStage 1(Proposal)になります。

https://github.com/tc39/proposal-signals

Signalsの仕様提案の推進者には、BloombergのDaniel Ehrenberg氏、Emberの開発者であるYehuda Katz氏、Google社内で使用されるWizフレームワークのメンテナのJatin Ramanathan氏、SvelteメンテナのDominic Gannaway氏などが名を連ねています。

alien-signalsのようなライブラリや各フレームワークによるSignalsの実装がより浸透していくと、この標準化の動きをさらに加速させる可能性があります。将来的には、JavaScriptの標準APIとしてSignalsが利用できるようになれば、アプリケーション側はSignalsを採用するために変更を加える必要はなくなります。また、複数のマイクロフロントエンドで共通のデータ層を共有する場合などに役立つとされています。

まとめ

宣伝: Vue.js v-tokyo Meetup #22

Vue.js日本ユーザーグループが主催する「Vue.js v-tokyo Meetup #22」では、alien-signalsのメジャーリリースを記念して、Webフロントエンドフレームワークのリアクティビィティについてキャッチアップできるイベントが3/28に開催されます。

Vue.js v-tokyo Meetup #22 - connpass

alien-signalsやVue.jsについてはもちろん、PreactやAngular、Svelteなどのフレームワークにおけるリアクティブについても学ぶことができる貴重な機会です。ぜひご参加ください!

謝辞

本記事は、NotebookLM Plusにより関連情報の要約・整理をしてもらい作成されました。本記事のレビューについてはubugeeeiさん、ナイトウさん、GANGANさんよりしていただけました。感謝申し上げます。

参考情報

脚注

  1. Observer

  2. The fundamental principles behind MobX | HackerNoon

  3. Autotracking In-Depth - In-Depth Topics - Ember Guides

  4. https://v2.vuejs.org/v2/guide/reactivity

  5. https://vuejs.org/guide/extras/reactivity-in-depth.html

アーカイブ記事のため、内容に関する更新依頼は受け付けておりませんが、誤字や脱字などありましたらご連絡ください。

この記事に関する修正依頼
トップへ戻る