javascript - Vuex 动作取消承诺
问题描述
我希望能够从我的 Vue 组件中取消已启动的承诺,特别是 Vuex 操作返回的承诺。
我的用例是我的 Vuex 操作轮询端点的状态,如果用户执行某个操作(示例中的关闭函数),我希望能够取消该轮询。
我创建了一个从另一个 stackoverflow 答案中提取的自定义 CancelablePromise 类,但它不适用于 Vuex。
可取消的承诺类(来自https://stackoverflow.com/a/60600274/2152511)
export class CancellablePromise<T> extends Promise<T> {
private onCancel: () => void;
constructor(
executor: (
resolve: (value?: T | PromiseLike<T>) => void,
reject: (reason?: any) => void,
onCancel: (cancelHandler: () => void) => void
) => void
) {
let onCancel: () => void;
super((rs, rj) =>
executor(rs, rj, (ch: () => void) => {
onCancel = ch;
})
);
this.onCancel = onCancel;
}
public cancel(): void {
if (this.onCancel) {
this.onCancel();
}
}
}
行动
async [SomeAction.foo]({ state, dispatch, commit, rootGetters }) {
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);
onCancel(() => {
clearInterval(interval);
reject();
});
});
return cancellablePromise;
}
零件
data: (() => {
promise: undefined as CancellablePromise<any> | undefined
}),
async call() {
this.promise = this.$store
.dispatch(SomeAction.foo)
.then(response => {
// do something
}) as CancellablePromise<any>;
},
close(): void {
if (this.promise) {
this.promise.cancel(); // outputs cancel is not a function
}
}
问题出现在不是close
函数this.promise.cancel
的函数中。
这在我看来是因为返回的对象dispatch
确实是 Promise,而不是 CancellablePromise。我的怀疑来自查看Vuex 源代码,它似乎new Promise
再次从操作返回的创建一个Promise
。我对 Typescript 的类型系统不是很熟悉,但除非我误读了这段代码,否则我认为我的代码CancellablePromise
在这里“迷路”了。
我怎样才能在这里完成我想做的事情?
解决方案
扩展 Promise 是混乱且不必要的。这更正常
- 将 Promise 的
reject
方法暴露给更广泛的世界(在 Promise 的构造函数之外),并在必要时调用它以使 Promise 采用其错误路径。 - 与感兴趣的 Promise 竞争“取消 Promise”,但这不是必需的,因为该
setInterval
过程的 Promise 使reject
方法可用。
像这样的东西应该这样做(未经测试)。
行动
async [SomeAction.foo]({ state, dispatch, commit, rootGetters }) {
let reject_, interval;
const promise = new Promise((resolve, reject) => {
reject_ = reject; // externalise the reject method
interval = setInterval(async () => {
const status = await dispatch(SomeAction.bar);
if (status === 'goodstatus') {
resolve();
} else if (status === 'badstatus') {
reject(new Error(status)); // for example
} else {
// ignore other states ???
}
}, 2000);
});
promise.cancel = reject_; // decorate promise with its own reject method.
return promise.always(() => { clearInterval(interval) }); // clear the interval however the promise settles (resolve() or reject() above, or promise.cancel() externally).
}
零件
data: (() => {
cancel: null
}),
async call() {
this.close(new Error('new call was made before previous call completed')); // may be a good idea
let promise = this.$store.dispatch(SomeAction.foo); // don't chain .then() yet otherwise the .cancel property is lost.
this.cancel = promise.cancel; // store the means to force-reject the promise;
return promise.then(response => { // now chain .then()
// do something
})
.catch(error => {
console.log(error);
throw error;
});
},
close(reason): void {
if (this.cancel) {
this.cancel(reason || new Error('cancelled'));
}
}
推荐阅读
- c++ - C++ 程序如何根据编译选项打印 0 或 1?
- linux - smartmontools 替代方案或建议
- python - 如何使用 pushshift 获得最高分的子 reddit 提交?
- arrays - 在 VBA 中,如何读取作为数组的书签?
- python - Elasticsearch 7.11 Python 扫描是无限的
- python - Selenium chrome.options 中用户数据目录的正确目录是什么
- java - Java:布尔输出假但应该输出真
- google-analytics - Google Analytics - 对于实时报告,您如何列出所有活跃用户和浏览量?
- jmeter - jMeter 对我的请求做了什么 - 它正在获得响应但不应该
- c# - 如何在 C# MongoDB 中为多态类映射定义默认鉴别器