响应式编程

#响应式系统 #响应式编程 #Reactivity

Review

  1. 2024-08-25 20:05

[!Summary] 响应式编程是一种编程范式,专注于数据流和变化的传播 适用场景:处理大规模数据、实时分析、处理复杂用户界面逻辑、处理异步和事件驱动场景

一、Introduction #

Reactivity powers the interactivity in Solid applications. This programming paradigm refers to a system’s ability to respond to changes in data or state automatically.

  1. Reactivity keeps the user interface (UI) and state in sync, which reduces the need for manual updates.
  2. Real-time updates create a more responsive and interactive user experience.

响应式编程(Reactive Programming)是一种编程范式,专注于数据流和变化的传播。它允许我们以声明式的方式处理异步数据流,使得程序能够自动对数据的变化做出反应。

a) 数据流:在响应式编程中,一切都可以被视为数据流,包括变量、用户输入、属性、缓存、数据结构等。 b) 观察者模式:响应式编程大量使用观察者模式,允许对象(观察者)自动接收它们感兴趣的对象(可观察对象)的通知。 c) 声明式:开发者声明数据之间的关系,而不是命令式地指定如何更新数据。

特征 a) 异步处理:能够优雅地处理异步事件和数据流。 b) 数据流转换:提供丰富的操作符来转换、组合、过滤数据流。 c) 错误处理:内置错误处理机制,使得异步错误处理变得简单。 d) 状态管理:简化了状态管理,特别是在复杂的用户界面中。

响应式更新(Reactive Updates)

  • 这是一个广义的概念,指的是当数据发生变化时,相关的UI或计算结果能够自动更新。
  • 它是响应式编程的核心思想,目的是使应用程序能够自动对变化做出反应,而不需要手动操作DOM或重新计算。

响应式更新 #

策略/目标 细粒度更新(Fine-grained Updates)是指系统能够精确地识别和更新只有那些真正受到数据变化影响的最小部分,而不是对整个组件或大块区域进行不必要的重新渲染。 价值:可以自动追踪依赖

Reactivity ensures automatic responses to data changes, eliminating the need for manual updates to the user interface (UI). By connecting UI elements to the underlying data, updates become automated. In a fine-grained reactive system an application will now have the ability to make highly targeted and specific updates. – solid

实现方案

  1. 观察者模式(Observer Pattern)
  2. 发布订阅模式(Pub-Sub Pattern)
  3. 脏检查(Dirty Checking)
  4. 数据绑定:单向绑定,双向绑定
  5. Proxy/Object.defineProperty
  6. Signal

流行库

  1. RxJS
  2. ReactiveX

Signal #

Signals are the most primary part of a reactive system. They consist of a getter, setter, and a value. Although often referred to as Signals in academic papers, they also have been called Observables, Atoms, Subjects, or Refs.

  • Signal是一种用于实现细粒度响应式更新的编程模式或工具。
  • 它代表一个随时间变化的值,并且可以自动追踪依赖关系。
  • 当Signal的值改变时,所有依赖于它的计算或UI元素都会自动更新。
  • Signal通常提供了一种声明式的方式来定义和使用响应式值。
const [count, setCount] = createSignal(0);

// read a value
console.log(count()); // 0

// set a value
setCount(5);
console.log(count()); //5

Signals alone are not very interesting without their partner in crime, Reactions. Reactions, also called Effects, Autoruns, Watches, or Computeds, observe our Signals and re-run them every time their value updates.

  • Signals are the core elements of a reactive system. They are responsible for storing and managing data.
  • Signals are both readable and writeable because of getters and setters.
  • Subscribers are automated responders that track changes in signals and update the system accordingly.
  • Signals and subscribers work together to ensure that the system is kept up-to-date with the latest data changes.
  • A reactive system is built on the principles of data-driven reactivity. This means that the system’s reactivity is driven by the data it is built on.
  • Reactive systems can be synchronous or asynchronous.

代码示例

type Execute = () => void;
type Effect = {
  execute: Execute;
  deps: Set<Set<Effect>>;
};

// 保存effect调用栈
const effectStack: Effect[] = [];

function subscribe(effect: Effect, subs: Set<Effect>): void {
  //订阅关系建立
  subs.add(effect);
  //依赖关系建立
  effect.deps.add(subs);
}

function cleanup(effect: Effect): void {
  //从该effect订阅的所有state对应subs中移除改effect
  for (const subs of effect.deps) {
    subs.delete(effect);
  }

  //将该effect依赖的所有state对应subs移除
  effect.deps.clear();
}

function useState<T>(value?: T): [() => T | void, (nextValue: T) => void] {
  //保存订阅该state变化的effect
  const subs: Set<Effect> = new Set();

  const getter = (): T | void => {
    //获取当前上下文的effect
    const effect = effectStack[effectStack.length - 1];
    if (effect) {
      subscribe(effect, subs);
    }
    return value;
  };
  const setter = (nextValue: T) => {
    value = nextValue;

    //通知所有订阅该state变化的effect执行
    for (const effect of [...subs]) {
      effect.execute();
    }
  };
  return [getter, setter];
}

function useEffect(callback: () => void) {
  const execute: Execute = () => {
    //重置依赖
    cleanup(effect);

    //将当前effect推入栈顶
    effectStack.push(effect);

    try {
      //执行回调
      callback();
    } finally {
      //effect出栈
      effectStack.pop();
    }
  };

  const effect: Effect = {
    execute,
    deps: new Set(),
  };

  // 立刻执行一次,建立发布订阅关系
  execute();
}

function useMemo<Callback extends () => any>(
  callback: Callback
): Callback | unknown {
  const [s, set] = useState();
  //首次执行callback,建立回调中state的订阅发布关系
  useEffect(() => set(callback));
  return s;
}

Reference #

[[编程范式概览]] # A Hands-on Introduction to Fine-Grained Reactivity Solid # Intro to reactivity Solid # Fine-grained reactivity Understanding Fine-Grained Reactivity Guide