一、異步任務常見場景
網絡請求:
fetch()
、axios
?等 API 調用定時操作:
setTimeout
、setInterval
用戶交互:事件監聽回調
資源加載:圖片/腳本動態加載
Web Workers:后臺線程計算
二、核心處理方案
1. Promise(ES6+)
function fetchUser(id) {return new Promise((resolve, reject) => {fetch(`/api/users/${id}`).then(response => response.json()).then(resolve).catch(reject)})
}// 使用示例
fetchUser(123).then(user => console.log(user)).catch(error => console.error(error))
2. async/await(ES2017+)
async function getUserData() {try {const user = await fetchUser(123)const posts = await fetchPosts(user.id)return { user, posts }} catch (error) {console.error('數據獲取失敗:', error)return null}
}// 調用
getUserData().then(console.log)
3. Promise 組合方法
方法 | 特點 | 使用場景 |
---|---|---|
Promise.all() | 全部成功才返回,短路失敗 | 強依賴的并行請求 |
Promise.allSettled() | 等待所有完成,返回狀態詳情 | 獨立任務的結果收集 |
Promise.race() | 返回第一個完成的結果 | 請求超時控制 |
Promise.any() | 返回第一個成功的結果 | 多源數據擇優 |
Promise.allSettled() 示例:
const promise1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('Promise 1');}, 1000);
});const promise2 = new Promise((resolve, reject) => {setTimeout(() => {resolve('Promise 2');}, 2000);
});const promise3 = new Promise((resolve, reject) => {setTimeout(() => {resolve('Promise 3');}, 3000);
});Promise.allSettled([promise1, promise2, promise3]).then(results => { results.forEach(result => { if(result.status === 'fulfilled') { console.log('成功獲取值:', result.value); } else { console.error('拒絕原因:', result.reason); } }); });
三、高級處理模式
1. 請求競速(race)
function withTimeout(promise, timeout) {return Promise.race([promise,new Promise((_, reject) => setTimeout(() => reject(new Error('請求超時')), timeout))])
}// 使用
withTimeout(fetch('/api/data'), 5000).catch(error => console.error(error))
2. 順序執行 + 并行組合
async function processOrder(orderId) {// 順序執行const order = await fetchOrder(orderId)const user = await fetchUser(order.userId)// 并行執行const [product, address] = await Promise.all([fetchProduct(order.productId),fetchAddress(user.addressId)])return { order, user, product, address }
}
3. 錯誤重試機制
async function retry(fn, retries = 3, delay = 1000) {try {return await fn()} catch (err) {if (retries <= 0) throw errawait new Promise(res => setTimeout(res, delay))return retry(fn, retries - 1, delay * 2) // 指數退避}
}// 使用
retry(() => fetch('/unstable-api'))
四、實際應用技巧
加載狀態管理:
async function loadData() {setLoading(true)try {const data = await fetchData()setState(data)} catch (error) {setError(error.message)} finally {setLoading(false)}
}
并發控制(避免同時發起過多請求):
async function parallelWithLimit(tasks, limit) {const results = []const executing = []for (const task of tasks) {const p = task().then(res => {executing.splice(executing.indexOf(p), 1)return res})results.push(p)executing.push(p)if (executing.length >= limit) {await Promise.race(executing)}}return Promise.all(results)
}// 使用:最多同時3個請求
parallelWithLimit([task1, task2, ...task10], 3)
五、最佳實踐
始終捕獲錯誤:使用?
try/catch
?或?.catch()
避免嵌套地獄:優先使用 async/await 替代回調嵌套
合理使用并行:獨立任務用?
Promise.all()
?或?Promise.allSettled()
添加取消機制:對長時間操作提供取消支持
性能優化:
請求合并(GraphQL/BFF)
數據緩存(SWR/React Query)
懶加載非關鍵資源