ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

RxJS v4 `Rx.Observable.fromCallback` 详解:把回调函数转换为 Observable 序列

RxJS v4 `Rx.Observable.fromCallback` 详解:把回调函数转换为 Observable 序列 后端【免费下载链接】RxJSThe Reactive Extensions for JavaScript项目地址https://gitcode.com/gh_mirrors/rxj/RxJS点击查看免费下载导读本文深入讲解 RxJS v4Reactive Extensions for JavaScript中用于桥接回调世界与响应式世界的核心工具函数Rx.Observable.fromCallback。它将以回调作为最后一个参数的传统异步函数封装为返回 Observable 序列的函数让 Node.js 风格的fs.exists、事件驱动 API 等直接接入subscribe的订阅模型。读完本文你将掌握fromCallback的完整签名、三个参数的语义、返回值行为、底层 AsyncSubject 实现原理以及它与fromNodeCallback的适用边界并能在真实项目中直接套用示例代码。背景为什么需要把回调转成 Observable在浏览器和 Node.js 生态中除了事件还有大量以回调函数为载体的异步数据源。这种设计模式的特点是调用方把参数传给函数回调通常作为最后一个参数一旦异步结果就绪回调被执行并把数据传入其作用域。RxJS v4 提供Rx.Observable.fromCallback来包装这类标准回调即回调参数里不带error-first 约定的函数。需要特别强调的是它不覆盖 Node.js 标准的 error-first 回调风格回调的第一个参数是Error否则为null处理那种情况应使用Rx.Observable.fromNodeCallback详见 Node.js 风格回调的转换。函数签名与参数语义Rx.Observable.fromCallback(func, [context], [selector])参数类型说明funcFunction以回调作为最后一个参数的异步函数将被转换为 Observable 序列[context]Any执行func时的this上下文不指定时默认undefined在模块化实现中回退为调用时的this[selector]Function选择器函数接收回调的全部参数将其归约为单个要在next上发出的值返回值fromCallback本身返回一个函数。当以去除回调后的剩余参数调用该返回函数时它会生成一个 Observable 序列若未提供selector回调参数会以数组形式作为序列的唯一值发出若回调只有一个参数则直接发出该参数本身若提供selector发出的是selector函数以回调参数为入参计算出的对象。官方示例包装fs.exists以下示例来自官方文档演示如何把 Node.js 的fs.exists接收路径回调返回true/false表示文件是否存在包装为 Observablevar fs require(fs), Rx require(rx); // Wrap fs.exists var exists Rx.Observable.fromCallback(fs.exists); // Check if file.txt exists var source exists(file.txt); var subscription source.subscribe( function (x) { console.log(Next: x); }, function (err) { console.log(Error: err); }, function () { console.log(Completed); }); // Next: true // Completed注意输出中Next: true是布尔值而不是数组——这正是上文所述回调仅有一个参数时直接发出该参数的行为。执行流程是fromCallback(fs.exists)生成包装函数existsexists(file.txt)立即以file.txt为参数调用fs.exists并注入内部生成的回调处理器异步回调触发后序列发出true并紧接着发出Completed通知回调型函数天然是单值即结束的序列。参数组合实战context 与 selector指定 contextthis 上下文当被包装的函数内部依赖this时通过第二个参数传入上下文var res Rx.Observable.fromCallback( function (cb) { // 这里 this 即 42 cb(true); }, 42)(); res.subscribe( function (x) { console.log(Next: x); }, function (e) { console.log(Error: e); }, function () { console.log(Completed); });从源码看context默认值为undefined核心版见 src/core/perf/operators/fromcallback.js其中typeof ctx undefined (ctx this)会在未指定时回退为当前调用上下文随后通过fn.apply(ctx, args)把ctx绑定到被包装函数上执行。使用 selector 归约多参数回调很多回调会回传多个参数。若不使用 selector多参数将以数组发出使用 selector 则可以取出其中需要的部分归约为单个值var res Rx.Observable.fromCallback( function (f, s, t, cb) { cb(f, s, t); }, null, // 不关心 this显式传 null function (f) { return f; // 只取第一个回调参数 })(1, 2, 3); res.subscribe(function (r) { console.log(Next: r); // Next: 1 });底层原理AsyncSubject 与回调处理器fromCallback的精髓在于它底层基于AsyncSubject实现。阅读 AsyncSubject 源码 可知其语义它只会发出终止前的最后一个值并且该值会被缓存供所有当前及未来的订阅者使用。整个调用链可以拆解为三层包装层Observable.fromCallback(fn, ctx, selector)返回一个闭包函数。该函数在真正执行时把调用参数收集为数组args然后调用createCbObservablesrc/core/perf/operators/fromcallback.js。构造层createCbObservable创建一个新的AsyncSubject实例o把内部回调处理器createCbHandler(o, ctx, selector)追加到参数数组末尾args.push(...)然后执行fn.apply(ctx, args)最后返回o.asObservable()对外隐藏 Subject 的写端只暴露只读 Observable。回调层createCbHandler返回的handler函数就是注入给被包装函数的回调。它把回调收到的所有参数收集到results数组然后分三种情况处理src/core/perf/operators/fromcallback.js提供 selector用tryCatch(selector).apply(ctx, results)计算归约结果若 selector 抛错则调用o.onError(error)否则o.onNext(result)仅一个回调参数直接o.onNext(results[0])多个回调参数o.onNext(results)整体以数组发出最后调用o.onCompleted()。两个值得注意的实现细节同步抛错也走 onError在模块化实现 src/modular/observable/bindcallback.js 中连fn.apply(ctx, args)本身都用tryCatch包裹若被包装函数同步抛出异常同样转为o.onError通知避免异常直接泄漏。冷缓存、可重订阅因为回调只在每次调用返回函数时执行一次而 AsyncSubject 会缓存最终值所以同一个返回函数生成的 Observable 可以被多次订阅订阅者都能拿到同一个结果值。测试用例fromCallback resubscribe见 tests/observable/fromcallback.js验证了这一点连续两次subscribe同一个序列被包装函数内部计数器count仍保持为 1即回调只被触发一次两次订阅共享缓存结果。完整测试用例佐证仓库自带的单元测试 tests/observable/fromcallback.js 覆盖了五个关键场景是理解 API 行为的权威参考测试名验证点fromCallback基本包装回调cb(true)发出true并完成fromCallback single argument函数先接收普通参数再接收回调cb(file)发出file.txtfromCallback selector多参数回调 selector 归约为第一个参数fromCallback context回调内断言this 42验证 context 生效fromCallback resubscribe同一序列可重复订阅底层函数只执行一次与 fromNodeCallback 的边界划分回调风格适用函数错误处理标准回调如fs.exists参数即结果Rx.Observable.fromCallback错误只能通过手动抛错或 selector 内tryCatch转为onErrorNode.js error-first 回调如fs.rename首个参数是ErrorRx.Observable.fromNodeCallback自动识别首个 error 参数非空则发onError否则发onNext并onCompleted选择依据很简单被包装函数的回调是否以Error为第一个参数。是则用fromNodeCallback否则用fromCallback。两种 API 在入门指南 Bridging to Callbacks 中有成对示例可对照阅读。模块化实现与安装方式核心实现src/core/perf/operators/fromcallback.js完整版、性能优化版模块化实现fromCallback在模块化构建中被实现为bindCallback并在 src/modular/index.js 中以Observable.fromCallback Observable.bindCallback形式挂载打包产物rx.all.js、rx.all.compat.js、rx.async.js、rx.async.compat.js、rx.lite.js、rx.lite.compat.js等 dist 版本均包含该 APINPMrx包NuGetRxJS-Complete、RxJS-Async、RxJS-Lite包若使用rx.async.js/rx.async.compat.js需要预先加载rx.js或rx.compat.js与rx.binding.js作为前置依赖。小结Rx.Observable.fromCallback是 RxJS v4 中桥接传统回调 API 与 Observable 管线的最轻量工具一次包装、按需调用、单值即完成。理解它的三个参数func/context/selector、返回值形态单参数直发、多参数组数组、selector 归约以及 AsyncSubject 的缓存语义你就能把任何回调结尾的异步函数无缝接入subscribe、map、filter、merge等完整的响应式操作符体系并与 error-first 场景的fromNodeCallback正确区分使用。赞分享后端【免费下载链接】RxJSThe Reactive Extensions for JavaScript项目地址https://gitcode.com/gh_mirrors/rxj/RxJS点击查看免费下载相关推荐RxJS v4 Rx.Observable.from 完全指南将数组、类数组与可迭代对象转换为 Observable 序列RxJS v4 Rx.Observable.from 完全指南将数组、类数组与可迭代对象转换为 Observable 序列 导读 Rx.Observable.后端RxJS v4 jortSort 操作符详解判断 Observable 序列是否已排序RxJS v4 jortSort 操作符详解判断 Observable 序列是否已排序 jortSort 是 RxJS v4Reactive Extensi后端RxJS v4 详解 concatAll 操作符把可观测序列序列化为顺序执行的订阅RxJS v4 详解 concatAll 操作符把可观测序列序列化为顺序执行的订阅 本文基于 RxJSThe Reactive Extensions for后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表