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. 观察者模式
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;}
}
结语 📝
响应式编程为处理异步数据流提供了强大而优雅的解决方案。通过本文,我们学习了:
- 响应式编程的基本概念和实现
- 高级操作符的实现原理
- 实际应用场景和示例
- 性能优化技巧
- 最佳实践和设计模式
💡 学习建议:在使用响应式编程时,要注意内存管理和取消订阅。合理使用操作符组合,避免过度复杂的数据流。同时,要考虑错误处理和边界情况。
如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇
终身学习,共同成长。
咱们下一期见
💻
相关文章:
JavaScript系列(45)--响应式编程实现详解
JavaScript响应式编程实现详解 🔄 今天,让我们深入探讨JavaScript的响应式编程实现。响应式编程是一种基于数据流和变化传播的编程范式,它使我们能够以声明式的方式处理异步数据流。 响应式编程基础概念 🌟 💡 小知识…...
Lustre Core 语法 - 布尔表达式
Lustre v6 中的 Lustre Core 部分支持的表达式种类中,支持布尔表达式。相关的表达式包括and, or, xor, not, #, nor。 相应的文法定义为 Expression :: not Expression| Expression and Expression| Expression or Expression | Expression xor Expression | # (…...
python学opencv|读取图像(四十六)使用cv2.bitwise_or()函数实现图像按位或运算
【0】基础定义 按位与运算:全1取1,其余取0。按位或运算:全0取0,其余取1。 【1】引言 前序学习进程中,已经对图像按位与计算进行了详细探究,相关文章链接如下: python学opencv|读取图像&…...
C# 添加、替换、提取、或删除Excel中的图片
在Excel中插入与数据相关的图片,能将关键数据或信息以更直观的方式呈现出来,使文档更加美观。此外,对于已有图片,你有事可能需要更新图片以确保信息的准确性,或者将Excel 中的图片单独保存,用于资料归档、备…...
工作总结:压测篇
前言 压测是测试需要会的一项技能,作为开发,有点时候也要会一点压测。也是被逼着现学现卖的。 一、压测是什么,以及压测工具的选择 压测,即压力测试,是一种性能测试手段,通过模拟大量用户同时访问系统&am…...
11JavaWeb——SpringBootWeb案例02
前面我们已经实现了员工信息的条件分页查询以及删除操作。 关于员工管理的功能,还有两个需要实现: 新增员工 修改员工 首先我们先完成"新增员工"的功能开发,再完成"修改员工"的功能开发。而在"新增员工"中…...
vs2022+tesseract ocr识别中英文 编译好的库下载
测试图片 效果 编译其实挺麻烦的,可参考:在Windows上用Visual Studio编译Tesseract_windows编译tesseract-CSDN博客 #include "baseapi.h" #include "allheaders.h" #include <iostream> #include <fstream> // 用于文…...
状态模式——C++实现
目录 1. 状态模式简介 2. 代码示例 3. 单例状态对象 4. 状态模式与策略模式的辨析 1. 状态模式简介 状态模式是一种行为型模式。 状态模式的定义:状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。 通俗的说就是一个对象…...
3.观察者模式(Observer)
组件协作模式 现代软件专业分工之后的第一个结果是 “框架与应用程序的划分”,“组件协作” 模式通过晚期绑定,来实现框架与应用程序直接的松耦合,是二者之间协作时常用的模式 典型模式 Template Method Strategy Observer /Event 动机(M…...
Kotlin判空辅助工具
1)?.操作符 //执行逻辑 if (person ! null) {person.doSomething() } //表达式 person?.doSomething() 2)?:操作符 //执行逻辑 val c if (a ! null) {a } else {b } //表达式 val c a ?: b 3)!!表达式 var message: String? &qu…...
Electron学习笔记,安装环境(1)
1、支持win7的Electron 的版本是18,这里node.js用的是14版本(node-v14.21.3-x86.msi)云盘有安装包 Electron 18.x (截至2023年仍在维护中): Chromium: 96 Node.js: 14.17.0 2、安装node环境,node-v14.21.3-x86.msi双击运行选择安…...
将 OneLake 数据索引到 Elasticsearch - 第 1 部分
作者:来自 Elastic Gustavo Llermaly 学习配置 OneLake,使用 Python 消费数据并在 Elasticsearch 中索引文档,然后运行语义搜索。 OneLake 是一款工具,可让你连接到不同的 Microsoft 数据源,例如 Power BI、Data Activ…...
【C++】STL介绍 + string类使用介绍 + 模拟实现string类
目录 前言 一、STL简介 二、string类 1.为什么学习string类 2.标准库中的string类 3.auto和范围for 4.迭代器 5.string类的常用接口说明 三、模拟实现 string类 前言 本文带大家入坑STL,学习第一个容器string。 一、STL简介 在学习C数据结构和算法前,我…...
Hive:基本查询语法
和oracle一致的部分 和oracle不一样的部分 排序 oracle中,在升序排序中,NULL 值被视为最大的值;在降序排序中,NULL 值被视为最小的值。 在MySQL中,NULL 被视为小于任何非空值。 在Hive中, NULL是最小的; Hive除了可以用order…...
日志收集Day008
1.zk集群优化 修改zookeeper的堆内存大小,一般情况下,生产环境给到2G足以,如果规模较大可以适当调大到4G。 (1)配置ZK的堆内存 vim /app/softwares/zk/conf/java.env export JAVA_HOME/sortwares/jdk1.8.0_291 export JVMFLAGS"-Xms2…...
【解决方案】VMware虚拟机adb连接宿主机夜神模拟器
1、本机(宿主机,系统windows10)ip为192.168.31.108 2、运行模拟器后本机cmd查看端口为62026 3、VMware虚拟机(系统,kali)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” 论文地址:https://arxiv.org/pdf/2411.11059 摘要 本研究探索了如何通过将大语言模型(LLM)支持的情感分析融入强化学习(RL)中&#…...
脚本运行禁止:npm 无法加载文件,因为在此系统上禁止运行脚本
问题与处理策略 1、问题描述 npm install -D tailwindcss执行上述指令,报如下错误 npm : 无法加载文件 D:\nodejs\npm.ps1,因为在此系统上禁止运行脚本。 有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的 about_…...
借DeepSeek-R1东风,开启创业新机遇
DeepSeek-R1的崛起 DeepSeek-R1的推出引发了广泛关注,在AI领域引起了一阵旋风。作为新一代的智能模型,它在多项任务中表现出了卓越的能力。普通人可以借助这个强大的工具,开启属于自己的创业之路,抓住时代带来的机遇。 内容创作…...
C# lock使用详解
总目录 前言 在 C# 多线程编程中,lock 关键字是一种非常重要的同步机制,用于确保同一时间只有一个线程可以访问特定的代码块,从而避免多个线程同时操作共享资源时可能出现的数据竞争和不一致问题。以下是关于 lock 关键字的详细使用介绍。 一…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
鸿蒙(HarmonyOS5)实现跳一跳小游戏
下面我将介绍如何使用鸿蒙的ArkUI框架,实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...
高分辨率图像合成归一化流扩展
大家读完觉得有帮助记得关注和点赞!!! 1 摘要 我们提出了STARFlow,一种基于归一化流的可扩展生成模型,它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流(TARFlow&am…...
自定义线程池1.2
自定义线程池 1.2 1. 简介 上次我们实现了 1.1 版本,将线程池中的线程数量交给使用者决定,并且将线程的创建延迟到任务提交的时候,在本文中我们将对这个版本进行如下的优化: 在新建线程时交给线程一个任务。让线程在某种情况下…...
如何让非 TCP/IP 协议驱动屏蔽 IPv4/IPv6 和 ARP 报文?
——从硬件过滤到协议栈隔离的完整指南 引言 在现代网络开发中,许多场景需要定制化网络协议(如工业控制、高性能计算),此时需确保驱动仅处理特定协议,避免被标准协议(如 IPv4/IPv6/ARP)干扰。本文基于 Linux 内核驱动的实现,探讨如何通过硬件过滤、驱动层拦截和协议栈…...
