https://www.pandanoir.info/entry/2021/04/21/234305

名前から既にワクワクするこのAPIは、なんとPromiseを返すsetTimeout、setInterval関数を提供しています!最高です…

というわけで今回はそれの紹介です。

基本的な使い方

await setTimeout(1000) ←これができるんです!素晴らしくないですか??

top-level await や for-awaitと組み合わせるとこんな感じで書けます

import { setTimeout } from 'timers/promises';

console.log('start');
await setTimeout(1000); // これでいける!!
console.log('1s passed');

import { setInterval } from 'timers/promises';

console.log('start');
for await (const startAt of setInterval(1000, Date.now()) {
  console.log(Date.now() - startAt);
}

特に setTimeout は最高ですね…

キャンセルする

キャンセルはAbortControllerを使ってできます。

import { setTimeout } from 'timers/promises'

const controller = new AbortController();

(async() => {
  console.log('start');
  await setTimeout(1000, null, { signal: controller.signal });
  console.log('end');
})().catch(()=>console.log('aborted'));

// 上の setTimeout が発火する前にキャンセルしてみる
await setTimeout(500);
controller.abort();

AbortController ということは React の useEffect とも相性が良いです。

useEffect(() => {
  const controller = new AbortController();
  const { signal } = controller;

  (async () => {
    const res = await fetch('<http://example.com>', { signal });
    await setTimeout(1000, null, { signal });
    console.log(res);
  })();

  return () => controller.abort();
});

clearTimeout を使うよりグッとシンプルになりました。

timers/promises の 型定義

型定義がまだなさそうだったので自分で書きました。おそらく合ってますが間違えている可能性はあります。

module 'timers/promises' {
  const setTimeout: <T>(
    delay?: number,
    value?: T,
    options?: { ref?: boolean; signal?: AbortSignal }
  ) => Promise<T>;
  const setImmediate: <T>(
    value?: T,
    options?: { ref?: boolean; signal?: AbortSignal }
  ) => Promise<T>;
  const setInterval: <T>(
    delay?: number,
    value?: T,
    options?: { ref?: boolean; signal?: AbortSignal }
  ) => AsyncIterable<T>;
}

debounce や throttle を実装してみる