首页/新闻资讯/正文详情

Flux Dispatcher 完全指南:从 API 到 waitFor 依赖编排原理

发布时间:2026/9/21 2:05:44 来源:云帆数科 栏目:资讯中心
Flux Dispatcher 完全指南:从 API 到 waitFor 依赖编排原理
Flux Dispatcher 完全指南从 API 到 waitFor 依赖编排原理【免费下载链接】fluxApplication Architecture for Building User Interfaces项目地址: https://gitcode.com/gh_mirrors/fl/fluxFlux 是一套用于构建用户界面的单向数据流应用架构而Dispatcher是整个架构中唯一不依赖 React、也不依赖任何第三方库的枢纽组件——所有 Action 都经由它广播给各个 Store 的回调函数。本指南以仓库中的 docs/Dispatcher.md 为骨架结合 Dispatcher.js 源码与 Dispatcher-test.js 测试用例深入讲解 Dispatcher 的 API、waitFor()依赖编排机制以及它与 Store 协作的底层原理读完即可在自己的 Flux 应用中正确使用 Dispatcher 并规避循环依赖等经典陷阱。Dispatcher 是什么与通用发布/订阅系统的本质区别Dispatcher用于把 payload载荷广播给所有已注册的回调函数。它和通用的 pub-sub发布/订阅系统有两点本质区别回调不订阅特定事件每个 payload 都会被派发给每一个已注册的回调。也就是说回调无法只关心某类事件而是必须自己判断 payload 是否与自己相关。回调可以被整体或部分地延迟执行通过waitFor()一个回调可以等待其他回调执行完毕后再继续从而在多个 Store 之间建立确定的依赖顺序。从源码结构看Dispatcher.js 是一个泛型类DispatcherTPayload内部维护了_callbacks、_isDispatching、_isHandled、_isPending四张状态表这正是它区别于普通事件发射器的核心数据结构。为什么需要这种设计在 Flux 中一个用户操作往往需要多个 Store 同时响应而这些 Store 之间存在数据依赖。例如选择国家后自动选择默认城市、再计算航班价格如果不保证执行顺序价格计算就可能读到过期的城市数据。Dispatcher 的waitFor()正是为了解决这种依赖更新的问题而生的。API 全景Dispatcher 暴露了 5 个核心方法文档中的完整签名如下方法签名说明registerregister(function callback): string注册一个回调每次 dispatch 时都会被调用。返回一个 token令牌可用于waitFor()unregisterunregister(string id): void根据 token 移除一个已注册的回调waitForwaitFor(arraystring ids): void等待指定 token 对应的回调执行完毕再继续执行当前回调。只能在回调响应某次 dispatch 的过程中调用dispatchdispatch(object payload): void向所有已注册回调派发一个 payloadisDispatchingisDispatching(): boolean查询 Dispatcher 当前是否正处于派发过程中registertoken 的生成规则从 Dispatcher.js 可以看到 token 的生成实现var _prefix ID_; register(callback) { var id _prefix this._lastID; // 例如 ID_1、ID_2、ID_3 ... this._callbacks[id] callback; return id; }_lastID从 1 开始自增所以第一次注册返回的 token 是ID_1第二次是ID_2依此类推。token 的类型在源码中被定义为DispatchToken string见 Dispatcher.js它只是一个字符串标识不是Promise 或句柄。unregister按 token 移除回调Dispatcher.js 中的实现使用了invariant做防御性校验如果传入的 token 没有对应任何已注册回调会直接抛出错误Dispatcher.unregister(...):does not map to a registered callback.。移除后该回调在后续 dispatch 中不会再被调用测试用例should properly unregister callbacks验证了这一点见 Dispatcher-test.js。实战示例航班目的地表单文档用航班目的地表单这一假想场景完整演示了 Dispatcher 的核心用法。假设表单在选中国家后自动选择该国家的默认城市并根据国家 城市计算基础票价。第一步创建 Dispatcher 与 Storevar flightDispatcher new Dispatcher(); // 记录当前选中的国家 var CountryStore {country: null}; // 记录当前选中的城市 var CityStore {city: null}; // 记录当前选中城市的基础票价 var FlightPriceStore {price: null};注意这里的CountryStore等只是普通 JavaScript 对象用于演示 Dispatcher 的机制。在真实 Flux 应用中Store 通常基于EventEmitter或仓库提供的FluxStore基类构建并在构造时通过dispatcher.register(...)注册回调详见下文与 FluxStore 的协作。第二步派发城市更新 payload用户更改了选中的城市后通过dispatch广播flightDispatcher.dispatch({ actionType: city-update, selectedCity: paris, });该 payload 被CityStore消化flightDispatcher.register(function (payload) { if (payload.actionType city-update) { CityStore.city payload.selectedCity; } });注意这里体现了 Dispatcher 的第一个特性这个回调虽然只关心city-update但它每次 dispatch 都会被调用只是通过if判断主动忽略了不相关的 payload。第三步派发国家更新 payloadflightDispatcher.dispatch({ actionType: country-update, selectedCountry: australia, });该 payload 同时被两个 Store 消化CountryStore.dispatchToken flightDispatcher.register(function (payload) { if (payload.actionType country-update) { CountryStore.country payload.selectedCountry; } });注册CountryStore回调时把返回的 token 保存在CountryStore.dispatchToken上。有了这个 token后续回调就可以用waitFor()声明自己对它的依赖。第四步用 waitFor 保证依赖顺序当CityStore的回调需要根据新国家计算默认城市时它必须先确认CountryStore已经更新完毕CityStore.dispatchToken flightDispatcher.register(function (payload) { if (payload.actionType country-update) { // 注意此时 CountryStore.country 可能尚未更新 flightDispatcher.waitFor([CountryStore.dispatchToken]); // 执行到这里时CountryStore.country 已保证被更新 // 为新国家选择默认城市 CityStore.city getDefaultCityForCountry(CountryStore.country); } });waitFor([CountryStore.dispatchToken])的含义是暂停当前回调的执行先确保CountryStore的回调已经执行完毕再继续。这就是 Dispatcher 的第二个特性——回调可以被整体或部分地延迟。waitFor 可以链式调用依赖是可以叠加的。FlightPriceStore的价格计算同时依赖国家和城市可以这样写FlightPriceStore.dispatchToken flightDispatcher.register(function (payload) { switch (payload.actionType) { case country-update: case city-update: flightDispatcher.waitFor([CityStore.dispatchToken]); FlightPriceStore.price getFlightPriceStore( CountryStore.country, CityStore.city, ); break; } });最终country-updatepayload 会保证按CountryStore→CityStore→FlightPriceStore的顺序依次调用各 Store 注册的回调。waitFor 的底层原理pending / handled 状态机waitFor之所以能保证顺序靠的是 Dispatcher 内部维护的_isPending和_isHandled两张状态表以及_invokeCallback的记账逻辑。整个 dispatch 周期分为三个阶段见 Dispatcher.js_startDispatching(payload)把每个回调的_isPending和_isHandled重置为false保存_pendingPayload并将_isDispatching置为true。遍历_callbacks执行对每个未被标记为 pending 的回调调用_invokeCallback(id)。_invokeCallback会先把该回调标记为_isPending[id] true再执行回调最后标记_isHandled[id] true见 Dispatcher.js。_stopDispatching()删除_pendingPayload把_isDispatching恢复为false。这一步骤放在finally块中即使回调抛异常也会执行确保 Dispatcher 不会卡死在派发中状态。waitFor的执行逻辑见 Dispatcher.js正是基于这两张表waitFor(ids) { for (var ii 0; ii ids.length; ii) { var id ids[ii]; if (this._isPending[id]) { // 目标回调已经或正在执行若它还没执行完说明形成循环依赖直接抛错 invariant( this._isHandled[id], Dispatcher.waitFor(...): Circular dependency detected while waiting for %s., id, ); continue; // 已执行完毕无需再等待 } invariant( this._callbacks[id], Dispatcher.waitFor(...): %s does not map to a registered callback., id, ); this._invokeCallback(id); // 立即同步执行目标回调 } }这段代码揭示了几个关键事实waitFor是同步递归执行目标回调而不是异步等待。因此调用链上不存在微任务/宏任务调度顺序是确定性的。如果一个目标回调已经被执行完毕_isPending为 true 且_isHandled为 truewaitFor直接continue跳过不会重复执行——这正是多个回调对同一 store 调用waitFor不会重复更新的原因。如果一个目标回调正在执行中_isPending为 true 但_isHandled为 false说明出现了循环等待直接抛出Circular dependency detected错误。三个必须遵守的约束附源码级验证Dispatcher 对使用方式有硬性约束违反即抛错。这些行为都被测试用例逐一验证过1. 禁止在 dispatch 过程中再次 dispatch。dispatcher.register((payload) { dispatcher.dispatch(payload); // 抛错 });Dispatcher.js 中dispatch首先检查_isDispatching为 true 时抛出Cannot dispatch in the middle of a dispatch.。对应测试should throw if dispatch() while dispatchingDispatcher-test.js。2. 禁止在非派发状态下调用waitFor。dispatcher.waitFor([tokenA]); // 抛错Must be invoked while dispatching.waitFor的第一行 invariant 就是检查_isDispatching见 Dispatcher.js。对应测试should throw if waitFor() while not dispatchingDispatcher-test.js。3. 禁止形成循环依赖。包括自我等待和互相等待两种形态// 自我循环A 等待 A const tokenA dispatcher.register((payload) { dispatcher.waitFor([tokenA]); // 抛错Circular dependency detected }); // 相互循环A 等待 BB 又等待 A const tokenA dispatcher.register((payload) { dispatcher.waitFor([tokenB]); }); const tokenB dispatcher.register((payload) { dispatcher.waitFor([tokenA]); });对应测试should throw on self-circular dependencies与should throw on multi-circular dependenciesDispatcher-test.js。循环依赖检测正是通过上述 pending/handled 状态机在运行时完成的。此外还有两个值得注意的边界行为失败的 dispatch 不会破坏状态一致性即使某个回调抛异常finally块中的_stopDispatching()也会执行后续 dispatch 依然可用。测试should remain in a consistent state after a failed dispatchDispatcher-test.js验证了这一点。waitFor传入不存在的 token 会抛错对应测试should throw if waitFor() with invalid tokenDispatcher-test.js。与 FluxStore / ReduceStore 的协作dispatchToken 从哪来文档示例中dispatchToken是手动保存的而真实 Flux 应用中token 通常由 Store 基类自动管理。看 FluxStore.js 的构造函数constructor(dispatcher) { ... this.__dispatcher dispatcher; this._dispatchToken dispatcher.register((payload) { this.__invokeOnDispatch(payload); }); } getDispatchToken() { return this._dispatchToken; // 供其他 Store 的 waitFor 使用 }也就是说每个基于FluxStore创建的 Store 在实例化时就会把自己的分发回调注册进 Dispatcher并通过getDispatchToken()暴露 token。于是 Store 之间的依赖可以写成class CityStore extends FluxStore { __onDispatch(payload) { if (payload.actionType country-update) { this.getDispatcher().waitFor([CountryStore.getDispatchToken()]); this._city getDefaultCityForCountry(CountryStore.getCountry()); } } }从源码结构看FluxStore的__invokeOnDispatchFluxStore.js会在每轮 dispatch 开始时重置__changed并在子类处理完 payload 后通过 EventEmitter 广播change事件——这就是Store 变更通知视图的底层机制而这一切的入口都始于 Dispatcher 的那次register。在项目中使用 Dispatcher通过 npm 安装Flux 以 npm 模块发布在package.json中添加依赖或直接运行npm install flux即可。安装后通过命名空间访问const Dispatcher require(flux).Dispatcher;从仓库构建克隆本仓库并进入flux目录后运行npm installGulp 构建任务会自动生成Flux.js文件之后可以这样引入const Dispatcher require(path/to/this/directory/Flux).Dispatcher;构建过程还会在lib目录下生成去掉语法糖的Dispatcher与invariant模块可以直接拷贝到任何目录单独使用——仓库中的flux-todomvc等示例应用就是这么做的。推荐的单例模式在实际应用中整个应用通常共享一个Dispatcher 实例。仓库示例的写法可供参考// examples/flux-todomvc/src/data/TodoDispatcher.js import {Dispatcher} from flux; export default new Dispatcher();// examples/flux-flow/src/AppDispatcher.js带 Flow 泛型约束 import type {Action} from ./AppActions; import {Dispatcher} from flux; const dispatcher: DispatcherAction new Dispatcher(); export default dispatcher;之所以强调单例是因为如果多个模块各自new Dispatcher()Store 之间就无法通过waitFor建立依赖token 属于不同实例互不可见整个数据流的确定性顺序也就无从谈起。小结Flux 的 Dispatcher 用不到两百行代码实现了三个关键能力全量广播每个 payload 到达每个回调、依赖编排waitFor保证执行顺序、运行时防护禁止嵌套 dispatch、禁止非派发期调用 waitFor、检测循环依赖。理解它的核心在于记住_isPending/_isHandled状态机waitFor是同步递归、天然去重、且能识别循环的。若想深入验证这些行为可以直接阅读 Dispatcher.js 源码并运行仓库中的 Dispatcher-test.js 测试套件——十个测试用例覆盖了从基本广播到失败恢复的全部边界场景。【免费下载链接】fluxApplication Architecture for Building User Interfaces项目地址: https://gitcode.com/gh_mirrors/fl/flux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

