かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

JavaScript async / await で同期的に setTimeout (sleep) したい

setTimeout を同期的に使いたい場合、setTimeout は Promise を返さないので async / await を使って呼び出したい場合は Promise を返す関数にしてやればOK

Promise を返し内部で setTimeout する関数にすればOK

const sleep = (callback, delay = 1000) => {
  return new Promise((resolve) => {
    return setTimeout(() => {
      callback();
      return resolve();
    }, delay);
  });
};

async function myFunction() {
  console.log('start');
  await sleep(() => { console.log('timeout!') });
  console.log('end');
}

myFunction();
// => start
// -- 1000ms --
// => timeout!
// => end 

処理が単純なら別関数にしなくても OK

async function myFunction() {
  const callback = () => console.log('timeout!');
  console.log('start');
  await new Promise((resolve) => setTimeout(() => {
    return resolve();
  }, 1000));
  callback(); // setTimeout 内で実行する必要なし
  console.log('end');
}

myFunction() を実行したら同じ結果になる。

カリー化して同期的に setTimeout して処理を実行できる関数を作る

setTimeout 後に実行したい関数を保持させて呼び出し時に引数を渡す関数を作ってみます。

const sleepCallback = (callback, delay = 500) => (...props) => {
  return new Promise((resolve) => setTimeout(() => {
    return resolve( callback(...props) );
  }, delay));
};

const sum = (...props) => props.reduce((a, v) => a += v);
const sleepAfterSum = sleepCallback(sum);

async function myFunction(...props) {
  const a = await sleepAfterSum(...props);
  console.log(a);
}

myFunction(1,2,3,4,5,6,7,8,9,10);
// --- 500ms ---
// => 55

setTimeout で単純に処理を止める関数にしてみる

const sleep = (delay = 500) => new Promise(resolve => setTimeout(resolve, delay));

const sum = (...props) => props.reduce((a, v) => a += v);

async function myFunction(...props) {
  await sleep();
  const a = sum(...props);
  console.log(a);
}

myFunction(1,2,3,4,5,6,7,8,9,10);
// --- 500ms ---
// => 55

この方が汎用性高そう?

setTimeout で debounce に state を変更するサンプル

See the Pen setTimeout with async / await by KIKIKI (@kikiki_kiki) on CodePen.

 
おわり


[参考]