ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RxJS 备忘清单:从 Observable 到操作符的响应式编程速查指南

RxJS 备忘清单:从 Observable 到操作符的响应式编程速查指南 RxJS 备忘清单从 Observable 到操作符的响应式编程速查指南【免费下载链接】reference为开发人员分享快速参考备忘清单(速查表)项目地址: https://gitcode.com/jaywcjlove/referenceRxJSReactive Extensions for JavaScript是处理异步事件与数据流的响应式编程库本清单以可复制的代码示例为主线系统梳理 Observable 的创建方式、常用操作符、组合策略、错误处理与调度器机制。在 jaywcjlove/reference 项目中RxJS 速查表归类于前端技术板块见 README.md 前端分组配套 assets/rxjs.svg 主题图标。阅读本文后你将能够用声明式管道替代命令式事件监听、掌握 20 余个高频操作符的语义与输出并理解调度器如何控制任务的执行时机。入门安装 RxJS在任意 Node.js 或浏览器前端项目中通过 npm 安装npm install rxjs安装完成后即可从rxjs与rxjs/operators两个入口按需导入。需要说明的是较新版本的 RxJS7.x已统一从rxjs包导出操作符例如import { map } from rxjs本备忘清单沿用了经典的rxjs/operators写法两者在 7.x 中均可正常工作。清晰用纯函数隔离状态RxJS 的强大之处在于它使用纯函数生成值的能力这意味着代码更不容易出错。通常情况下你会创建一个不纯的函数而代码的其他部分可能会弄乱你的状态let count 0; document.addEventListener(click, () { console.log(Clicked ${count} times) });上面的写法中计数状态count暴露在全局作用域任何代码都可能意外修改它。使用 RxJS 可以将状态隔离在操作符的闭包内部import { fromEvent, scan } from rxjs; fromEvent(document, click) .pipe(scan((count) count 1, 0)) .subscribe((count) { console.log(Clicked ${count} times) });scan操作符的工作原理与数组的reduce类似它接受一个暴露给回调函数的值初始值0回调的返回值将成为下次回调运行时公开的下一个值。区别在于reduce只在流结束时输出一次结果而scan会在每一次新值到达时都发出中间累积结果——这正是它适合做计数器、累加器、状态汇总的原因。流控制事件的流速RxJS 拥有一整套操作符可以帮助你控制事件如何流经可观察对象。这是使用纯 JavaScript 实现每秒最多允许一次点击的方式let count 0; let rate 1000; let lastClick Date.now() - rate; document.addEventListener(click, () { if (Date.now() - lastClick rate) { console.log(Clicked ${count}times); lastClick Date.now(); } });同样的需求使用 RxJS 只需在管道中组合两个操作符import { fromEvent, throttleTime, scan } from rxjs; fromEvent(document, click) .pipe(throttleTime(1000), scan((count) count 1, 0) ) .subscribe((count) { console.log(Clicked ${count} times) });throttleTime(1000)会抑制源流中过于频繁的发射——当源在 1 秒内多次发出值时只有第一次会通过其余被丢弃直到冷却期结束。与手动维护lastClick时间戳相比命令式代码把限流策略硬编码进了业务逻辑而 RxJS 把策略抽象成可组合的操作符可读性与可维护性都显著提升。第一个示例从事件监听器到 Observable通常情况下你需要手动注册事件监听器document.addEventListener(click, () { console.log(Clicked!) });使用 RxJS你可以创建一个可观察对象并订阅它import { fromEvent } from rxjs; fromEvent(document, click) .subscribe(() { console.log(Clicked!) });两者的行为等价但后者带来三个额外收益统一的订阅/退订模型subscribe返回的 Subscription 可随时unsubscribe、可接入操作符管道进行数据变换、以及可与其他数据流组合。导入所需的 Observable 和操作符快速开发时可按需从两个入口导入import { Observable, of, from, interval, fromEvent } from rxjs; import { map, filter, switchMap, mergeMap, catchError, debounceTime, distinctUntilChanged, take, tap, concatMap, delay, retryWhen, scan, combineLatest, concat, merge, forkJoin, withLatestFrom, startWith, reduce } from rxjs/operators;rxjs核心类型与创建函数Observable、of、from、interval、fromEventrxjs/operators管道操作符变换、过滤、组合、错误处理、工具类。创建 Observableofconst obs of(1, 2, 3); obs.subscribe(console.log); // 输出: 1 2 3创建一个立即发送指定值并完成的Observable。适合包装固定数量的常量序列。fromconst obs from([1, 2, 3]); obs.subscribe(console.log); // 输出: 1 2 3从Promise、数组、可迭代对象创建Observable。与of的区别在于of把整个参数当作一个值发出而from会逐个遍历并发出其中的每一项当传入 Promise 时from会在 Promise resolve 后发出其结果并完成。intervalconst obs interval(1000); obs.subscribe(console.log); // 每秒输出一次递增的数字创建一个定时发送递增整数从0开始每1000ms一个的Observable永不自动完成。注意配合take等操作符使用避免无限运行导致内存泄漏。fromEventconst button document.querySelector(button); const obs fromEvent(button, click); obs.subscribe(event { console.log(Button clicked!, event) });从DOM 事件创建Observable事件对象作为发射值传给订阅回调。这是把既有事件驱动代码迁移到响应式管道的入口。操作符操作符通过pipe()串联形成一个数据变换管道源 Observable 发射的每个值依次流经各操作符最终到达订阅回调。mapconst obs of(1, 2, 3).pipe( map(x x * 2) ); obs.subscribe(console.log); // 输出: 2 4 6对Observable发出的每个值应用一个函数返回新值。与数组Array.prototype.map语义一致是使用频率最高的变换操作符。filterconst obs of(1, 2, 3).pipe( filter(x x % 2 0) ); obs.subscribe(console.log); // 输出: 2过滤Observable发出的值只让满足谓词函数的值通过其余被丢弃。switchMapconst obs interval(1000).pipe( switchMap(() of(Hello)) ); obs.subscribe(console.log); // 每秒输出一次 Hello将Observable每个值映射成一个内部Observable并订阅它当源再次发射新值时前一个内部订阅会被取消只保留最新的。这使switchMap天然适合输入即搜索切换路由等需要丢弃过期结果的场景——例如用户快速输入时只关心最后一次请求的结果。mergeMapconst obs interval(1000).pipe( mergeMap(() of(Hello)) ); obs.subscribe(console.log); // 每秒输出一次 Hello类似switchMap但允许多个内部Observable并发执行所有内部订阅的结果都会合并到输出流不会取消先前的订阅。适合并发请求多个接口并聚合结果的场景。catchErrorconst obs of(1, 2, 3).pipe( map(x { if (x 2) throw Error!; return x; }), catchError(err of(发现一个错误err)) ); obs.subscribe(console.log); // 输出: 1 发现一个错误Error!捕获Observable链中的错误当上游抛出异常时catchError的投影函数返回一个替代 Observable来接管数据流从而阻止错误继续向下传播。注意此处示例中of(1, 2, 3)会在第 2 个值处抛错因此只输出1和错误信息。debounceTimeconst obs fromEvent(document,mousemove) .pipe(debounceTime(300)); obs.subscribe(event { console.log(Mouse moved!, event) });防抖延迟处理直到源Observable停止发出数据满指定时间300ms后才发出最后一个值。与throttleTime相对——debounceTime关注静默期停止后才触发throttleTime关注冷却期固定节流。典型应用搜索框输入联想、窗口 resize 后的重排。distinctUntilChangedconst obs of(1, 1, 2, 2, 3, 3).pipe( distinctUntilChanged() ); obs.subscribe(console.log); // 输出: 1 2 3忽略连续重复的值只有与前一个发射值不同时才放行。注意它只比较相邻值1, 2, 1中的两个1都会被发出。takeconst obs interval(1000).pipe( take(3) ); obs.subscribe(console.log); // 输出: 0 1 2只发出前 n 个值之后自动完成并退订。是控制无限流如interval生命周期的关键操作符。组合操作符combineLatestconst obs1 interval(1000); const obs2 of(A, B, C); const combined combineLatest( [obs1, obs2] ); combined.subscribe(console.log); // 每秒输出一次两个 observables 的最新值当所有Observable都发出过值后任一源发射新值时都会发出所有源最新值的组合元组/数组。常用于多条件筛选联动表单多字段状态合并。注意obs2为有限流of立即完成因此实际输出为obs2的最后一个值C与obs1每秒递增值的组合。concatconst obs1 of(1, 2, 3); const obs2 of(4, 5, 6); const combined concat(obs1, obs2); combined.subscribe(console.log); // 输出: 1 2 3 4 5 6按顺序连接多个Observable前一个完成后才开始订阅下一个保持严格的先后顺序。mergeconst obs1 interval(1000).pipe( map(x A x) ); const obs2 interval(500).pipe( map(x B x) ); const combined merge(obs1, obs2); combined.subscribe(console.log); // 每秒输出 A 和 B 开头的递增数字将多个Observable按发射时间合并为一个流谁先发出谁先到达不做排序示例中B系列每 500ms 一次频率是A的两倍。forkJoinconst obs1 of(1, 2, 3); const obs2 of(A, B, C); const combined forkJoin([obs1, obs2]); combined.subscribe(console.log); // 输出: [3, C]等待所有Observable完成然后发出它们最后一个值组成的数组。与Promise.all语义类似适合并行请求多个接口、全部成功后统一处理。错误处理retryWhenconst obs throwError(出了些问题) .pipe( retryWhen(errors errors.pipe(delayWhen(() interval(1000))) ) ); obs.subscribe(console.log, console.error); // 输出: 出了些问题 (每秒重试一次)在Observable发出错误时重试retryWhen接收错误流errors作为参数你可以在其中用操作符如delayWheninterval控制重试的时机与次数。示例中每次出错后延迟 1 秒重试形成指数退避、固定间隔等自定义重试策略的基础。该示例依赖throwError、delayWhen使用前需额外导入throwError来自rxjsdelayWhen来自rxjs/operators。实用操作符tapconst obs of(1, 2, 3).pipe( tap(x console.log(Before: ${x})), map(x x * 2), tap(x console.log(After: ${x})) ); obs.subscribe(); // 输出: Before: 1, After: 2, Before: 2, // After: 4, Before: 3, After: 6用于记录、测量或执行副作用操作tap透传每个值但不改变它适合在管道中间插入日志、调试或埋点而不会干扰数据流。startWithconst obs of(1, 2, 3).pipe( startWith(0) ); obs.subscribe(console.log); // 输出: 0 1 2 3在Observable序列开头插入一个或多个值。常用于给 UI 提供初始状态避免订阅后长时间无值。scanconst obs of(1, 2, 3).pipe( scan((acc, value) acc value, 0) ); obs.subscribe(console.log); // 输出: 1 3 6对Observable发出的每个值应用累加器函数并发出每次的中间结果与reduce的区别见下。reduceconst obs of(1, 2, 3).pipe(reduce((acc, value) acc value, 0)); obs.subscribe(console.log); // 输出: 6对Observable发出的值进行累加但只在源流完成后发出一次最终结果scan每次都会发中间值reduce只发总和6。delayconst obs of(Hello).pipe(delay(2000)); obs.subscribe(console.log); // 输出: Hello (延迟2秒)延迟Observable发出数据的时间此处为 2 秒常配合动画、消息提示等时序控制场景。调度器调度器说明调度器Scheduler控制着 RxJS 操作的执行时机同步还是异步、何时排队。常见的调度器有asyncScheduler异步执行任务适合定时器、网络请求等延迟执行queueScheduler按队列顺序执行任务默认同步队列适合简单的递归式调度animationFrameScheduler在浏览器的下一次重绘前执行任务适合与动画帧同步的操作。示例const obs of(1, 2, 3).pipe(observeOn(asyncScheduler)); console.log(Before subscribe); obs.subscribe(console.log); console.log(After subscribe); // 输出: Before subscribe, After subscribe, 1, 2, 3observeOn(asyncScheduler)将值的发射调度为异步执行即使of(1, 2, 3)本身是同步创建的订阅回调也不会立即触发而是进入异步队列因此After subscribe会先于1 2 3输出。理解这一点有助于排查订阅后值何时到达的时序问题。本示例使用observeOn需从rxjs/operators额外导入。另见RxJS 官方文档RxJS 学习资源RxJS 操作符参考【免费下载链接】reference为开发人员分享快速参考备忘清单(速查表)项目地址: https://gitcode.com/jaywcjlove/reference创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表