当前位置: 首页 > news >正文

JavaScript系列(45)--响应式编程实现详解

JavaScript响应式编程实现详解 🔄

今天,让我们深入探讨JavaScript的响应式编程实现。响应式编程是一种基于数据流和变化传播的编程范式,它使我们能够以声明式的方式处理异步数据流。

响应式编程基础概念 🌟

💡 小知识:响应式编程的核心是将所有事物都视为数据流,包括变量、用户输入、网络请求等。通过对这些数据流进行组合和转换,我们可以以声明式的方式处理复杂的异步操作。

基本实现 📊

// 1. 基础Observable实现
class Observable {constructor(subscribe) {this.subscribe = subscribe;}// 静态创建方法static from(value) {return new Observable(observer => {if (Array.isArray(value)) {value.forEach(item => observer.next(item));observer.complete();} else {observer.next(value);observer.complete();}return () => {}; // 清理函数});}static fromEvent(target, eventName) {return new Observable(observer => {const handler = event => observer.next(event);target.addEventListener(eventName, handler);return () => target.removeEventListener(eventName, handler);});}// 转换操作符map(fn) {return new Observable(observer => {return this.subscribe({next: value => observer.next(fn(value)),error: err => observer.error(err),complete: () => observer.complete()});});}filter(predicate) {return new Observable(observer => {return this.subscribe({next: value => {if (predicate(value)) {observer.next(value);}},error: err => observer.error(err),complete: () => observer.complete()});});}
}// 2. Subject实现
class Subject extends Observable {constructor() {super();this.observers = new Set();}next(value) {this.observers.forEach(observer => observer.next(value));}error(error) {this.observers.forEach(observer => observer.error(error));}complete() {this.observers.forEach(observer => observer.complete());}subscribe(observer) {this.observers.add(observer);return {unsubscribe: () => {this.observers.delete(observer);}};}
}// 3. BehaviorSubject实现
class BehaviorSubject extends Subject {constructor(initialValue) {super();this._value = initialValue;}get value() {return this._value;}next(value) {this._value = value;super.next(value);}subscribe(observer) {observer.next(this._value);return super.subscribe(observer);}
}

高级操作符实现 🚀

// 1. 组合操作符
class OperatorFactory {// 合并多个Observablestatic merge(...observables) {return new Observable(observer => {const subscriptions = observables.map(obs =>obs.subscribe({next: value => observer.next(value),error: err => observer.error(err)}));return () => {subscriptions.forEach(sub => sub.unsubscribe());};});}// 连接多个Observablestatic concat(...observables) {return new Observable(observer => {let currentIndex = 0;let currentSubscription = null;function subscribeNext() {if (currentIndex >= observables.length) {observer.complete();return;}currentSubscription = observables[currentIndex].subscribe({next: value => observer.next(value),error: err => observer.error(err),complete: () => {currentIndex++;subscribeNext();}});}subscribeNext();return () => {if (currentSubscription) {currentSubscription.unsubscribe();}};});}// 组合最新值static combineLatest(...observables) {return new Observable(observer => {const values = new Array(observables.length);const hasValue = new Array(observables.length).fill(false);const subscriptions = observables.map((obs, index) =>obs.subscribe({next: value => {values[index] = value;hasValue[index] = true;if (hasValue.every(Boolean)) {observer.next([...values]);}},error: err => observer.error(err)}));return () => {subscriptions.forEach(sub => sub.unsubscribe());};});}
}// 2. 时间操作符
class TimeOperators {// 延迟发送static delay(time) {return observable => new Observable(observer => {return observable.subscribe({next: value => {setTimeout(() => observer.next(value), time);},error: err => observer.error(err),complete: () => observer.complete()});});}// 节流static throttleTime(time) {return observable => new Observable(observer => {let lastTime = 0;return observable.subscribe({next: value => {const now = Date.now();if (now - lastTime >= time) {lastTime = now;observer.next(value);}},error: err => observer.error(err),complete: () => observer.complete()});});}// 防抖static debounceTime(time) {return observable => new Observable(observer => {let timeoutId = null;return observable.subscribe({next: value => {if (timeoutId !== null) {clearTimeout(timeoutId);}timeoutId = setTimeout(() => {observer.next(value);timeoutId = null;}, time);},error: err => observer.error(err),complete: () => observer.complete()});});}
}// 3. 错误处理操作符
class ErrorOperators {// 重试static retry(count) {return observable => new Observable(observer => {let retries = 0;let subscription = null;function subscribe() {subscription = observable.subscribe({next: value => observer.next(value),error: err => {if (retries < count) {retries++;subscribe();} else {observer.error(err);}},complete: () => observer.complete()});}subscribe();return () => {if (subscription) {subscription.unsubscribe();}};});}// 错误恢复static catchError(selector) {return observable => new Observable(observer => {return observable.subscribe({next: value => observer.next(value),error: err => {try {const result = selector(err);result.subscribe(observer);} catch (e) {observer.error(e);}},complete: () => observer.complete()});});}
}

