核心原理
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
作用:创建一个延迟指定毫秒数后才会 resolve 的 Promise,用于实现异步等待。
执行流程
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
// 执行流程可视化
console.log('1. 开始执行')
sleep(2000).then(() => {
console.log('3. 2秒后执行')
})
console.log('2. 立即执行,不阻塞')
// 输出顺序:
// 1. 开始执行
// 2. 立即执行,不阻塞
// 3. 2秒后执行
详细分析
1. Promise 构造器
new Promise(resolve => setTimeout(resolve, delay))
resolve是 Promise 提供的回调函数setTimeout在延迟后调用resolve- 当
resolve被调用时,Promise 状态变为fulfilled
2. 返回值
返回一个 Promise 对象,可以链式调用 .then() 或使用 async/await
使用方式
方式1:Promise.then()
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
console.log('开始')
sleep(1000).then(() => {
console.log('1秒后')
return sleep(1000)
}).then(() => {
console.log('2秒后')
})
方式2:async/await
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
async function demo() {
console.log('开始')
await sleep(1000)
console.log('1秒后')
await sleep(1000)
console.log('2秒后')
}
demo()
方式3:配合循环使用
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
async function countdown(seconds) {
for (let i = seconds; i > 0; i--) {
console.log(`${i} 秒...`)
await sleep(1000)
}
console.log('时间到!')
}
countdown(5)
实际应用场景
场景1:轮询
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
async function pollData() {
let retries = 3
while (retries > 0) {
try {
const data = await fetchData()
if (data) return data
console.log('数据未就绪,1秒后重试...')
await sleep(1000)
retries--
} catch (error) {
console.log('请求失败,重试中...')
await sleep(2000)
retries--
}
}
throw new Error('获取数据失败')
}
场景2:限流/节流
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
async function rateLimitedRequests(urls) {
const results = []
for (const url of urls) {
const result = await fetch(url)
results.push(result)
await sleep(1000) // 每秒最多请求一次
}
return results
}
场景3:模拟加载
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
async function simulateLoading() {
console.log('加载中...')
await sleep(2000)
console.log('✅ 加载完成')
console.log('处理数据...')
await sleep(1500)
console.log('✅ 处理完成')
console.log('保存结果...')
await sleep(1000)
console.log('✅ 保存完成')
}
simulateLoading()
场景4:超时控制
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
function timeout(promise, ms) {
return Promise.race([
promise,
sleep(ms).then(() => {
throw new Error('操作超时')
})
])
}
// 使用
async function fetchWithTimeout() {
try {
const data = await timeout(fetch('https://api.example.com'), 3000)
console.log('数据:', data)
} catch (error) {
console.log('超时错误:', error.message)
}
}
边界情况
1. delay 为 0
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
console.log('1. 同步代码')
sleep(0).then(() => console.log('3. 微任务后执行'))
console.log('2. 同步代码')
// 输出:
// 1. 同步代码
// 2. 同步代码
// 3. 微任务后执行
2. 负数 delay
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
// 负数会被转换为0或接近0
sleep(-1000).then(() => console.log('立即执行(微任务)'))
console.log('同步代码')
3. 非常大的 delay
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
// 最大延迟约 24.8 天(2^31-1 毫秒)
sleep(2 ** 31 - 1).then(() => console.log('永远不会执行?'))
// setTimeout 最大延迟约 24.8 天
性能分析
1. 精度问题
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
async function measurePrecision() {
const start = Date.now()
await sleep(1000)
const actualDelay = Date.now() - start
console.log(`期望: 1000ms, 实际: ${actualDelay}ms`)
console.log(`误差: ${actualDelay - 1000}ms`)
}
measurePrecision()
// 通常在 1000-1010ms 左右(4-10ms 误差)
2. 内存占用
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
// 大量并发 sleep
async function manySleeps() {
const promises = []
for (let i = 0; i < 10000; i++) {
promises.push(sleep(1000))
}
await Promise.all(promises)
console.log('所有 sleep 完成')
}
// 会创建 10000 个定时器,内存占用较大
增强版本
版本1:支持取消
function sleep(delay) {
let timeoutId
const promise = new Promise(resolve => {
timeoutId = setTimeout(resolve, delay)
})
promise.cancel = () => {
clearTimeout(timeoutId)
}
return promise
}
// 使用
const sleepPromise = sleep(5000)
sleepPromise.then(() => console.log('不会执行'))
// 3秒后取消
setTimeout(() => {
sleepPromise.cancel()
console.log('已取消')
}, 3000)
版本2:支持值传递
function sleep(delay, value) {
return new Promise(resolve => setTimeout(() => resolve(value), delay))
}
// 使用
sleep(1000, '完成').then(result => {
console.log(result) // 1秒后输出 '完成'
})
// 配合 async/await
async function demo() {
const result = await sleep(2000, '数据已加载')
console.log(result)
}
版本3:带状态提示
function sleep(delay, options = {}) {
const { signal, onStart, onEnd } = options
return new Promise((resolve, reject) => {
if (signal?.aborted) {
return reject(new Error('已取消'))
}
onStart?.()
const timeoutId = setTimeout(() => {
onEnd?.()
resolve()
}, delay)
signal?.addEventListener('abort', () => {
clearTimeout(timeoutId)
reject(new Error('已取消'))
})
})
}
// 使用 AbortController
const controller = new AbortController()
sleep(5000, { signal: controller.signal })
.then(() => console.log('完成'))
.catch(e => console.log('取消:', e.message))
setTimeout(() => controller.abort(), 2000)
版本4:精确延迟(使用 performance)
function sleepPrecise(delay) {
const start = performance.now()
return new Promise(resolve => {
function tick(now) {
if (now - start >= delay) {
resolve()
} else {
requestAnimationFrame(tick)
}
}
requestAnimationFrame(tick)
})
}
// 更精确但更耗 CPU
async function test() {
const start = performance.now()
await sleepPrecise(1000)
const actual = performance.now() - start
console.log(`精确延迟: ${actual.toFixed(2)}ms`)
}
与其他实现对比
// 1. 你的实现
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
// 2. 使用 setTimeout 直接返回
function sleep2(delay) {
return new Promise(resolve => {
setTimeout(resolve, delay)
})
}
// 3. 使用 async/await 包装(多余)
async function sleep3(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
// 4. 带错误处理
function sleep4(delay) {
if (typeof delay !== 'number' || delay < 0) {
return Promise.reject(new Error('delay must be a positive number'))
}
return new Promise(resolve => setTimeout(resolve, delay))
}
// 性能测试
async function comparePerformance() {
const iterations = 1000
console.time('sleep 原始')
for (let i = 0; i < iterations; i++) {
await sleep(10)
}
console.timeEnd('sleep 原始')
console.time('sleep4 带检查')
for (let i = 0; i < iterations; i++) {
await sleep4(10)
}
console.timeEnd('sleep4 带检查')
}
常见使用模式
1. 顺序延迟
async function sequentialDelay() {
console.log('步骤1')
await sleep(1000)
console.log('步骤2')
await sleep(1000)
console.log('步骤3')
}
2. 并发延迟
async function concurrentDelay() {
const promises = [
sleep(1000).then(() => '任务1'),
sleep(2000).then(() => '任务2'),
sleep(3000).then(() => '任务3')
]
const results = await Promise.all(promises)
console.log('所有任务完成:', results)
}
3. 指数退避
async function exponentialBackoff(fn, maxRetries = 5) {
let delay = 1000
for (let i = 0; i < maxRetries; i++) {
try {
return await fn()
} catch (error) {
if (i === maxRetries - 1) throw error
console.log(`第 ${i + 1} 次重试,等待 ${delay}ms...`)
await sleep(delay)
delay *= 2 // 指数增长
}
}
}
总结
sleep 函数:
✅ 优点:
- 简洁优雅:一行代码实现核心功能
- 性能良好:使用原生 Promise 和 setTimeout
- 易于使用:支持 then 和 async/await
- 无副作用:纯函数,不修改外部状态
✅ 应用场景:
- 测试异步代码
- 实现轮询
- 控制请求频率
- 模拟耗时操作
- 动画和过渡效果
- 超时控制
⚠️ 注意事项:
- 精度约为 4-10ms(受事件循环影响)
- 大量并发可能占用较多定时器资源
- 不会阻塞事件循环(非阻塞延迟)