
事件循环,Promise和async/await的详解
【代码】事件循环,Promise和async/await的详解。
·
这是一个很重要的话题,让我们逐步讲解:
- 事件循环基本概念:
// JavaScript执行顺序
console.log('1'); // 同步任务
setTimeout(() => console.log('2'), 0); // 宏任务
Promise.resolve().then(() => console.log('3')); // 微任务
console.log('4');
// 输出顺序:1, 4, 3, 2
- 任务队列分类:
// 宏任务(macrotask)
setTimeout
setInterval
setImmediate (Node.js)
requestAnimationFrame
I/O
UI渲染
// 微任务(microtask)
Promise.then/catch/finally
process.nextTick (Node.js)
MutationObserver
- Promise的基本使用:
// 基本语法
const promise = new Promise((resolve, reject) => {
// 异步操作
if (/* 成功 */) {
resolve(value);
} else {
reject(error);
}
});
// 链式调用
promise
.then(value => {
// 处理成功
})
.catch(error => {
// 处理错误
})
.finally(() => {
// 总是执行
});
// Promise方法
Promise.all([p1, p2, p3]) // 所有Promise都完成
Promise.race([p1, p2, p3]) // 第一个完成的Promise
Promise.allSettled([p1, p2, p3]) // 所有Promise都结束
Promise.any([p1, p2, p3]) // 第一个成功的Promise
- async/await使用:
// 基本语法
async function getData() {
try {
const result = await fetchData();
return result;
} catch (error) {
console.error(error);
}
}
// 并行执行
async function parallel() {
const [result1, result2] = await Promise.all([
fetch('url1'),
fetch('url2')
]);
}
// 循环中使用
async function processArray(array) {
// 串行执行
for (const item of array) {
await processItem(item);
}
// 并行执行
const promises = array.map(item => processItem(item));
await Promise.all(promises);
}
- 复杂示例:
// 事件循环示例
console.log('1'); // 同步
setTimeout(() => {
console.log('2'); // 宏任务1
Promise.resolve().then(() => {
console.log('3'); // 宏任务1中的微任务
});
}, 0);
Promise.resolve().then(() => {
console.log('4'); // 微任务1
setTimeout(() => {
console.log('5'); // 微任务1中的宏任务
}, 0);
});
console.log('6'); // 同步
// 输出:1, 6, 4, 2, 3, 5
- 错误处理:
// Promise错误处理
promise
.then(data => {
throw new Error('error');
})
.catch(error => {
console.error(error);
return 'recovered';
})
.then(data => {
console.log(data); // 'recovered'
});
// async/await错误处理
async function errorHandling() {
try {
await Promise.reject('error');
} catch (error) {
console.error(error);
}
}
- 实际应用场景:
// 请求重试
async function fetchWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await fetch(url);
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
}
}
}
// 并发控制
async function pool(tasks, poolLimit) {
const results = [];
const executing = new Set();
for (const task of tasks) {
const promise = Promise.resolve().then(() => task());
results.push(promise);
executing.add(promise);
const clean = () => executing.delete(promise);
promise.then(clean, clean);
if (executing.size >= poolLimit) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
- 常见陷阱:
// Promise.resolve()的陷阱
Promise.resolve(new Promise(resolve => {
setTimeout(resolve, 1000);
})).then(() => console.log('done'));
// async函数总是返回Promise
async function fn() {
return 1;
}
console.log(fn()); // Promise {<fulfilled>: 1}
// await的使用位置
function wrong() {
await fetchData(); // SyntaxError
}
- 性能优化:
// 避免不必要的await
async function optimized() {
const promise1 = fetchData1(); // 不用await
const promise2 = fetchData2(); // 不用await
const [data1, data2] = await Promise.all([promise1, promise2]);
}
// 使用Promise.all而不是串行await
async function better() {
const results = await Promise.all([
fetch('url1'),
fetch('url2'),
fetch('url3')
]);
}
- 最佳实践:
- 合理使用Promise.all进行并行操作
- 正确处理错误情况
- 避免回调地狱
- 注意内存泄漏
- 合理使用async/await
- 理解事件循环机制
更多推荐
所有评论(0)