如何在Vue组件中取消Vuex Action返回的可取消Promise?
解决Vuex Action返回的Promise无法取消的问题
你猜的完全没错!Vuex的dispatch方法内部会用Promise.resolve()重新包装Action返回的Promise,这就导致你自定义的CancellablePromise被转换成了标准Promise实例,自然找不到cancel方法。下面给你几个可行的解决方案,从标准API到自定义实现都有:
方案1:使用标准AbortController(推荐)
现代浏览器和Node.js都支持这个原生API,不需要维护自定义Promise类,代码更简洁可靠:
修改Vuex Action
async [SomeAction.foo]({ dispatch }) { const controller = new AbortController(); const signal = controller.signal; const pollPromise = new Promise<void>((resolve, reject) => { const interval = setInterval(async () => { // 提前检查是否已取消 if (signal.aborted) { clearInterval(interval); reject(new Error('轮询已取消')); return; } const status = await dispatch(SomeAction.bar); if (status === "goodstatus") { clearInterval(interval); resolve(); } else if (status === "badstatus") { clearInterval(interval); reject(new Error('状态异常')); } }, 2000); // 监听取消信号 signal.addEventListener('abort', () => { clearInterval(interval); reject(new Error('轮询已取消')); }); }); // 返回包含Promise和取消方法的对象 return { promise: pollPromise, cancel: () => controller.abort() }; }
修改Vue组件代码
data: (() => ({ poller: undefined as { promise: Promise<void>, cancel: () => void } | undefined })), async call() { this.poller = this.$store.dispatch(SomeAction.foo); try { await this.poller.promise; // 轮询成功后的逻辑 console.log('轮询完成'); } catch (err) { // 忽略取消导致的错误,处理其他异常 if ((err as Error).message !== '轮询已取消') { console.error('轮询出错:', err); } } finally { this.poller = undefined; } }, close(): void { this.poller?.cancel(); this.poller = undefined; }
方案2:改造自定义CancellablePromise(兼容旧环境)
如果必须用自定义Promise类,不要让Vuex包装它,而是返回一个包含Promise和取消方法的对象:
修改Vuex Action
async [SomeAction.foo]({ dispatch }) { let cancelHandler: () => void; const cancellablePromise = new CancellablePromise<any>((resolve, reject, onCancel) => { const interval = setInterval(async () => { const status = await dispatch(SomeAction.bar); if (status === "goodstatus") { clearInterval(interval); resolve(); } else if (status === "badstatus") { clearInterval(interval); reject(); } }, 2000); cancelHandler = () => { clearInterval(interval); reject(new Error('轮询已取消')); }; onCancel(cancelHandler); }); // 直接返回包含Promise和取消方法的对象 return { promise: cancellablePromise, cancel: cancelHandler }; }
修改Vue组件代码
data: (() => ({ poller: undefined as { promise: CancellablePromise<any>, cancel: () => void } | undefined })), async call() { this.poller = this.$store.dispatch(SomeAction.foo); try { await this.poller.promise; // 成功逻辑 } catch (err) { // 错误处理 } }, close(): void { this.poller?.cancel(); this.poller = undefined; }
为什么原来的方案不行?
Promise规范里,Promise.resolve()会将自定义Promise子类的实例转换成标准Promise实例——简单说就是Vuex的包装操作把你的CancellablePromise“降级”成了普通Promise,所有自定义方法自然就丢失了。
内容的提问来源于stack exchange,提问作者Jokab
相关产品推荐
相关产品推荐