实际应用场景 💼

// 1. 表单验证
class ReactiveForm {constructor() {this.formData = new BehaviorSubject({});this.errors = new BehaviorSubject({});}// 设置表单值setValue(field, value) {const currentData = this.formData.value;this.formData.next({...currentData,[field]: value});this.validate(field, value);}// 添加验证规则addValidation(field, rules) {const formStream = this.formData.pipe(map(data => data[field]),filter(value => value !== undefined));formStream.subscribe(value => {const fieldErrors = [];rules.forEach(rule => {const error = rule(value);if (error) {fieldErrors.push(error);}});const currentErrors = this.errors.value;this.errors.next({...currentErrors,[field]: fieldErrors});});}
}// 2. 实时搜索
class ReactiveSearch {constructor(inputElement) {this.searchInput = Observable.fromEvent(inputElement, 'input').pipe(map(event => event.target.value),debounceTime(300),filter(text => text.length >= 2));}onSearch(callback) {return this.searchInput.subscribe({next: async text => {try {const results = await this.performSearch(text);callback(null, results);} catch (error) {callback(error);}}});}async performSearch(text) {// 实现搜索逻辑}
}// 3. WebSocket实时数据
class ReactiveWebSocket {constructor(url) {this.messages = new Subject();this.ws = new WebSocket(url);this.ws.onmessage = event => {this.messages.next(JSON.parse(event.data));};this.ws.onerror = error => {this.messages.error(error);};this.ws.onclose = () => {this.messages.complete();};}send(data) {this.ws.send(JSON.stringify(data));}close() {this.ws.close();}
}

性能优化技巧 ⚡

// 1. 共享订阅
class ShareOperator {static share() {return observable => {const subject = new Subject();let refCount = 0;let subscription = null;return new Observable(observer => {refCount++;if (!subscription) {subscription = observable.subscribe(subject);}const sub = subject.subscribe(observer);return () => {refCount--;sub.unsubscribe();if (refCount === 0 && subscription) {subscription.unsubscribe();subscription = null;}};});};}
}// 2. 缓存优化
class CacheOperator {static cache(maxSize = 100) {return observable => {const cache = new Map();return new Observable(observer => {return observable.subscribe({next: value => {if (cache.size >= maxSize) {const firstKey = cache.keys().next().value;cache.delete(firstKey);}cache.set(Date.now(), value);observer.next(value);},error: err => observer.error(err),complete: () => observer.complete()});});};}
}// 3. 批处理优化
class BatchOperator {static bufferCount(count) {return observable => new Observable(observer => {let buffer = [];return observable.subscribe({next: value => {buffer.push(value);if (buffer.length >= count) {observer.next(buffer);buffer = [];}},error: err => observer.error(err),complete: () => {if (buffer.length > 0) {observer.next(buffer);}observer.complete();}});});}
}

最佳实践建议 💡

  1. 响应式设计模式
// 1. 观察者模式
class ObserverPattern {// 创建可观察的状态static createObservableState(initialState) {return new BehaviorSubject(initialState);}// 创建派生状态static createDerivedState(source, transform) {return source.pipe(map(transform),distinctUntilChanged());}
}// 2. 响应式状态管理
class ReactiveStore {constructor(initialState = {}) {this.state = new BehaviorSubject(initialState);this.actions = new Subject();this.actions.subscribe(action => {const currentState = this.state.value;const newState = this.reducer(currentState, action);this.state.next(newState);});}dispatch(action) {this.actions.next(action);}select(selector) {return this.state.pipe(map(selector),distinctUntilChanged());}
}// 3. 响应式数据绑定
class ReactiveBinding {static bindInput(input, subject) {const subscription = Observable.fromEvent(input, 'input').pipe(map(event => event.target.value)).subscribe(value => subject.next(value));subject.subscribe(value => {input.value = value;});return subscription;}
}

结语 📝

响应式编程为处理异步数据流提供了强大而优雅的解决方案。通过本文,我们学习了:

