文章中英模式
布鲁斯前端JS面试题目 - 实现 Promise Sleep 函数
学习如何实现 JavaScript 中的 Promise Sleep 函数,处理延迟执行、定时任务与动画,掌握异步程序设计的基础工具。
文章中英模式
懒得看文章?那就来看视频吧
Promise Sleep 函数概述
Promise Sleep 函数是一个简单但实用的工具,它能让代码暂停执行指定的时间。在各种异步操作中,sleep 函数非常有用,尤其是需要延迟执行、模拟网络延迟或控制动画节奏时。
为什么需要 Sleep 函数?
- 1.
控制执行节奏
:在连续操作之间添加延迟,避免过度频繁的操作 - 2.
模拟网络延迟
:测试代码对延迟的处理能力 - 3.
动画与视觉效果
:控制连续视觉变化的间隔 - 4.
API 限流
:避免短时间内发送过多请求 - 5.
重试机制
:实现指数退避等重试策略
基本 Promise Sleep 实现
下面是一个简单的 Promise Sleep 函数实现:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 使用示例
async function example() {
console.log('开始');
await sleep(2000); // 暂停 2 秒
console.log('2秒后'); // 2秒后执行
}
example();
这个函数创建了一个新的 Promise,在指定的毫秒数后调用 resolve。结合 async/await 语法,可以让代码暂停执行指定的时间。
进阶 Promise Sleep 功能
我们可以扩展基本的 sleep 函数,增加更多功能:
带返回值的 Sleep
function sleepWithValue(ms, value) {
return new Promise(resolve => setTimeout(() => resolve(value), ms));
}
// 使用范例
async function example() {
console.log('开始');
const result = await sleepWithValue(2000, '延迟返回的数据');
console.log(result); // 2秒后显示:延迟返回的数据
}
example();
可取消的 Sleep
function cancellableSleep(ms) {
let timeoutId;
const promise = new Promise(resolve => {
timeoutId = setTimeout(resolve, ms);
});
// 添加取消方法
promise.cancel = function() {
clearTimeout(timeoutId);
};
return promise;
}
// 使用示例
async function example() {
console.log('开始');
const sleepPromise = cancellableSleep(5000);
// 2秒后取消休眠
setTimeout(() => {
console.log('取消休眠');
sleepPromise.cancel();
}, 2000);
try {
await sleepPromise;
console.log('5秒后'); // 不会执行,因为已取消
} catch (error) {
console.log('Sleep 被取消');
}
}
example();
实际应用场景
以下是一些 Promise Sleep 函数的实际应用:
1. 实现 API 请求重试机制
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
const { retryDelay = 1000 } = options;
let lastError;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
// 尝试发起请求
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.log(`尝试 ${attempt + 1} 失败: ${error.message}`);
lastError = error;
if (attempt < maxRetries - 1) {
// 使用指数退避策略计算下次重试延迟
const delay = retryDelay * Math.pow(2, attempt);
console.log(`等待 ${delay}ms 后重试...`);
await sleep(delay);
}
}
}
throw lastError;
}
// 使用示例
async function getData() {
try {
const data = await fetchWithRetry('https://api.example.com/data');
console.log('成功获取数据:', data);
} catch (error) {
console.error('所有重试都失败了:', error);
}
}
getData();
2. 创建动画序列
async function animateSequence(element) {
// 设置初始状态
element.style.opacity = '0';
element.style.transform = 'translateY(20px)';
element.style.transition = 'all 0.5s ease-out';
// 确保元素可见
element.style.display = 'block';
// 等待一帧以确保过渡效果生效
await sleep(50);
// 淡入动画
element.style.opacity = '1';
element.style.transform = 'translateY(0)';
// 等待淡入完成
await sleep(500);
// 添加强调效果
element.style.transform = 'scale(1.1)';
await sleep(200);
// 恢复正常大小
element.style.transform = 'scale(1)';
}
// 使用示例
document.getElementById('showButton').addEventListener('click', () => {
const notification = document.getElementById('notification');
animateSequence(notification);
});
3. 限流 API 请求
class RateLimiter {
constructor(requestsPerSecond) {
this.minDelayMs = 1000 / requestsPerSecond;
this.lastRequestTime = 0;
}
async limit() {
const now = Date.now();
const timeElapsed = now - this.lastRequestTime;
if (timeElapsed < this.minDelayMs) {
// 计算需要等待的时间
const waitTime = this.minDelayMs - timeElapsed;
await sleep(waitTime);
}
this.lastRequestTime = Date.now();
}
}
// 使用示例 - 每秒最多发送2个请求
const limiter = new RateLimiter(2);
async function fetchWithRateLimit(url) {
await limiter.limit();
return fetch(url).then(res => res.json());
}
// 示范多次调用
async function fetchMultipleData() {
console.log('开始获取数据...');
// 这些请求将被限流,每秒最多执行2个
const results = await Promise.all([
fetchWithRateLimit('https://api.example.com/1'),
fetchWithRateLimit('https://api.example.com/2'),
fetchWithRateLimit('https://api.example.com/3'),
fetchWithRateLimit('https://api.example.com/4')
]);
console.log('所有数据获取完成', results);
}
fetchMultipleData();