Skip to content

async/await

async/await 是 JavaScript 中处理异步操作的一种更优雅的方式,它建立在 Promise 之上,使异步代码看起来和同步代码一样。

基本概念

1. async 函数

async 函数总是返回一个 Promise。

javascript
// 基本语法
async function fetchData() {
    return '数据';
}

// 等同于
function fetchData() {
    return Promise.resolve('数据');
}

// 使用
fetchData().then(data => console.log(data));

2. await 操作符

await 只能在 async 函数内部使用,它会暂停函数的执行,直到 Promise 完成。

javascript
async function fetchUserData() {
    const response = await fetch('https://api.example.com/user');
    const data = await response.json();
    return data;
}

错误处理

1. try/catch

javascript
async function fetchData() {
    try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('获取数据失败:', error);
        throw error;
    }
}

2. 错误传播

javascript
async function processData() {
    try {
        const data = await fetchData();
        return data;
    } catch (error) {
        // 处理错误
        return '默认数据';
    }
}

并行执行

1. Promise.all 与 await

javascript
async function fetchMultipleData() {
    const [users, posts, comments] = await Promise.all([
        fetchUsers(),
        fetchPosts(),
        fetchComments()
    ]);
    return { users, posts, comments };
}

2. 顺序执行 vs 并行执行

javascript
// 顺序执行
async function sequential() {
    const user = await fetchUser();
    const posts = await fetchPosts(user.id);
    const comments = await fetchComments(posts[0].id);
    return { user, posts, comments };
}

// 并行执行
async function parallel() {
    const [user, posts, comments] = await Promise.all([
        fetchUser(),
        fetchPosts(),
        fetchComments()
    ]);
    return { user, posts, comments };
}

高级用法

1. 异步迭代器

javascript
async function* asyncGenerator() {
    yield await Promise.resolve(1);
    yield await Promise.resolve(2);
    yield await Promise.resolve(3);
}

async function iterate() {
    for await (const num of asyncGenerator()) {
        console.log(num);
    }
}

2. 异步类方法

javascript
class DataFetcher {
    async fetchData() {
        const response = await fetch('https://api.example.com/data');
        return response.json();
    }

    static async fetchStaticData() {
        const response = await fetch('https://api.example.com/static');
        return response.json();
    }
}

常见陷阱

1. 在循环中使用 await

javascript
// 不好的做法
async function processItems(items) {
    for (const item of items) {
        await processItem(item); // 顺序执行
    }
}

// 好的做法
async function processItems(items) {
    await Promise.all(items.map(item => processItem(item))); // 并行执行
}

2. 忘记 await

javascript
// 不好的做法
async function fetchData() {
    const promise = fetch('https://api.example.com/data');
    const data = promise.json(); // 错误:promise 还未解析
    return data;
}

// 好的做法
async function fetchData() {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
}

3. 错误处理不完整

javascript
// 不好的做法
async function fetchData() {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
}

// 好的做法
async function fetchData() {
    try {
        const response = await fetch('https://api.example.com/data');
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('获取数据失败:', error);
        throw error;
    }
}

性能优化

1. 避免不必要的 await

javascript
// 不好的做法
async function processData() {
    const data = await fetchData();
    const processed = await processData(data);
    return processed;
}

// 好的做法
async function processData() {
    const data = await fetchData();
    return processData(data); // 如果 processData 是同步的,不需要 await
}

2. 并行请求优化

javascript
// 不好的做法
async function fetchUserData(userId) {
    const user = await fetchUser(userId);
    const posts = await fetchUserPosts(userId);
    const comments = await fetchUserComments(userId);
    return { user, posts, comments };
}

// 好的做法
async function fetchUserData(userId) {
    const [user, posts, comments] = await Promise.all([
        fetchUser(userId),
        fetchUserPosts(userId),
        fetchUserComments(userId)
    ]);
    return { user, posts, comments };
}

最佳实践

1. 函数命名

javascript
// 好的命名
async function fetchUserData() { }
async function processPayment() { }
async function validateForm() { }

// 不好的命名
async function getData() { }
async function doStuff() { }
async function handle() { }

2. 错误处理

javascript
// 好的错误处理
async function fetchData() {
    try {
        const response = await fetch('https://api.example.com/data');
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        return await response.json();
    } catch (error) {
        console.error('获取数据失败:', error);
        throw new Error('数据获取失败,请稍后重试');
    }
}

3. 超时处理

javascript
async function fetchWithTimeout(url, timeout = 5000) {
    const controller = new AbortController();
    const id = setTimeout(() => controller.abort(), timeout);

    try {
        const response = await fetch(url, {
            signal: controller.signal
        });
        clearTimeout(id);
        return response;
    } catch (error) {
        clearTimeout(id);
        throw error;
    }
}

总结

  1. async/await 使异步代码更易读和维护
  2. 正确处理错误和异常情况
  3. 合理使用并行执行提高性能
  4. 避免常见陷阱和错误
  5. 遵循最佳实践和命名规范
  6. 注意性能优化和资源使用
  7. 使用适当的错误处理和超时机制