繁体   English   中英

如何使用 clearTimeout 功能实现承诺的 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的 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不必要地使其复杂化; 您可以只使用.thenawait ,然后直接在代码中调用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM