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. 最佳实践和设计模式

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


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

终身学习,共同成长。

咱们下一期见

💻

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/8405.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

递归搜索回溯综合练习(十五题)

目录 1.找出所有子集的异或总和再求和 2.全排列2 3.电话号码的字母组合 4.括号生成 5.组合 6.目标和 1.path作为全局变量 2.path用于传参 7.组合总和 方法一&#xff1a;按照每个空选什么数字进行递归 方法二&#xff1a;按照每个数字选几个进行递归 8.字母大小写全排…

JWT实现单点登录

文章目录 JWT实现单点登录JWT 简介存在问题及解决方案登录流程后端程序实现前端保存Tokenstore存放信息的缺点及解决 校验流程&#xff1a;为gateway增加登录校验拦截器 另一种单点登录方法&#xff1a;Token&#xff0b;Redis实现单点登录 JWT实现单点登录 登录流程&#xff…

qt-QtQuick笔记之常见项目类简要介绍

qt-QtQuick笔记之常见项目类简要介绍 code review! 文章目录 qt-QtQuick笔记之常见项目类简要介绍1.QQuickItem2.QQuickRectangle3.QQuickImage4.QQuickText5.QQuickBorderImage6.QQuickTextInput7.QQuickButton8.QQuickSwitch9.QQuickListView10.QQuickGridView11.QQuickPopu…

循环神经网络(RNN)+pytorch实现情感分析

目录 一、背景引入 二、网络介绍 2.1 输入层 2.2 循环层 2.3 输出层 2.4 举例 2.5 深层网络 三、网络的训练 3.1 训练过程举例 1&#xff09;输出层 2&#xff09;循环层 3.2 BPTT 算法 1&#xff09;输出层 2&#xff09;循环层 3&#xff09;算法流程 四、循…

Autosar-Os是怎么运行的?(多核系统运行)

写在前面&#xff1a; 入行一段时间了&#xff0c;基于个人理解整理一些东西&#xff0c;如有错误&#xff0c;欢迎各位大佬评论区指正&#xff01;&#xff01;&#xff01; 目录 1.Autosar多核操作系统 1.1多核启动过程 1.2多核运行过程 1.2.1核间任务同步 1.2.2Counte…

【C语言练习题】正弦函数

题目&#xff1a; 根据麦克劳林公式计算正弦值。 输入格式 x ε 注&#xff1a;x 为角(弧度)&#xff0c;ε 为计算精度。 输出格式 y 注&#xff1a;y 为 x 的正弦值&#xff0c;输出 6 位小数。 输入样例1 0.5235987755982989 0.00000001输出样例1 0.500000输入样例2 314.68…

GBase 8a 9.5.3.27 DBlink配置---源端GBase

原理图 1.目标端集群将数据请求由gcluster的5258端口发送至dblink的9898端口 2.Dblink将请求由9898端口转发至源端集群的5258端口 3.源端数据库将接收的请求生成执行计划&#xff0c;由gcluster的5258端口下发至各gnode的5050端口 4.源端的5050端口接收到执行计划进行查询&…

二次封装的方法

二次封装 我们开发中经常需要封装一些第三方组件&#xff0c;那么父组件应该怎么传值&#xff0c;怎么调用封装好的组件原有的属性、插槽、方法&#xff0c;一个个调用虽然可行&#xff0c;但十分麻烦&#xff0c;我们一起来看更简便的方法。 二次封装组件&#xff0c;属性怎…

*胡闹厨房*

前期准备 详细教程 一、创建项目 1、选择Universal 3D,创建项目 2、删除预制文件Readme:点击Remove Readme Assets,弹出框上点击Proceed 3、Edit-Project Setting-Quality,只保留High Fidelity 4、打开 Assets-Settings ,保留URP-HighFidelity-Renderer 和 URP-High…

Effective Objective-C 2.0 读书笔记—— objc_msgSend

Effective Objective-C 2.0 读书笔记—— objc_msgSend 文章目录 Effective Objective-C 2.0 读书笔记—— objc_msgSend引入——静态绑定和动态绑定OC之中动态绑定的实现方法签名方法列表 其他方法objc_msgSend_stretobjc_msgSend_fpretobjc_msgSendSuper 尾调用优化总结参考文…

Three.js实战项目02:vue3+three.js实现汽车展厅项目

文章目录 实战项目02项目预览项目创建初始化项目模型加载与展厅灯光加载汽车模型设置灯光材质设置完整项目下载实战项目02 项目预览 完整项目效果: 项目创建 创建项目: pnpm create vue安装包: pnpm add three@0.153.0 pnpm add gsap初始化项目 修改App.js代码&#x…

Elasticsearch 性能测试工具 Loadgen 之 001——部署及应用详解

在现代软件开发中&#xff0c;性能测试是确保应用程序稳定性和响应速度的关键环节。 今天&#xff0c;我们就来深入了解一款国产化功能强大的 Elasticsearch 负载测试工具——INFINI Loadgen。 一、INFINI Loadgen 简介 Github地址&#xff1a;https://github.com/infinilabs/l…

Python从0到100(八十五):神经网络-使用迁移学习完成猫狗分类

前言: 零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、 计算机视觉、机器学习、神经网络以及人工智能…

(1)SpringBoot入门+彩蛋

SpringBoot 官网(中文)&#xff1a;Spring Boot 中文文档 Spring Boot是由Pivotal团队提供的一套开源框架&#xff0c;可以简化spring应用的创建及部署。它提供了丰富的Spring模块化支持&#xff0c;可以帮助开发者更轻松快捷地构建出企业级应用。Spring Boot通过自动配置功能…

C语言从入门到进阶

视频&#xff1a;https://www.bilibili.com/video/BV1Vm4y1r7jY?spm_id_from333.788.player.switch&vd_sourcec988f28ad9af37435316731758625407&p23 //枚举常量 enum Sex{MALE,FEMALE,SECRET };printf("%d\n", MALE);//0 printf("%d\n", FEMALE…

MacOS安装Docker battery-historian

文章目录 需求安装battery-historian实测配置国内源相关文章 需求 分析Android电池耗电情况、唤醒、doze状态等都要用battery-historian&#xff0c; 在 MacOS 上安装 battery-historian&#xff0c;可以使用 Docker 进行安装runcare/battery-historian:latest。装完不需要做任…

公式与函数的应用

一 相邻表格相乘 1 也可以复制 打印标题

DeepSeek学术写作测评第二弹:数据分析、图表解读,效果怎么样?

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 针对最近全球热议的DeepSeek开源大模型&#xff0c;娜姐昨天分析了关于论文润色、中译英的详细效果测评&#xff1a; DeepSeek学术写作测评第一弹&#xff1a;论文润色&#…

MongoDB平替数据库对比

背景 项目一直是与实时在线监测相关&#xff0c;特点数据量大&#xff0c;读写操作大&#xff0c;所以选用的是MongoDB。但按趋势来讲&#xff0c;需要有一款国产数据库可替代&#xff0c;实现信创要求。选型对比如下 1. IoTDB 这款是由清华大学主导的开源时序数据库&#x…

动手学深度学习-卷积神经网络-3填充和步幅

目录 填充 步幅 小结 在上一节的例子&#xff08;下图&#xff09; 中&#xff0c;输入的高度和宽度都为3&#xff0c;卷积核的高度和宽度都为2&#xff0c;生成的输出表征的维数为22。 正如我们在 上一节中所概括的那样&#xff0c;假设输入形状为nhnw&#xff0c;卷积核形…