高级前端
js
【Q435】JS 如何实现一个 sleep/delay 函数

JS 如何实现一个 sleep/delay 函数

更多描述 sleep 函数实现较为简单,也常作为对 Promise 的代码考察。在日常工作中,特别是 Node 写脚本时,常用它控制频率。

实现一个 sleep 函数格式如下:

type sleep = (s: number) => Promise<void>;

追问:

实现一个 delay 函数格式如下,在 N 毫秒之后执行函数,并以函数结果作为返回值

function delay(func, seconds, ...args) {}
 
// 在 3s 之后返回 hello, world
await delay((str) => str, 3000, "hello, world");
 
// 在 3s 之后返回 hello, world,第一个函数可返回 promise
await delay((str) => Promise.resolve(str), 3000, "hello, world");

Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 442 (opens in a new tab)

Author 回答者: yuuk (opens in a new tab)

function delay(time) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, time);
  });
}

Author 回答者: canvascat (opens in a new tab)

const sleep = (t = 0) => new Promise((resolve) => setTimeout(resolve, t));
 
const delay = <T extends (...args: any[]) => any>(
  func: T,
  seconds: number,
  ...args: Parameters<T>
): Promise<ReturnType<T>> => sleep(seconds).then(() => func(...args));

Author 回答者: canvascat (opens in a new tab)

function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if (new Date().getTime() - start > milliseconds) {
      break;
    }
  }
}

from: kurento-utils-js (opens in a new tab)

Author 回答者: shfshanyue (opens in a new tab)

sleep 函数既是面试中常问到的一道代码题,也是日常工作,特别是测试中常用的一个工具函数。

实现起来较为简单,一行即可实现,代码如下

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

实现一个 delay 稍微复杂点,代码见 【Q435】JS 如何实现一个 sleep/delay 函数 (opens in a new tab)

function delay(func, seconds, ...args) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Promise.resolve(func(...args))
        .then(resolve)
        .catch(reject);
    }, seconds);
  });
}

使用代码测试:

console.log(new Date());
delay(
  (str) => {
    console.log(new Date());
    return str;
  },
  3000,
  "shanyue",
).then((o) => console.log(o));

Author 回答者: heretic-G (opens in a new tab)

type resolving<P = any> = (res: P) => void;
 
function delay<P extends any[], T extends (...args: P) => any = () => null>(
  func: T,
  seconds: number = 0,
  ...args: P
): Promise<ReturnType<T>> {
  let _resolve: resolving<ReturnType<T>>;
  let _reject: resolving;
  setTimeout(() => {
    try {
      _resolve(func(...args));
    } catch (e) {
      _reject(e);
    }
  }, seconds);
  return new Promise((resolve, reject) => {
    _resolve = resolve;
    _reject = reject;
  });
}

Author 回答者: shfshanyue (opens in a new tab)

@heretic-G 如果写成 TS 的话,如何标记 type

Author 回答者: hengistchan (opens in a new tab)

async function delay(func, second, ...args) {
  return await new Promise((resolve) => {
    setTimeout(() => {
      resolve(func(...args));
    }, second);
  });
}
 
delay((str) => str, 3000, "Hello world").then((res) => {
  console.log(res);
});

Author 回答者: shfshanyue (opens in a new tab)

@HengistChan 如果 return promise 的话,应该可以不需要加 async/await

Author 回答者: shengrongchun (opens in a new tab)

使用setTimeout有意义吗

Author 回答者: justorez (opens in a new tab)

实现一个 delay 稍微复杂点,代码见 【Q435】JS 如何实现一个 sleep/delay 函数 (opens in a new tab)

function delay(func, seconds, ...args) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Promise.resolve(func(...args))
        .then(resolve)
        .catch(reject);
    }, seconds);
  });
}

@shfshanyue setTimeout 里应该需要 try/catch 一下 Promise.resolve().catch() 捕捉不到异常。