agentic-awesome-skills 之 API 设计原则实战手册:REST 与 GraphQL 的工程化落地指南
agentic-awesome-skills 之 API 设计原则实战手册:REST 与 GraphQL 的工程化落地指南

agentic-awesome-skills 之 API 设计原则实战手册:REST 与 GraphQL 的工程化落地指南 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and … · 2026/9/21 2:05:44

Agentic Awesome Skills 应用构建器 feature-building 技能解析:面向 Agent 的功能分析与迭代实现方法论
Agentic Awesome Skills 应用构建器 feature-building 技能解析:面向 Agent 的功能分析与迭代实现方法论

AI 技能AI 插件 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,115 agentic skills. Includes CLI, local MCP, catalog, … · 2026/9/21 2:05:44

VW 80000 EN-2021标准解析与汽车电子测试落地实践
VW 80000 EN-2021标准解析与汽车电子测试落地实践

简介:大众汽车集团VW 80000标准2021-01英文版PDF,是一份面向汽车电子电气系统研发、测试与质量管理人员的专业规范。标准规定了3.5吨以下机动车辆中电气和电子单元的通用要求、测试条件与试验方法,涵盖PCBA、电控单元等对象,特别包… · 2026/9/21 2:05:44

windowsserver2003怎么给网站做域名解析及2024年建站报价避坑指南
windowsserver2003怎么给网站做域名解析及2024年建站报价避坑指南

