antd Message 的 Promise 接口(thenable)实战:用 .then() 编排消息关闭后的回调

antd Message 的 Promise 接口(thenable)实战:用 .then() 编排消息关闭后的回调 antd Message 的 Promise 接口thenable实战用 .then() 编排消息关闭后的回调【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-designMessage 是 antdant-design中用于轻量级全局反馈的组件通常用于展示操作成功、失败或加载中的提示。antd 为 Message 的关闭时机封装了一层 Promise 化接口使开发者可以通过message.open(...).then(...)、message.success(...).then(...)在消息即将关闭时触发后续回调从而把“多条消息依次串行展示”“关闭后执行副作用”等时序逻辑写成清晰、可读的链式代码。本文以仓库中的 thenable 示例 与 配套文档 为线索结合 接口类型定义、util.ts、useMessage.tsx 与 index.tsx 等源码讲解 Promise 接口的用法、类型结构与底层实现原理。一、这个示例在讲什么先看原始 demo 说明thenable.mdzh-CN可以通过then接口在关闭后运行 callback。该用例将在每个 message 将要结束时通过then显示新的 message。en-USmessageprovides a promise interface foronClose. The above example will display a new message when the old message is about to close.一句话概括Message 把“单条消息关闭”这个事件抽象为可 then 的 Promise让onClose这种回调式表达升级为链式编排。示例的运行效果是先弹出“Action in progress..”的 loading 消息约 2.5 秒后它关闭同时紧接着弹出message.success(Loading finished)再过 2.5 秒该条关闭继续弹出message.info(...)。三条消息严格按序首尾衔接而不是同时弹出。二、完整示例代码与逐段拆解示例位于 components/message/demo/thenable.tsx完整代码如下import React from react; import { Button, message } from antd; const App: React.FC () { const [messageApi, contextHolder] message.useMessage(); const success () { messageApi .open({ type: loading, content: Action in progress.., duration: 2.5, }) .then(() message.success(Loading finished, 2.5)) .then(() message.info(Loading finished, 2.5)); }; return ( {contextHolder} Button onClick{success}Display sequential messages/Button / ); }; export default App;拆解其中四个关键点使用 Hooks 形式获得实例const [messageApi, contextHolder] message.useMessage();。hooks 方式能让 message 读取到当前组件树上下文Context/ConfigProvider并把承载消息的contextHolder显式挂载到 JSX 中详细说明见 FAQWhy I can not access context...。open返回可 then 的返回值messageApi.open({ type: loading, ... })的返回值不是void而是MessageType——它是一个PromiseLike见下节类型分析因此可以直接.then(...)。链式编排“上一条关闭后才弹下一条”.then(() message.success(Loading finished, 2.5))中的回调会在当前这条 loading 消息关闭之后被调用。由于回调里本身又触发一条新消息并再次返回MessageType于是可以继续.then(...)无限衔接。2.5是 duration 参数message.success(Loading finished, 2.5)是messagelevel的缩写形式表示新消息展示 2.5 秒后自动关闭。第二条.then(() message.info(...))同理形成两段首尾相接的“loading → success → info”串行提示序列。提示then回调触发的是“旧消息开始/即将关闭”之后。官方文档措辞是when the message is about to close在文档 index.en-US.md 的 API 章节中则明确写成afterClosecan be called in thenable interface。从仓库实现看实际 resolve 的时机位于关闭动画结束之后详见第五节。三、MessageType既是关闭函数又是 PromiseLike要让链式.then成立核心在于 open 方法的返回值类型。查看 components/message/interface.tsexport interface MessageType extends PromiseLikeboolean { (): void; } export type TypeOpen ( content: JointContent, duration?: number | VoidFunction, onClose?: VoidFunction, ) MessageType;这里有两条关键语义MessageType继承自PromiseLikeboolean因此所有消息 APIopen、info、success、error、warning、loading的返回值都具备then(onFulfilled, onRejected)能力而boolean的 resolve 值表示“该消息确实被正常关闭了”。MessageType本身还是可调用函数(): void调用该返回值即可立即手动关闭这条消息。也就是说拿到返回值后你有两种关闭手段——等它自动关闭duration 耗尽后 resolve或主动调用返回值等价于立刻 close。这与文档 API 中提到的message.destroy(key)是不同粒度的控制方式返回值关闭针对的是单条消息实例。类型层面还定义了五种快捷方法与open的统一签名interface.tsMessageInstance上每个方法的参数都兼容(content, duration?, onClose?)与(config)两种形态。官方文档index.en-US.md随后也给出了 thenable 接口的两种规范写法messagelevel.then(afterClose)messagelevel.then(afterClose)其中level指success/info/error/warning/loading之一then的结果仍然是 Promise可继续链式调用。四、底层实现wrapPromiseFn 如何把“关闭”变成 Promise示例能链式执行关键在工具函数 wrapPromiseFn。它接收一个openFn把“打开一条消息 在关闭回调里 resolve”的逻辑封装成一个 PromiseLike 对象export function wrapPromiseFn(openFn: (resolve: VoidFunction) VoidFunction) { let closeFn: VoidFunction; const closePromise new Promiseboolean((resolve) { closeFn openFn(() { resolve(true); }); }); const result: any () { closeFn?.(); }; result.then (filled: VoidFunction, rejected: VoidFunction) closePromise.then(filled, rejected); result.promise closePromise; return result; }可以把它拆成三层来看创建一个内部的PromisebooleanopenFn在执行时会收到一个resolve回调这个回调就是“消息关闭完成”的信号。返回一个可调用对象resultresult本身是函数() closeFn?.()即前面说的“主动关闭”能力同时给它挂上.then把调用转发给内部的closePromise从而在外部得到PromiseLike外观。result.promise暴露真实 Promise如果确实需要原生 Promise 能力如await、Promise.all可以从返回值的.promise字段取到真实的closePromise。换句话说MessageType是“关闭句柄”和“PromiseLike”的混合体链式.then注册的回调只有在内部closePromise被 resolve 后才会执行。五、resolve 的触发链路关闭动画结束 → 回调执行现在把 Demo 代码与源码串起来看一条.then回调到底何时执行。以 hooks 形式为例入口在 useMessage.tsx 的 open 实现用户调用messageApi.open(config)代码把onClose包装成() { onClose?.(); resolve(); }传给底层originOpen(...)来自rc-component/notification也就是把用户自定义的 onClose 与 wrapPromiseFn 注入的 resolve 合并先执行用户 onClose再 resolve当这条消息展示时间耗尽duration并完成关闭含退场动画时底层通知机制触发该 onCloseresolve(true)被调用closePromise兑现result.then里注册的后续回调随之执行于是“上一条结束后弹下一条”的链式效果得以成立。如果手动调用返回的MessageType()关闭函数效果是立即关闭该 key 的消息并走同样的 resolve 路径——参见 useMessage.tsx 中 open 返回的关闭函数 调用的close(mergedKey)。需要强调的一点是resolve 与消息关闭是联动的即“先真正关闭完成再执行后续 then 回调”。因此用它做“串行消息”非常合适但若消息被destroy()全局销毁或从未成功渲染行为会因触发路径不同而有所差异测试时请以实际关闭事件为准。六、静态方法版本任务队列与实例就绪示例用的是 hooks 版本如果改用文档里的静态方法形式message.success(content).then(...)实现走的是 index.tsx 的open/typeOpen。它们同样调用wrapPromiseFn包装但内部维护了一个taskQueue 任务队列静态方法首次被调用时flushMessageQueue会在DocumentFragment上懒渲染一个全局GlobalHolder在全局实例尚未就绪前调用会被暂存进队列实例就绪后再统一回放见 index.tsx 的 flushMessageQueue。对使用者来说两种写法都能拿到可.then的返回值差异主要在于静态方法message.success(...)无法读取组件上下文Context / ConfigProvider locale、主题等参见官方 FAQ 关于 context 的说明Hooks 方法message.useMessage()能继承组件上下文是官方推荐用法但需要把contextHolder挂载进你的 JSX。官方文档index.en-US.md对本示例的定位也印证了这一点thenable.tsx被登记在“Promise interface”示例条目下供文档站展示与测试。七、类型与测试层面的保障仓库不仅给出了示例还用类型测试和单元测试锁定了这一行为类型层面type.test.tsx 中直接出现message.success(yes!!!).then(filled)与带拒绝回调的message.success(yes!!!).then(filled, rejected)验证.then的可调用签名可被 TypeScript 静态检查接受单元测试层面hooks.test.tsx 中有api.open({ content: good, duration: 1 }).then(() ...)的用例验证打开后消息关闭会触发 then 回调index.test.tsx 中也有message.info(whatever).then(onClose)覆盖静态方法形态的 Promise 接口。这说明“返回 PromiseLike、关闭后触发 then”既是文档承诺的 API也是被测试用例保护的稳定契约。八、实践小结与注意事项结合 thenable 示例 与相关源码可沉淀出如下实践要点何时使用 Promise 接口需要“在上一条提示结束后执行动作”的场景——典型如依次弹出 loading → 结果提示、多阶段操作的分步反馈。示例用open.then连续弹出三条消息正是该模式的教科书式写法。duration 默认值为 3 秒消息若不传 duration默认 3 秒后自动关闭见 useMessage.tsx 中 DEFAULT_DURATION 3以及文档表格中 duration 默认3。置0则不会自动关闭。then 回调发生在关闭之后不要假设.then在消息仍可见时执行如需在“即将关闭”或“可见期间”做交互应改用duration/onClose参数或其他生命周期手段。上下文敏感场景优先 hooks需要在消息中使用 ConfigProvider 主题、locale 或业务 Context 时使用message.useMessage()并把contextHolder渲染进组件树静态方法适用于不需要上下文的轻量场景。手动提前关闭MessageType同时是可调用函数调用返回值可立刻关闭该条消息并触发对应的 then 链这为“用户主动结束 loading”等交互提供了补充手段。从 demo 目录 还可以看到更多相关示例如 duration、loading、update、hooks 等它们与本例相互补充共同构成 Message 组件的完整用法图谱若需更丰富的全局配置maxCount、top、rtl、stack 等可继续查阅 index.en-US.md 的message.config章节与 ConfigProvider 组件配置。【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-design创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考