考虑这个简单的示例,可能是您编写了几次但现在可中止的函数:
/**
*
* @param {number} delay
* @param {AbortSignal} [abortSignal]
* @returns {Promise<void>}
*/
export default function timeoutPromise(delay, abortSignal) {
return new Promise((resolve, reject) => {
if(abortSignal) {
abortSignal.throwIfAborted();
}
const timeout = setTimeout(() => {
resolve();
}, delay);
abortSignal.addEventListener("abort", () => {
clearTimeout(timeout);
reject(new Error("Aborted"));
});
});
}
明显的问题是,如果超时正常成功,这不会清除 eventListener。可以做到,但是很难看:
/**
*
* @param {number} delay
* @param {AbortSignal} [abortSignal]
* @returns {Promise<void>}
*/
export default function timeoutPromise(delay, abortSignal) {
return new Promise((resolve, reject) => {
if(abortSignal && abortSignal.aborted) {
reject(new Error("timeoutPromise aborted"));
}
let timeout = null;
function abortHandler() {
clearTimeout(timeout);
reject(new Error("timeoutPromise aborted"))
}
timeout = setTimeout(() => {
if(abortSignal) {
abortSignal.removeEventListener("abort", abortHandler);
}
resolve();
}, delay);
if(abortSignal) {
abortSignal.addEventListener("abort", abortHandler, {once: true});
}
});
}
对于这么简单的事情来说,有很多代码。我这样做对吗还是有更好的方法?
您可以对
AbortSignal
上的方法调用使用可选链接:
function delay(ms, signal) {
return new Promise((resolve, reject) => {
function done() {
resolve();
signal?.removeEventListener("abort", stop);
}
function stop() {
reject(this.reason);
clearTimeout(handle);
}
signal?.throwIfAborted();
const handle = setTimeout(done, ms);
signal?.addEventListener("abort", stop);
});
}