windowsserver2003怎么给网站做域名解析及2024年建站报价避坑指南 刚接到北京朝阳区一家贸易公司的电话,老板一脸愁容,手里攥着一张过期的SSL证书和一份厚厚的建站报价单。他问:“师傅,我这台老服务器还能救吗?备案流程一头雾水,域名解析也配不上,这钱花得冤不冤?”… · 2026/9/21 4:46:47

伤豆丁文库网站开发图解步骤:被黑挂马后怎么救
伤豆丁文库网站开发图解步骤:被黑挂马后怎么救

伤豆丁文库网站开发图解步骤:被黑挂马后怎么救 网站被黑挂马不知道怎么办?别慌,先别删库,也别盲目重装系统。很多站长在发现首页变乱码或出现非法链接时,第一反应是重置密码,但这往往治标不治本。真正的危机在于你的服务器底层已经被植入了后门,或者数据库被注入了恶意脚本。 这里有一份针对 伤豆丁文库网站开发… · 2026/9/21 4:32:42

3步解决wordpress自己打包apk挂马危机与最佳实践
3步解决wordpress自己打包apk挂马危机与最佳实践

3步解决wordpress自己打包apk挂马危机与最佳实践 网站被黑挂马却不知从哪查起?别慌,这不仅是技术事故,更是法律风险。很多新手做wordpress自己打包apk时,为了省事直接调用第三方接口,结果APK里塞满恶意代码。本文拆解真实案例,给出可落地的最佳实践,帮你从根源堵住漏洞,守住网站底线。… · 2026/9/21 4:19:24

