JavaScript Promise 与 async/await 异步编程

小飞兽 ES6+ 7 次阅读 2026-07-29

Introduction

异步编程是 JavaScript 的核心概念。Promise 是 ES6 引入的异步编程解决方案,用于处理异步操作,告别了回调地狱。async/await 则是 ES2017 推出的语法糖,让异步代码看起来像同步代码,大幅提升可读性。掌握 Promise 与 async/await 是现代 JavaScript 开发的必备技能。

基础语法

1. Promise 基础

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = true;
    if (success) resolve('操作成功!');
    else reject(new Error('操作失败'));
  }, 1000);
});
promise.then(result => console.log(result)).catch(error => console.error(error)).finally(() => console.log('无论成功失败都会执行'));

2. Promise 静态方法

Promise.all([promise1, promise2, promise3]).then(results => console.log(results)).catch(error => console.error(error));
Promise.allSettled([promise1, promise2]).then(results => { results.forEach((result, i) => { if (result.status === 'fulfilled') console.log(Promise${i}: ${result.value}); else console.log(Promise${i} 失败: ${result.reason}); }); });
Promise.race([promise1, promise2]).then(result => console.log(result));
Promise.any([promise1, promise2]).then(result => console.log(result));
Promise.resolve('直接成功').then(console.log);
Promise.reject(new Error('直接失败')).catch(console.error);

3. async/await

async function fetchData() { try { const result = await asyncOperation(); return result; } catch (error) { console.error('捕获错误:', error); throw error; } }
async function parallel() { const [result1, result2] = await Promise.all([fetchUser(id1), fetchUser(id2)]); return { result1, result2 }; }
async function safeFetch() { try { const response = await fetch('/api/data'); if (!response.ok) throw new Error('HTTP错误'); return await response.json(); } catch (err) { console.error('请求失败:', err); return null; } }

完整代码示例

const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const mockFetchUser = (userId) => delay(500).then(() => ({ id: userId, name: userId === 1 ? '张三' : '李四', role: userId === 1 ? 'admin' : 'user', avatar: https://i.pravatar.cc/150?u=${userId} }));
const mockFetchPermissions = (role) => delay(300).then(() => ({ admin: ['read', 'write', 'delete', 'admin'], user: ['read'], guest: ['read'] }[role] || []));
const mockFetchPosts = (userId) => delay(400).then(() => ([{ id: 101, title: 'ES6 完全指南', likes: 120 }, { id: 102, title: 'Async/Await 实战', likes: 85 }, { id: 103, title: 'TypeScript 入门', likes: 200 }]));

function loadUserProfilePromise(userId) {
return mockFetchUser(userId).then(user => {
console.log('1. 获取用户:', user.name);
return mockFetchPermissions(user.role).then(permissions => ({ user, permissions }));
}).then(({ user, permissions }) => {
console.log('2. 权限列表:', permissions.join(', '));
return mockFetchPosts(user.id).then(posts => ({ user, permissions, posts }));
}).then(({ user, permissions, posts }) => {
console.log('3. 文章数量:', posts.length);
return { user, permissions, posts };
}).catch(error => { console.error('加载失败:', error.message); return null; });
}

async function loadUserProfileAsync(userId) {
try {
const user = await mockFetchUser(userId);
console.log('1. 获取用户:', user.name);
const permissions = await mockFetchPermissions(user.role);
console.log('2. 权限列表:', permissions.join(', '));
const posts = await mockFetchPosts(user.id);
console.log('3. 文章数量:', posts.length);
return { user, permissions, posts };
} catch (error) { console.error('加载失败:', error.message); return null; }
}

async function loadUserProfileOptimized(userId) {
try {
const user = await mockFetchUser(userId);
console.log('用户:', user.name);
const [permissions, posts] = await Promise.all([mockFetchPermissions(user.role), mockFetchPosts(user.id)]);
return { user, permissions, posts };
} catch (error) { console.error('加载失败:', error.message); return null; }
}

async function loadMultipleUsers(userIds) {
const promises = userIds.map(id => mockFetchUser(id));
const results = await Promise.allSettled(promises);
const successful = results.filter(r => r.status === 'fulfilled').map(r => r.value);
const failed = results.filter(r => r.status === 'rejected').map(r => r.reason);
console.log(成功: ${successful.length}, 失败: ${failed.length});
return { successful, failed };
}

async function fetchJSON(url, options = {}) {
try {
const response = await fetch(url, { headers: { 'Content-Type': 'application/json' }, ...options });
if (!response.ok) throw new Error(HTTP ${response.status}: ${response.statusText});
return await response.json();
} catch (error) { if (error instanceof TypeError) throw new Error('网络错误,请检查网络连接'); throw error; }
}

async function main() {
console.log('--- Promise 链式调用 ---');
const profile1 = await loadUserProfilePromise(1);
console.log('最终结果:', profile1?.user?.name);
console.log('\n--- async/await ---');
const profile2 = await loadUserProfileAsync(2);
console.log('最终结果:', profile2?.user?.name);
console.log('\n--- 并行优化 ---');
const profile3 = await loadUserProfileOptimized(1);
console.log('文章:', profile3?.posts?.map(p => p.title));
console.log('\n--- Promise.allSettled ---');
const multi = await loadMultipleUsers([1, 2, 999]);
console.log('成功用户:', multi.successful.map(u => u.name));
}
main();

常见问题

    • async/await 和 Promise 链式调用如何选择? 简单场景用 Promise.all 并行时用 Promise;复杂顺序逻辑或需要 try/catch 统一处理错误时用 async/await 更清晰。
    • Promise.all 有一个 reject 就会整体失败,如何获取所有结果? 使用 Promise.allSettled(ES2020),它不短路,会等待所有 Promise 结束。
    • forEach 和 async/await 一起用会怎样? forEach 不会等待 async 回调,需要顺序执行时用 for...of 循环。
    • 如何取消正在进行的 Promise 请求? 使用 AbortController API:const controller = new AbortController(); fetch(url, { signal: controller.signal }); controller.abort();

延伸阅读