实现一个 sleep 函数
手写一个 sleep 函数,实现异步等待指定毫秒数的功能
问题
在 JavaScript 中,我们经常需要让程序暂停一段时间后再继续执行。虽然 JavaScript 没有内置的 sleep 函数(不像其他语言如 Python),但我们可以利用 Promise 和 async/await 来实现一个类似的功能。
要求实现一个 sleep(ms) 函数,调用后能够让程序等待指定的毫秒数后再继续执行。
解答
/**
* 实现 sleep 函数
* @param {number} ms - 等待的毫秒数
* @returns {Promise} 返回一个在指定时间后 resolve 的 Promise
*/
function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
// 方法二:使用 async/await 的工具函数
function sleep2(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 方法三:支持取消的 sleep
function sleepWithCancel(ms) {
let timeoutId;
const promise = new Promise((resolve, reject) => {
timeoutId = setTimeout(resolve, ms);
});
// 添加取消方法
promise.cancel = () => {
clearTimeout(timeoutId);
};
return promise;
}
使用示例
// 示例1:基本使用
async function example1() {
console.log('开始执行');
await sleep(1000); // 等待 1 秒
console.log('1秒后执行');
await sleep(2000); // 等待 2 秒
console.log('再过2秒后执行');
}
example1();
// 示例2:在循环中使用
async function example2() {
for (let i = 1; i <= 5; i++) {
console.log(`第 ${i} 次执行`);
await sleep(1000); // 每次间隔 1 秒
}
}
example2();
// 示例3:配合 Promise.then 使用
function example3() {
console.log('开始');
sleep(1000)
.then(() => {
console.log('1秒后');
return sleep(1000);
})
.then(() => {
console.log('2秒后');
});
}
example3();
// 示例4:可取消的 sleep
async function example4() {
console.log('开始等待');
const sleepPromise = sleepWithCancel(5000);
// 2秒后取消等待
setTimeout(() => {
sleepPromise.cancel();
console.log('等待被取消');
}, 2000);
try {
await sleepPromise;
console.log('等待完成'); // 不会执行
} catch (error) {
console.log('等待被中断');
}
}
example4();
// 示例5:模拟接口请求重试
async function fetchWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url);
return response;
} catch (error) {
console.log(`第 ${i + 1} 次请求失败`);
if (i < maxRetries - 1) {
await sleep(1000 * (i + 1)); // 递增等待时间
}
}
}
throw new Error('请求失败');
}
关键点
-
Promise 封装:sleep 函数返回一个 Promise 对象,通过
setTimeout在指定时间后调用resolve,使 Promise 变为完成状态 -
async/await 配合:sleep 函数必须配合
await关键字使用,才能实现真正的”等待”效果,否则只是返回一个 Promise 对象 -
非阻塞特性:JavaScript 的 sleep 是非阻塞的,不会阻塞主线程,其他代码仍可以正常执行
-
应用场景:
- 控制异步操作的执行节奏
- 实现轮询间隔
- 模拟网络延迟
- 接口请求重试机制
-
注意事项:
- sleep 只能在 async 函数中使用 await 调用
- 不要在同步代码中期望 sleep 能阻塞执行
- 如果需要取消等待,可以扩展实现支持取消的版本
目录