实现 sleep 延迟函数

使用 Promise 实现 JavaScript 的 sleep 函数

问题

实现一个 sleep / delay 函数,使代码暂停执行指定的时间。

async function main() {
  console.log('开始');
  await sleep(1000); // 暂停 1 秒
  console.log('1秒后');
}

解答

基础实现

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// 使用示例
async function demo() {
  console.log('开始');
  await sleep(1000);
  console.log('1秒后执行');
}

demo();

带返回值的版本

function sleep(ms, value) {
  return new Promise(resolve => setTimeout(() => resolve(value), ms));
}

// 使用示例
async function demo() {
  const result = await sleep(1000, 'hello');
  console.log(result); // 'hello'
}

可取消的 sleep

function sleep(ms) {
  let timeoutId;
  let rejectFn;

  const promise = new Promise((resolve, reject) => {
    rejectFn = reject;
    timeoutId = setTimeout(resolve, ms);
  });

  // 添加取消方法
  promise.cancel = () => {
    clearTimeout(timeoutId);
    rejectFn(new Error('Sleep cancelled'));
  };

  return promise;
}

// 使用示例
async function demo() {
  const sleepPromise = sleep(5000);
  
  // 2秒后取消
  setTimeout(() => sleepPromise.cancel(), 2000);
  
  try {
    await sleepPromise;
    console.log('完成');
  } catch (e) {
    console.log(e.message); // 'Sleep cancelled'
  }
}

循环中使用

async function countdown(n) {
  for (let i = n; i > 0; i--) {
    console.log(i);
    await sleep(1000);
  }
  console.log('结束');
}

countdown(3);
// 输出: 3 -> (1秒) -> 2 -> (1秒) -> 1 -> (1秒) -> 结束

关键点

  • sleep 本质是用 Promise 包装 setTimeout
  • 必须配合 async/await.then() 使用才能实现暂停效果
  • setTimeout 的回调直接使用 resolve,无需额外包装
  • 可取消版本需要保存 timeoutId 并暴露 cancel 方法
  • 在循环中使用时,必须用 for 循环 + awaitforEach 无法正确等待