如何使用 clearTimeout 功能实现 promisified setTimeout?
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
的承诺没有 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
(如果有的话)返回的承诺上使用 await
并将结果传递给 resolve
有点迂回;相反,您可以将承诺传递给 resolve
,这会将您创建的承诺解析为 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;
}
就其价值而言,我不会将 abort
添加到承诺中,尤其是因为当您在该承诺上使用 .then
或 .catch
或在async
函数,你从他们那里得到的承诺不会有 abort
方法。相反,您可以考虑接受 AbortSignal
.
我还会删除 cb
并使 pause
成为一个纯粹的暂停功能。 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();
});
});
};
下面的实现会抛出一个错误(见下面的评论),如何解决这个问题?
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
的承诺没有 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
(如果有的话)返回的承诺上使用 await
并将结果传递给 resolve
有点迂回;相反,您可以将承诺传递给 resolve
,这会将您创建的承诺解析为 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;
}
就其价值而言,我不会将 abort
添加到承诺中,尤其是因为当您在该承诺上使用 .then
或 .catch
或在async
函数,你从他们那里得到的承诺不会有 abort
方法。相反,您可以考虑接受 AbortSignal
.
我还会删除 cb
并使 pause
成为一个纯粹的暂停功能。 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();
});
});
};