JavaScript中实现sleep功能的方法
技术背景
在JavaScript里,并没有像其他编程语言那样原生的 sleep()
函数。这是由于JavaScript采用单线程事件驱动模型,若实现阻塞式的 sleep()
会让整个程序陷入停顿,从而影响用户体验。不过,在一些场景下,我们的确需要实现类似“休眠”的功能,比如在执行某个操作后等待一段时间再执行下一个操作。
实现步骤
1. 使用Promise和setTimeout实现
可以借助 Promise
和 setTimeout
来实现 sleep
功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
async function demo() { for (let i = 0; i < 5; i++) { console.log(`Waiting ${i} seconds...`); await sleep(i * 1000); } console.log('Done'); }
demo();
|
2. 单行程写法
1
| await new Promise(r => setTimeout(r, 2000));
|
3. 作为函数
1
| const sleep = ms => new Promise(r => setTimeout(r, ms));
|
4. TypeScript实现
1
| const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
5. 不同运行环境的实现
Node.js 16+
1 2 3
| import {setTimeout} from 'timers/promises';
await setTimeout(1000);
|
Bun.js
核心代码
通用实现
1
| const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
TypeScript带Abort Signal实现
1 2 3 4 5 6 7 8 9
| const wait = (x: number, signal?: AbortSignal): Promise<number> => { return new Promise((s, f) => { const id = setTimeout(s, x, x); signal?.addEventListener('abort', () => { clearTimeout(id); f('AbortError'); }); }); };
|
最佳实践
- 使用
async/await
:在 async
函数里使用 await sleep()
能让代码更具可读性。 - 避免阻塞主线程:尽量别使用阻塞式的
sleep
实现,以免影响用户体验。 - 考虑兼容性:要是需要兼容旧版本的Node.js或者浏览器,可以使用Babel进行转译。
常见问题
1. await
只能在 async
函数中使用
await
只能在以 async
关键字修饰的函数中执行,或者在部分支持的环境里的脚本顶层使用。
2. 阻塞式 sleep
不可取
阻塞式的 sleep
会让整个线程陷入停顿,影响程序性能和用户体验。大多数情况下,建议使用非阻塞式的 sleep
实现。
3. 浏览器对某些特性支持有限
例如 Atomics.wait
在浏览器中的支持极为有限,大部分浏览器不允许在主线程使用。