  1. 响应式编程的基本概念和实现
  2. 高级操作符的实现原理
  3. 实际应用场景和示例
  4. 性能优化技巧
  5. 最佳实践和设计模式

💡 学习建议:在使用响应式编程时,要注意内存管理和取消订阅。合理使用操作符组合,避免过度复杂的数据流。同时,要考虑错误处理和边界情况。


如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

相关文章:

JavaScript系列(45)--响应式编程实现详解

JavaScript响应式编程实现详解 &#x1f504; 今天&#xff0c;让我们深入探讨JavaScript的响应式编程实现。响应式编程是一种基于数据流和变化传播的编程范式&#xff0c;它使我们能够以声明式的方式处理异步数据流。 响应式编程基础概念 &#x1f31f; &#x1f4a1; 小知识…...

Lustre Core 语法 - 布尔表达式

Lustre v6 中的 Lustre Core 部分支持的表达式种类中&#xff0c;支持布尔表达式。相关的表达式包括and, or, xor, not, #, nor。 相应的文法定义为 Expression :: not Expression| Expression and Expression| Expression or Expression | Expression xor Expression | # (…...

python学opencv|读取图像(四十六)使用cv2.bitwise_or()函数实现图像按位或运算

【0】基础定义 按位与运算&#xff1a;全1取1&#xff0c;其余取0。按位或运算&#xff1a;全0取0&#xff0c;其余取1。 【1】引言 前序学习进程中&#xff0c;已经对图像按位与计算进行了详细探究&#xff0c;相关文章链接如下&#xff1a; python学opencv|读取图像&…...

C# 添加、替换、提取、或删除Excel中的图片

在Excel中插入与数据相关的图片&#xff0c;能将关键数据或信息以更直观的方式呈现出来&#xff0c;使文档更加美观。此外&#xff0c;对于已有图片&#xff0c;你有事可能需要更新图片以确保信息的准确性&#xff0c;或者将Excel 中的图片单独保存&#xff0c;用于资料归档、备…...

工作总结:压测篇

前言 压测是测试需要会的一项技能&#xff0c;作为开发&#xff0c;有点时候也要会一点压测。也是被逼着现学现卖的。 一、压测是什么&#xff0c;以及压测工具的选择 压测&#xff0c;即压力测试&#xff0c;是一种性能测试手段&#xff0c;通过模拟大量用户同时访问系统&am…...

11JavaWeb——SpringBootWeb案例02

前面我们已经实现了员工信息的条件分页查询以及删除操作。 关于员工管理的功能&#xff0c;还有两个需要实现&#xff1a; 新增员工 修改员工 首先我们先完成"新增员工"的功能开发&#xff0c;再完成"修改员工"的功能开发。而在"新增员工"中…...

vs2022+tesseract ocr识别中英文 编译好的库下载

测试图片 效果 编译其实挺麻烦的&#xff0c;可参考&#xff1a;在Windows上用Visual Studio编译Tesseract_windows编译tesseract-CSDN博客 #include "baseapi.h" #include "allheaders.h" #include <iostream> #include <fstream> // 用于文…...

状态模式——C++实现

目录 1. 状态模式简介 2. 代码示例 3. 单例状态对象 4. 状态模式与策略模式的辨析 1. 状态模式简介 状态模式是一种行为型模式。 状态模式的定义&#xff1a;状态模式允许对象在内部状态改变时改变它的行为&#xff0c;对象看起来好像修改了它的类。 通俗的说就是一个对象…...

3.观察者模式(Observer)

组件协作模式 现代软件专业分工之后的第一个结果是 “框架与应用程序的划分”,“组件协作” 模式通过晚期绑定&#xff0c;来实现框架与应用程序直接的松耦合&#xff0c;是二者之间协作时常用的模式 典型模式 Template Method Strategy Observer /Event 动机&#xff08;M…...

Kotlin判空辅助工具

1&#xff09;?.操作符 //执行逻辑 if (person ! null) {person.doSomething() } //表达式 person?.doSomething() 2&#xff09;?:操作符 //执行逻辑 val c if (a ! null) {a } else {b } //表达式 val c a ?: b 3&#xff09;!!表达式 var message: String? &qu…...

Electron学习笔记,安装环境(1)

1、支持win7的Electron 的版本是18&#xff0c;这里node.js用的是14版本&#xff08;node-v14.21.3-x86.msi&#xff09;云盘有安装包 Electron 18.x (截至2023年仍在维护中): Chromium: 96 Node.js: 14.17.0 2、安装node环境&#xff0c;node-v14.21.3-x86.msi双击运行选择安…...

将 OneLake 数据索引到 Elasticsearch - 第 1 部分

作者&#xff1a;来自 Elastic Gustavo Llermaly 学习配置 OneLake&#xff0c;使用 Python 消费数据并在 Elasticsearch 中索引文档&#xff0c;然后运行语义搜索。 OneLake 是一款工具&#xff0c;可让你连接到不同的 Microsoft 数据源&#xff0c;例如 Power BI、Data Activ…...

【C++】STL介绍 + string类使用介绍 + 模拟实现string类

目录 前言 一、STL简介 二、string类 1.为什么学习string类 2.标准库中的string类 3.auto和范围for 4.迭代器 5.string类的常用接口说明 三、模拟实现 string类 前言 本文带大家入坑STL&#xff0c;学习第一个容器string。 一、STL简介 在学习C数据结构和算法前&#xff0c;我…...

Hive:基本查询语法

和oracle一致的部分 和oracle不一样的部分 排序 oracle中,在升序排序中&#xff0c;NULL 值被视为最大的值&#xff1b;在降序排序中&#xff0c;NULL 值被视为最小的值。 在MySQL中&#xff0c;NULL 被视为小于任何非空值。 在Hive中, NULL是最小的; Hive除了可以用order…...

日志收集Day008

1.zk集群优化 修改zookeeper的堆内存大小&#xff0c;一般情况下&#xff0c;生产环境给到2G足以&#xff0c;如果规模较大可以适当调大到4G。 (1)配置ZK的堆内存 vim /app/softwares/zk/conf/java.env export JAVA_HOME/sortwares/jdk1.8.0_291 export JVMFLAGS"-Xms2…...

【解决方案】VMware虚拟机adb连接宿主机夜神模拟器

1、本机&#xff08;宿主机&#xff0c;系统windows10&#xff09;ip为192.168.31.108 2、运行模拟器后本机cmd查看端口为62026 3、VMware虚拟机&#xff08;系统&#xff0c;kali&#xff09;adb连接192.168.31.108:62026报错 failed to connect to 192.168.31.108:16416: Co…...

基于金融新闻的大型语言模型强化学习在投资组合管理中的应用

“Financial News-Driven LLM Reinforcement Learning for Portfolio Management” 论文地址&#xff1a;https://arxiv.org/pdf/2411.11059 摘要 本研究探索了如何通过将大语言模型&#xff08;LLM&#xff09;支持的情感分析融入强化学习&#xff08;RL&#xff09;中&#…...

脚本运行禁止:npm 无法加载文件,因为在此系统上禁止运行脚本

问题与处理策略 1、问题描述 npm install -D tailwindcss执行上述指令&#xff0c;报如下错误 npm : 无法加载文件 D:\nodejs\npm.ps1&#xff0c;因为在此系统上禁止运行脚本。 有关详细信息&#xff0c;请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的 about_…...

借DeepSeek-R1东风,开启创业新机遇

DeepSeek-R1的崛起 DeepSeek-R1的推出引发了广泛关注&#xff0c;在AI领域引起了一阵旋风。作为新一代的智能模型&#xff0c;它在多项任务中表现出了卓越的能力。普通人可以借助这个强大的工具&#xff0c;开启属于自己的创业之路&#xff0c;抓住时代带来的机遇。 内容创作…...

C# lock使用详解

总目录 前言 在 C# 多线程编程中&#xff0c;lock 关键字是一种非常重要的同步机制&#xff0c;用于确保同一时间只有一个线程可以访问特定的代码块&#xff0c;从而避免多个线程同时操作共享资源时可能出现的数据竞争和不一致问题。以下是关于 lock 关键字的详细使用介绍。 一…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...