首页 > 其他分享 >[Signal] 2- Cleanup subscriptions

[Signal] 2- Cleanup subscriptions

时间:2023-10-06 15:22:40浏览次数:42  
标签:execute const observer subscriptions Signal effect Cleanup createSignal

 

We have a basic version of signal:

const stack = []

export function createSignal(value) {
  const subscribers = new Set();
  const read = () => {
    // check is there any effect runnning?
    // if yes, then add to subscribers
    const observer = stack[stack.length - 1];
    if (observer) {
      subscribers.add(observer);
    }
    return value;
  };
  const write = (newValue) => {
    value = newValue;
    // notify all the subscribers there is changes
    for (const observer of subscribers) {
      // add effect to the stack again
      observer.execute();
    }
  };
  return [read, write];
}

export function createEffect(fn) {
    const effect = {
       execute() {
           stack.push(effect);
           fn();
           stack.pop();
       }
    };
    
    effect.execute();
}

 

One problem of current version is that, subscriptions are not cleanup. Therefore it might be triggered when not necessary.

import { createSignal, createEffect } from "./reactive";

const [count, setCount] = createSignal(0);
const [count2, setCount2] = createSignal(2);
const [show, setShow] = createSignal(true);

createEffect(() => {
  if (show()) console.log(count());
  else console.log(count2());
}); 

setShow(false);
setCount(10);

// 0
// 2
// 2

It logs 2 twice. Which is a signals cleanup is missing.

 

Version 3: with cleanup

In previous version, signals knows effect, but effect doesn't know signals.

We need to link bidirectional.

export function createEffect(fn) {
  const effect = {
    execute() {
      context.push(effect);
      fn();
      context.pop();
    },
    dependencies: new Set(), // add dependencies to link to signals
  };

  effect.execute();
}

 

When read from signals, we need to not only link effect to signals, but also link signals to effect:

function subscribe(observer, subscriptions) {
    subscriptions.add(observer)
    observer.dependencies.add(subscriptions)
}

export function createSignal(value) {
  const subscriptions = new Set();

  const read = () => {
    const observer = context[context.length - 1];
    if (observer) subscribe(observer, subscriptions); // link bidirectional
    return value;
  };
  const write = (newValue) => {
    value = newValue;
    for (const observer of [...subscriptions]) { // need to use [...subscriptions] to make a copy to avoid infinte loop
      observer.execute();
    }
  };

  return [read, write];
}

 

Write cleanup:

function cleanup(observer) {
  for (const dep of observer.dependencies) {
    dep.delete(observer);
  }
}

export function createEffect(fn) {
  const effect = {
    execute() {
      cleanup(effect); // call cleanup before next effect start
      context.push(effect);
      fn();
      context.pop();
    },
    dependencies: new Set(),
  };

  effect.execute();
}

 

---FULL CODE---

const context = [];

function cleanup(observer) {
  for (const dep of observer.dependencies) {
    dep.delete(observer);
  }
}

function subscribe(observer, subscriptions) {
  subscriptions.add(observer);
  observer.dependencies.add(subscriptions);
}

export function createSignal(value) {
  const subscriptions = new Set();

  const read = () => {
    const observer = context[context.length - 1];
    if (observer) subscribe(observer, subscriptions);
    return value;
  };
  const write = (newValue) => {
    value = newValue;
    for (const observer of [...subscriptions]) {
      observer.execute();
    }
  };

  return [read, write];
}

export function createEffect(fn) {
  const effect = {
    execute() {
      cleanup(effect);
      context.push(effect);
      fn();
      context.pop();
    },
    dependencies: new Set(),
  };

  effect.execute();
}

Test code:

import { createSignal, createEffect } from "./reactive";

const [count, setCount] = createSignal(0);
const [count2, setCount2] = createSignal(2);
const [show, setShow] = createSignal(true);

createEffect(() => {
  if (show()) console.log(count());
  else console.log(count2());
}); 

