Promise 会如何逃逸到事件循环?

问题描述 投票:0回答:1

我需要一个独立的抽象来消除函数调用的抖动。虽然 deno/async 提供了这样的功能,但 AFAICT 无法取消已经运行的功能(例如,杀死子进程)。所以,前几天,我尝试自己实现这个需求:

function debounced<T>(
  fn: (signal: AbortSignal) => Promise<T>,
  ms: number,
): () => Promise<T> {
  let controller: AbortController | null = null;
  return async () => {
    controller?.abort();
    controller = new AbortController();
    const signal = controller.signal;
    await delay(ms, { signal });
    return await fn(signal);
  };
}

此测试应展示预期的行为:

Deno.test(async function debouncedAbortsRunningFunctions() {
  // Arrange
  using time = new FakeTime();
  const enter = spy();
  const exit = spy();

  const fn = debounced(async (signal) => {
    enter();

    // simulate a long running function
    await delay(100, { signal });

    exit();
  }, 100); // 100ms delay before calling the function

  // Act
  const p1 = fn();
  time.tick(50);
  const p2 = fn();
  time.tick(150);
  const p3 = fn();

  time.tick(1000);
  const actual = await Promise.allSettled([p1, p2, p3]);

  // Assert
  assertEquals(actual[0].status, "rejected");
  assertEquals(actual[1].status, "rejected");
  assertEquals(actual[2].status, "fulfilled");

  assertSpyCalls(enter, 2); // 2 because the first call was aborted during the delay
  assertSpyCalls(exit, 1); // 1 because the second call was aborted mid-execution
});

但是,我越来越

error: Promise resolution is still pending but the event loop has already resolved.

在 NodeJs 中运行等效代码会得到

(uncaught error) error: (in promise) AbortError: The signal has been aborted

我认为这表明未绑定/未等待的承诺以某种方式转义为“后台任务”,因此 AbortError 异常会引发事件循环。我只是不知道这会如何以及在哪里发生。

此时,我已经尝试了多种

debounced()
的实现,使用
new Promise(...)
等等。

我迷路了。如有任何帮助,我们将不胜感激!

node.js typescript async-await deno debouncing
1个回答
0
投票

你的测试确实在被

p1
ed 之前就拒绝了
await
(通过
Promise.allSettled
),这就是未处理的拒绝的来源。

我对 deno/测试不太熟悉,但我建议你尝试一下

// act
const p1 = fn();
const p2 = delay(50).then(fn);
const p3 = delay(200).then(fn);

const promise = Promise.allSettled([p1, p2, p3]);
time.tick(1200);
const actual = await promise;

任何拒绝都应该能够逃脱

Promise.allSettled
的处理(除非 Promise 构造和
allSettled
调用之间存在同步异常)。

© www.soinside.com 2019 - 2024. All rights reserved.