ARIS 工作流总览:从 idea 到 paper 的 13 条 pipeline 如何一次看全
ARIS 工作流总览:从 idea 到 paper 的 13 条 pipeline 如何一次看全

ARIS 工作流总览:从 idea 到 paper 的 13 条 pipeline 如何一次看全 【免费下载链接】Auto-claude-code-research-in-sleep ARIS ⚔️ (Auto-Research-In-Sleep) — Lightweight Markdown-only skills for autonomous ML research: cross-model review loops, idea … · 2026/9/21 4:06:05

南郊网站建设报价单背后的安全防线:3个实战案例揭秘
南郊网站建设报价单背后的安全防线:3个实战案例揭秘

南郊网站建设报价单背后的安全防线:3个实战案例揭秘 备案流程一头雾水?别急,南郊网站建设报价单里藏着比备案更深的坑。我见过太多老板盯着价格看,却忽略了“安全”二字。 上个月刚处理完一个 实战案例… · 2026/9/21 4:04:06

Roc 格式化器幂等性测试实战:从 issue 8851 快照看多行分发与字段访问的格式化处理
Roc 格式化器幂等性测试实战:从 issue 8851 快照看多行分发与字段访问的格式化处理

Roc 格式化器幂等性测试实战:从 issue 8851 快照看多行分发与字段访问的格式化处理 【免费下载链接】roc A fast, friendly, functional language. 项目地址: https://gitcode.com/GitHub_Trending/ro/roc 导读:本文以 Roc 编译器仓库中的快照测试… · 2026/9/21 4:04:05

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化
Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡… · 2026/9/21 0:02:39

Word表格编号全攻略:从列表编号到题注交叉引用
Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技… · 2026/9/21 0:02:39

从第一个站到第二个站:独立开发者的静态网站选型与落地实践
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&… · 2026/9/20 0:00:41

Claude Code 按智谱AI指南装完,ANTHROPIC_BASE_URL 改走 TaoToken 兼容通道行不行
Claude Code 按智谱AI指南装完,ANTHROPIC_BASE_URL 改走 TaoToken 兼容通道行不行

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 0:00:18

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程
agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and … · 2026/9/21 0:00:18

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,… · 2026/9/21 0:00:18

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码