setShow(false);
setCount(10);

// 0
// 2

 

标签:execute,const,observer,subscriptions,Signal,effect,Cleanup,createSignal
From: https://www.cnblogs.com/Answer1215/p/17744602.html

相关文章

  • [Signal] 1 - Basic version of signal
    ImplementtwofunctionsofSignalscreateSignal:returnatuplewithreadfunctionandwrtiefunctioncreateEffect:acceptafunctionwhichwillbeexecutedwhensignalvaluechanged Codetotest:import{createSignal}from"./reactivy";......
  • EarthChat SignalR原理讲解
    SignalR原理讲解SignalR是什么?SignalR是Microsoft开发的一个库,用于ASP.NET开发人员实现实时web功能。这意味着服务端代码可以实时地推送内容到连接的客户端,而不需要客户端定期请求或轮询服务器以获取新数据。SignalR可以用于各种应用程序,如实时聊天、通知、实时数据更新......
  • RabbitMQ报错:Shutdown Signal: channel error; protocol method
    ShutdownSignal:channelerror;protocolmethod:#method<channel.close>(reply-code=406,reply-text=PRECONDITION_FAILED-unknowndeliverytag1,class-id=60,method-id=80)默认情况下RabbitMQ是自动ACK(确认签收)机制,就意味着MQ会在消息发送完毕后,自动帮我们去AC......
  • pyside 信号(Signal)和槽(Slot)以及装饰器 Property和setter
    1.Property的使用classBackend(QObject):def__init__(self)->None:super().__init__()self._hello='hello_world'@Property(str)defhello(self):returnself._helloqml:text:backend.hello2.Slot函数方法@Slo......
  • 基于SqlSugar的开发框架循序渐进介绍(25)-- 基于SignalR实现多端的消息通讯
    基于ASP.NETCoreSignalR可以实现客户端和服务器之间进行即时通信。本篇随笔介绍一些SignalR的基础知识,以及结合对SqlSugar的开发框架的支持,实现SignalR的多端处理整合,从而实现Winform客户端,基于Vue3+ElementPlus的BS端整合,后面也可以实现对移动端的SignalR的整合通讯。适合Sign......
  • C# SignalR使用
    SignalR简介SignalR是一个开源的库,跨平台;让Web应用与其他应用通讯变得很简单,Web服务端可以实时的将内容推送给对应的客户端,客户端发送的信息也可以实时到其他客户端。SignalR提供了一种远程过程调用(RPC)的方式,使得客户端可以调用服务器的方法,同样在服务器端的方法中也能调用客......
  • 集线器 SignalR.Core 消息推送实例
    SignalR.Core消息推送实例publicclassChatHub:Hub{privatestring_className="ChatHub";//privateSystem.Threading.Timertimer=null;privateSystem.Threading.Timer_timer=null;privatestaticreadonlyobject_lock=newobj......
  • Zeppelin起Spark任务报错:RECEIVED SIGNAL TERM
    Zeppelin起Spark任务报错:RECEIVEDSIGNALTERM解决方法如下所示:调大spark任务资源exportSPARK_SUBMIT_OPTIONS="--driver-memory4G--executor-memory4G--driver-cores2--executor-cores2--num-executors20--confspark.sql.shuffle.partitions=1000--confspark.......
  • P9189 [USACO23OPEN] Custodial Cleanup G 题解
    Description奶牛旅馆可以被看作一个\(N\)个节点\(M\)条边的无向简单图,其中每个房间有一个颜色\(C_i\),以及一个钥匙,颜色为\(S_i\),FJ最初在\(1\)号节点,手上一把钥匙都没有。FJ可以进行无数次以下操作:捡起当前房间的钥匙。(FJ可以同时手持多个钥匙)将部分或全部手......
  • appium运行报错UiAutomator exited unexpectedly with code 0, signal null
    增加配置desired_caps['automationName']="UiAutomator2"再次运行后,正常 ......