JavaScript系列(70)--响应式编程进阶详解
JavaScript响应式编程进阶详解 🔄
今天,让我们深入探讨JavaScript响应式编程的进阶内容。响应式编程是一种强大的编程范式,它能够帮助我们更好地处理异步数据流和状态管理。
响应式编程进阶概念 🌟
💡 小知识:响应式编程的核心是数据流,通过操作符(operators)对数据流进行转换、组合和过滤,从而实现复杂的业务逻辑。高阶响应式编程更关注性能优化和复杂场景处理。
自定义响应式系统实现 📊
// 1. 响应式数据核心
class Observable {constructor(subscribe) {this._subscribe = subscribe;}subscribe(observer) {if (typeof observer === 'function') {observer = { next: observer };}return this._subscribe(observer);}// 操作符工厂方法pipe(...operators) {return operators.reduce((source, operator) => operator(source), this);}// 静态创建方法static from(input) {if (Array.isArray(input)) {return new Observable(observer => {input.forEach(value => observer.next(value));observer.complete();return () => {};});}if (input[Symbol.iterator]) {return Observable.from([...input]);}throw new Error('Unsupported input type');}static of(...items) {return Observable.from(items);}
}// 2. 响应式主体
class Subject extends Observable {constructor() {super();this.observers = new Set();}next(value) {for (const observer of this.observers) {observer.next(value);}}error(error) {for (const observer of this.observers) {observer.error?.(error);}}complete() {for (const observer of this.observers) {observer.complete?.();}this.observers.clear();}subscribe(observer) {this.observers.add(observer);return {unsubscribe: () => {this.observers.delete(observer);}};}
}// 3. 行为主体
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) {const subscription = super.subscribe(observer);observer.next(this._value);return subscription;}
}
高级操作符实现 🚀
// 1. 转换操作符
const operators = {// 映射操作符map: (project) => (source) =>new Observable(observer => {return source.subscribe({next: value => observer.next(project(value)),error: err => observer.error(err),complete: () => observer.complete()});}),// 过滤操作符filter: (predicate) => (source) =>new Observable(observer => {return source.subscribe({next: value => {if (predicate(value)) {observer.next(value);}},error: err => observer.error(err),complete: () => observer.complete()});}),// 去重操作符distinct: (keySelector = x => x) => (source) =>new Observable(observer => {const seen = new Set();return source.subscribe({next: value => {const key = keySelector(value);if (!seen.has(key)) {seen.add(key);observer.next(value);}},error: err => observer.error(err),complete: () => observer.complete()});}),// 扁平化操作符mergeMap: (project) => (source) =>new Observable(observer => {let active = 0;let completed = false;const checkComplete = () => {if (completed && active === 0) {observer.complete();}};const outerSubscription = source.subscribe({next: value => {active++;const innerObservable = project(value);innerObservable.subscribe({next: innerValue => observer.next(innerValue),error: err => observer.error(err),complete: () => {active--;checkComplete();}});},error: err => observer.error(err),complete: () => {completed = true;checkComplete();}});return outerSubscription;})
};// 2. 组合操作符
const combinationOperators = {// 合并多个Observablemerge: (...sources) =>new Observable(observer => {let completed = 0;const subscriptions = sources.map(source =>source.subscribe({next: value => observer.next(value),error: err => observer.error(err),complete: () => {completed++;if (completed === sources.length) {observer.complete();}}}));return {unsubscribe: () => {subscriptions.forEach(sub => sub.unsubscribe());}};}),// 组合最新值combineLatest: (...sources) =>new Observable(observer => {const values = new Array(sources.length);const hasValue = new Array(sources.length).fill(false);let completed = 0;const checkComplete = () => {if (completed === sources.length) {observer.complete();}};const subscriptions = sources.map((source, index) =>source.subscribe({next: value => {values[index] = value;hasValue[index] = true;if (hasValue.every(Boolean)) {observer.next([...values]);}},error: err => observer.error(err),complete: () => {completed++;checkComplete();}}));return {unsubscribe: () => {subscriptions.forEach(sub => sub.unsubscribe());}};})
};// 3. 错误处理操作符
const errorOperators = {// 重试操作符retry: (count = 3) => (source) =>new Observable(observer => {let retries = 0;function subscribe() {return source.subscribe({next: value => observer.next(value),error: err => {if (retries < count) {retries++;subscribe();} else {observer.error(err);}},complete: () => observer.complete()});}return subscribe();}),// 捕获错误操作符catchError: (selector) => (source) =>new Observable(observer => {return source.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 Scheduler {constructor() {this.queue = new Map();this.running = false;}schedule(task, delay = 0) {return new Promise((resolve, reject) => {const timeoutId = setTimeout(() => {this.queue.set(timeoutId, {task,resolve,reject});this.runTasks();}, delay);});}async runTasks() {if (this.running) return;this.running = true;try {for (const [id, { task, resolve, reject }] of this.queue) {try {const result = await task();resolve(result);} catch (error) {reject(error);} finally {this.queue.delete(id);}}} finally {this.running = false;}}
}// 2. 内存优化
class MemoryOptimizedSubject extends Subject {constructor(options = {}) {super();this.bufferSize = options.bufferSize || 1;this.buffer = [];}next(value) {this.buffer.push(value);if (this.buffer.length > this.bufferSize) {this.buffer.shift();}super.next(value);}subscribe(observer) {// 发送缓冲区的值this.buffer.forEach(value => observer.next(value));return super.subscribe(observer);}
}// 3. 批处理优化
class BatchProcessor {constructor(options = {}) {this.batchSize = options.batchSize || 100;this.flushInterval = options.flushInterval || 1000;this.buffer = [];this.subject = new Subject();this.setupAutoFlush();}add(item) {this.buffer.push(item);if (this.buffer.length >= this.batchSize) {this.flush();}}flush() {if (this.buffer.length > 0) {this.subject.next([...this.buffer]);this.buffer = [];}}setupAutoFlush() {setInterval(() => this.flush(), this.flushInterval);}subscribe(observer) {return this.subject.subscribe(observer);}
}
最佳实践建议 💡
- 响应式设计模式
// 1. 响应式状态管理
class ReactiveStore {constructor(initialState = {}) {this.state = new BehaviorSubject(initialState);this.actions = new Subject();this.setupReducer();}setupReducer() {this.actions.pipe(operators.scan((state, action) => {const newState = this.reducer(state, action);return newState;}, this.state.value)).subscribe(this.state);}dispatch(action) {this.actions.next(action);}select(selector) {return this.state.pipe(operators.map(selector),operators.distinct());}
}// 2. 响应式缓存
class ReactiveCache {constructor(ttl = 60000) {this.cache = new Map();this.ttl = ttl;this.cleanup();}get(key) {const entry = this.cache.get(key);if (!entry) return null;if (Date.now() - entry.timestamp > this.ttl) {this.cache.delete(key);return null;}return entry.value;}set(key, value) {this.cache.set(key, {value,timestamp: Date.now()});}cleanup() {setInterval(() => {const now = Date.now();for (const [key, entry] of this.cache.entries()) {if (now - entry.timestamp > this.ttl) {this.cache.delete(key);}}}, this.ttl);}
}// 3. 响应式事件总线
class EventBus {constructor() {this.subjects = new Map();}on(event) {if (!this.subjects.has(event)) {this.subjects.set(event, new Subject());}return this.subjects.get(event);}emit(event, data) {const subject = this.subjects.get(event);if (subject) {subject.next(data);}}off(event) {const subject = this.subjects.get(event);if (subject) {subject.complete();this.subjects.delete(event);}}
}
结语 📝
响应式编程是一种强大的编程范式,掌握其进阶特性可以帮助我们构建更加健壮和可维护的应用。通过本文,我们学习了:
- 响应式编程的进阶概念和原理
- 自定义响应式系统的实现
- 高级操作符的实现和应用
- 性能优化技巧
- 最佳实践和设计模式
💡 学习建议:在实践响应式编程时,要注意内存管理和性能优化,合理使用操作符组合,同时要建立完善的错误处理机制。
如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇
终身学习,共同成长。
咱们下一期见
💻
相关文章:
JavaScript系列(70)--响应式编程进阶详解
JavaScript响应式编程进阶详解 🔄 今天,让我们深入探讨JavaScript响应式编程的进阶内容。响应式编程是一种强大的编程范式,它能够帮助我们更好地处理异步数据流和状态管理。 响应式编程进阶概念 🌟 💡 小知识&#x…...
安装指定版本的pnpm
要安装指定版本的 pnpm,可以使用以下方法: 方法 1: 使用 pnpm 安装指定版本 你可以通过 pnpm 的 add 命令来安装指定版本: pnpm add -g pnpm<版本号>例如,安装 pnpm 的 7.0.0 版本: pnpm add -g pnpm7.0.0方法…...
Dockerfiles 的 Top 10 常见 DevOps/SRE 面试问题及答案
1. RUN 和 CMD 之间有什么区别? RUN : 在镜像构建过程中执行命令,创建一个新的层。通常用于安装软件包。 示例: RUN apt-get update && apt-get install -y curlCMD : 指定容器启动时默认运行的命令。它在运行时执行,而不是在构建过程…...
头条百度批量采集软件说明文档
旧版说明文档《头条号文章批量采集软件4.0版本说明文档!头条/微头条文章批量采集》 头条的采集软件已经更新了好多个版本了,一直没有做详细的介绍文档,最近更新了一些功能进去,一块来写一下说明文档。 1、主界面 2、头条作者采集…...
36.日常算法
1.最小栈 题目来源 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void pop() 删除堆栈顶部的元素。 int top() 获取堆…...
计算机考研复试上机04
目录 6、向量 1)完数与盈数(清华大学复试上机题) 7、队列 1)约瑟夫问题 No. 2 8、栈 1)简单计算器(浙江大学复试上机题) 2)堆栈的使用(吉林大学复试上机题…...
【面试】面试常见的智力题
引言 在技术面试中,除了考察编程能力和算法知识外,智力题也是常见的考察方式。智力题不仅能够测试候选人的逻辑思维能力,还能反映其解决问题的创造力和应变能力。本文将整理一些常见的面试智力题,并详细分析解题思路,…...
【动态规划】风扫枯杨,满地堆黄叶 - 9. 完全背包问题
本篇博客给大家带来的是完全背包问题之动态规划解法技巧. 🐎文章专栏: 动态规划 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅🚀 要开心要快乐顺…...
BGP基础协议详解
BGP基础协议详解 一、BGP在企业中的应用二、BGP概述2.1 BGP的特点2.2 基本配置演示2.3 抓包观察2.4 BGP的特征三、BGP对等体关系四、bgp报文4.1 BGP五种报文类型(重点)4.2 BGP报文格式-报文头格式4.3 Open报文格式4.4 Update报文格式4.5 Notification报文格式4.6 Route-refre…...
LeetCode刷题---数组---840
矩阵中的幻方 https://leetcode.cn/problems/magic-squares-in-grid/submissions/598584907/ 题目: 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成…...
Visual Studio踩过的坑
统计Unity项目代码行数 编辑-查找和替换-在文件中查找 查找内容输入 b*[^:b#/].*$ 勾选“使用正则表达式” 文件类型留空 也有网友做了指定,供参考 !*\bin\*;!*\obj\*;!*\.*\*!*.meta;!*.prefab;!*.unity 打开Unity的项目 注意:只是看࿰…...
【深度学习入门实战】基于Keras的手写数字识别实战(附完整可视化分析)
本人主页:机器学习司猫白 ok,话不多说,我们进入正题吧 项目概述 本案例使用经典的MNIST手写数字数据集,通过Keras构建全连接神经网络,实现0-9数字的分类识别。文章将包含: 关键概念图解完整实现代码训练过程可视化模型效果深度分析环境准备 import numpy as np impo…...
SkyWalking 10.1.0 实战:从零构建全链路监控,解锁微服务性能优化新境界
文章目录 前言一、集成SkyWalking二、SkyWalking使用三、SkyWalking性能剖析四、SkyWalking 告警推送4.1 配置告警规则4.2 配置告警通知地址4.3 下发告警信息4.4 测试告警4.5 慢SQL查询 总结 前言 在传统监控系统中,我们通过进程监控和日志分析来发现系统问题&…...
计算机毕业设计——Springboot的旅游管理
🎉**欢迎来到琛哥的技术世界!**🎉 📘 博主小档案: 琛哥,一名来自世界500强的资深程序猿,毕业于国内知名985高校。 🔧 技术专长: 琛哥在深度学习任务中展现出卓越的能力&a…...
【通俗易懂说模型】反向传播(附多元分类与Softmax函数)
🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀深度学习_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. …...
Kickstart自动化安装过程中自动选择较小的磁盘安装操作系统
Kickstart自动化安装过程中自动选择较小的磁盘安装操作系统 需求 在实际生成操作过程中,一般会遇到物理服务器存在多块盘的情况。 安装过程中,磁盘的标签是随机分配的,并不是空间较小的盘,就会使用较小的磁盘标签 而需求往往需要…...
128,【1】buuctf [极客大挑战 2019]PHP
进入靶场 提示了备份文件 抓包,扫描 扫描出了两个有反应的 访问index.php没反应,但www.zip成功下载了文件 index.php里得到如下有用信息 <?phpinclude class.php;$select $_GET[select];$resunserialize($select);?> 所以我们要通过GET 方…...
3.3 学习UVM中的uvm_driver 类分为几步?
文章目录 前言1. 定义2. 核心功能3. 适用场景4. 使用方法5. 完整代码示例5.1 事务类定义5.2 Driver 类定义5.3 Sequencer 类定义5.4 测试平台 6. 代码说明7. 总结 前言 以下是关于 UVM 中 uvm_driver 的详细解释、核心功能、适用场景、使用方法以及一个完整的代码示例ÿ…...
系统思考—双环学习
前几天,一个企业高管向我提到:“我们调整了N次方案,市场策略、团队激励、管理制度,能改的全改了,怎么还是不见起色?” 这让我想到典型的单环学习,简单来说就是:发现问题 → 采取行动…...
QTreeView和QTableView单元格添加超链接
QTreeView和QTableView单元格添加超链接的方法类似,本文仅以QTreeView为例。 在QTableView仿Excel表头排序和筛选中已经实现了超链接的添加,但是需要借助delegate,这里介绍一种更简单的方式,无需借助delegate。 一.效果 二.实现 QHTreeView.h #ifndef QHTREEVIEW_H #def…...
elastic search 的 highlight
Elasticsearch 的 highlight 功能用于在搜索结果中突出显示匹配的文本片段。这对于用户界面上的搜索结果展示非常有用,因为它可以帮助用户快速定位到他们搜索的关键词。 1. 基本用法 在 Elasticsearch 中,highlight 功能通常在查询中使用,并…...
【MySQL篇】行格式详解
MySQL行格式详解 文章目录 MySQL行格式详解🎉 什么是行格式🐱👤 如何查看行格式🐱🚀 InnoDB 行格式有哪些?🐱🏍 Compact 行格式🚩 额外信息🚀 变长字段…...
嵌入式知识点总结 操作系统 专题提升(五)-内存
针对于嵌入式软件杂乱的知识点总结起来,提供给读者学习复习对下述内容的强化。 目录 1.在1G内存的计算机能否malloc(1.2G)?为什么? 2.malloc能申请多大的空间? 3.内存管理有哪几种方式? 4.什…...
动手学深度学习---深层神经网络
目录 一、神经网络1.1、模型训练1.2、损失函数1.2.1、分类:hinge loss/合页损失/支持向量机损失1.2.2、分类:交叉熵损失(softmax分类器)1.2.2.1 二分类交叉熵损失1.2.2.2 多分类交叉熵损失 1.2.3、回归:误差平方和(SSE)…...
第9章 城市基础设施更新工程 9.1 道路改造施工
9.1 道路改造施工 9.1.1 道路改造施工内容 沥青、水泥混凝土、砌块路面及人行步道、绿化照明、附属设施、交通标志。沥青路面材料的再生利用。 9.1.2 道路改造施工技术 1.沥青路面病害及微表处理 1.病害处理 裂缝处理 10mm以内 专用灌缝材料、热沥青灌缝、缝内潮湿时采用…...
java基础6(黑马)
一、static 1.static修饰成员变量 static:叫静态,可以修饰成员变量、成员方法。 成员变量按照有无static,分两种。 类变量:有static修饰,属于类,在计算机中只有一份,会被类的全部对象共享。…...
Transformer 详解:了解 GPT、BERT 和 T5 背后的模型
目录 什么是 Transformer? Transformer如何工作? Transformer 为何有用? 常见问题解答:机器学习中的 Transformer 在技术领域,突破通常来自于修复损坏的东西。制造第一架飞机的人研究过鸟类。莱特兄弟观察了秃鹫如何在气流中保持平衡,意识到稳定性比动力更重要。…...
Ollama命令使用指南
Ollama 命令使用指南 Ollama 命令使用指南1. Ollama 命令概览2. Ollama 命令详解2.1 启动 Ollama2.2 创建模型2.3 查看模型信息2.4 运行模型2.5 停止运行的模型2.6 从注册表拉取模型2.7 推送模型到注册表2.8 列出本地模型2.9 查看正在运行的模型2.10 复制模型2.11 删除模型 3. …...
【Prometheus】MySQL主从搭建,以及如何通过prometheus监控MySQL运行状态
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
上传文件防木马函数
项目环境:TP6、TP5 问题:解决旧项目中上传上来的文件校验不严格。导致会有木马文件入侵的情况发生。除了上篇博文中提及的限制上传文件存储的目录不可执行php文件外。仍需在入口处严格检验上传文件的类型,排除php类可执行文件上传。 解决&a…...
