![](/img/trans.png)
[英]How can I implement a timer using setTimeout and clearTimeout
[英]How to implement promisified setTimeout with clearTimeout functionality?
下面的实现抛出一个错误(见下面的评论),如何解决这个问题?
interface PromiseWithAbort extends Promise<unknown> {
abort: () => void
}
export const pause = (
ms?: number,
cb?: (...args: unknown[]) => unknown,
...args: unknown[]
): PromiseWithAbort => {
let timeout
// Error: Property 'abort' is missing in type 'Promise<unknown>'
// but required in type 'PromiseWithAbort'.
const promise: PromiseWithAbort = new Promise((resolve, reject) => {
timeout = setTimeout(async () => {
try {
resolve(await cb?.(...args))
} catch (error) {
reject(error)
}
}, ms)
})
promise.abort = () => clearTimeout(timeout)
return promise
}
问题是您分配给promise
的 promise 没有abort
属性,但是您分配给promise
的类型需要一个。 解决此问题的一种简单方法是在将其分配给promise
之前添加它。 (这也将使您摆脱promise
上的显式类型。)
还有其他一些事情,请参阅***
评论:
interface PromiseWithAbort extends Promise<unknown> {
abort: () => void
}
export const pause = (
ms?: number,
cb?: (...args: unknown[]) => unknown,
...args: unknown[]
): PromiseWithAbort => {
let timeout: number; // *** Need the type in order to avoid implicit `any`
// *** Add `abort` to the promise before assigning to `promise`
const promise = Object.assign(
new Promise((resolve, reject) => {
timeout = setTimeout(async () => {
try {
resolve(await cb?.(...args));
} catch (error) {
reject(error);
}
}, ms); // *** `ms` needs a default value, you're optionally passing `undefined`
}), {
abort: () => clearTimeout(timeout)
}
);
return promise;
}
也就是说,在cb
(如果有)返回的 promise 上使用await
并将结果传递给resolve
有点迂回; 相反,您可以将 promise 传递给resolve
,这会将您创建的 promise 解析为cb
返回的那个(如果有的话):
export const pause = (
ms?: number,
cb?: (...args: unknown[]) => unknown,
...args: unknown[]
): PromiseWithAbort => {
let timeout: number;
// *** Add `abort` to the promise before assigning to `promise`
const promise = Object.assign(
new Promise((resolve, reject) => {
timeout = setTimeout(() => { // *** No need for `async`
try {
resolve(cb?.(...args)); // *** No need for `await`, just resolve the promise to `cb`'s promise
} catch (error) {
reject(error);
}
}, ms);
}), {
abort: () => clearTimeout(timeout)
}
);
return promise;
}
Just for what it's worth, I wouldn't add abort
to the promise, not least because when you use .then
or .catch
on that promise or use it in an async
function, the promise you get from them won't have the abort
方法。 相反,您可能会考虑接受AbortSignal
。
我还要删除cb
并让pause
成为纯粹的暂停 function。 cb
不必要地使其复杂化; 您可以只使用.then
或await
,然后直接在代码中调用cb
。
这是一个例子:
class CancelledError extends Error {
constructor(msg = "Operation was cancelled") {
super(msg);
}
}
interface PauseOptions {
signal?: AbortSignal;
silent?: boolean;
}
export const pause = (
ms: number,
{signal, silent = false}: PauseOptions = {}
): Promise<void> => {
return new Promise((resolve, reject) => {
// Function we'll use if the operation is cancelled
const cancelled = () => {
if (!silent) {
reject(new CancelledError());
}
};
// The actual timer
const handle = setTimeout(() => {
if (signal?.aborted) { // It would be rare for this to happen
cancelled();
} else {
resolve();
}
}, ms);
// Handle cancellation
signal?.addEventListener("abort", () => {
clearTimeout(handle);
cancelled();
});
});
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.