async/await Promise.all Promise.race

本文详细介绍了async函数的特性、await关键字的使用以及Promise.all和Promise.race的区别。理解了这些,你就掌握了JavaScript异步编程的核心。

async声明一个异步函数

1.自动将常规函数转换成Promise,返回值也是一个Promise对象

2.只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数

3.异步函数内部可以使用await

await暂停异步的功能执行

1.放置在Promise调用之前,await强制其他代码等待,直到Promise完成并返回结果

2.只能与Promise一起使用,不适合用于回调

3.只能在async函数内部使用

async函数完全可以看作多个异步操作,包装成的一个Promise对象,而await命令就是内部then命令的语法糖

async声明函数

//函数声明
async function foo(){
    //do something
}

//函数表达式
const foo = async function(){
     //do something
}

//对象方法

let o = {
    async foo(){
        //do something
    }
}

// 箭头函数
const foo = async () => {
    // do something
}

await

是async wait的缩写,它等待返回的是一个表达式,不管是不是Promise对象都可以,只是说如果返回的是Promise对象,执行的状态不一样;

await只能在async函数中使用

function sync() {
  setTimeout(() => {
    return 1
  }, 1000)
}

async function async1(){
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(1)
    }, 2000)
  })
}

async function test(){
  await sync() //undefined
  console.log(1)
}

关于await的返回值:

1.await后是一个promise对象,如果是resolve状态,值就是resolve参数;如果是reject状态,会将错误抛出

2.await后不是promise对象,则返回值就是该值的本身

注意:

1.容错:考虑await后面的promise运行结果可能是rejected,最好把await放入try{}catch{}中

2.await后的异步操作,如果彼此没有依赖关系最好同时触发

3.await只能在async函数值中,如果在普通函数中会报错

function fn() {
   return Promise.reject('error')
}

async function asyncFn() {
    try {
        await fn()
        console.log(1) // 如果上一行出错将直接跳到catch,不会执行到这里
    } catch(e) {
        console.log(e) // error
    }
}

Promise.all([promise1,promise2,promise3......]).then(result=>{}).catch()

用于将多个promise实例,包装成一个新的Promise实例,返回的实例就是普通的promise

接收一个数组作为参数,数组里面可以是Promise对象,也可以是别的值;只有Promise会等待状态改变

result是参数promise数组中所有promise结果组合成的数组

只有当所有子promise都完成,并且结果都是resolve,才走then

只要有一个子promise结果为reject,就走catch,返回值是第一个失败的子promise的结果

Promise.race([promise1,promise2,promise3......]).then(result=>{}).catch()

result为第一个执行成功的promise的resolve结果

只要有一个promise完成就结束了

<think>我们被要求回答:Promise.allasync/await 结合使用的最佳实践和常见用法有哪些 根据用户提供的引用,特别是引用[2]中的示例,展示了在Vue3中如何使用Promise.all配合async/await来并行处理多个请求。 结合我们之前关于Promise.all的回答,现在重点讨论结合async/await的使用模式。 注意:引用[1]提到可以用async/await实现Promise.all(),但通常我们不会重新实现Promise.all,而是使用它并配合async/await语法。 常见模式: 1.async函数内使用await Promise.all([...])来等待多个异步任务完成,并获取它们的结果数组。 2. 错误处理:使用try/catch来捕获Promise.all中可能出现的错误(即任何一个Promise被拒绝)。 最佳实践: - 确保传递给Promise.all的数组中的每个元素都是一个Promise。如果有些函数不是异步的,可以包装成Promise(但Promise.all会自动将非Promise值转换为已解决的Promise,所以也可以直接放入)。 - 注意错误处理:由于Promise.all在任何一个Promise失败时会立即抛出错误,因此必须捕获错误,否则可能导致未处理的拒绝。 - 在需要同时发起多个独立请求(如多个API调用)并且需要所有结果都返回后再进行下一步操作时,使用这种模式非常高效。 示例代码(基于引用[2]的示例扩展): ```javascript // 假设有两个异步函数,模拟API请求 async function fetchUser(userId) { const response = await fetch(`/api/users/${userId}`); return response.json(); } async function fetchPosts(userId) { const response = await fetch(`/api/posts?userId=${userId}`); return response.json(); } // 在另一个async函数中使用Promise.all来并行请求 async function fetchUserAndPosts(userId) { try { // 使用Promise.all同时发起两个请求 const [user, posts] = await Promise.all([ fetchUser(userId), fetchPosts(userId) ]); // 这里按顺序获取结果:user对应第一个,posts对应第二个 console.log('用户信息:', user); console.log('用户帖子:', posts); // 返回组合后的数据(可选) return { user, posts }; } catch (error) { // 处理错误:任何一个请求失败都会进入这里 console.error('请求失败:', error); // 可以选择抛出错误或返回一个错误状态 throw error; // 或者返回一个错误对象,根据业务需求 } } // 调用 fetchUserAndPosts(123) .then(data => console.log('成功获取数据', data)) .catch(err => console.error('外部捕获错误', err)); ``` 解释: 1. 在`fetchUserAndPosts`函数中,我们使用`await Promise.all`来等待两个请求都完成。 2. 使用数组解构`[user, posts]`直接获取两个结果。 3. 使用try/catch捕获可能发生的错误(如网络错误、API返回错误等)。 其他常见用法: 1. 处理动态数量的Promise:有时候需要并行的Promise数量是动态的,比如根据一个id列表请求多个资源。 ```javascript async function fetchMultipleUsers(userIds) { // 创建Promise数组 const promises = userIds.map(id => fetchUser(id)); return Promise.all(promises); } ``` 注意:如果数组很大,要小心并发过多,可能需要限制并发数(使用如p-map、p-limit等库)。 2. 结合其他异步流程控制:如果不需要所有任务都成功,可以使用`Promise.allSettled`,然后根据每个Promise的状态处理结果。 3. 在Vue/React等前端框架中,可以在组件的生命周期方法(如mounted)或事件处理函数中使用这种模式。 总结最佳实践: - 总是使用try/catch(或.catch)来捕获错误。 - 注意并发数量,避免同时发起太多请求(尤其是在低端设备或服务器端)。 - 利用解构赋值简化结果处理。 相关问题: 1. 如何限制Promise.all的并发数量? 2.Promise.all中,如何处理部分失败(忽略失败或收集错误)? 3. Promise.allPromise.allSettled在错误处理上有什么区别? 4. 在Node.js中使用Promise.all进行文件读写操作时需要注意什么?</think>### Promise.allasync/await 结合使用的最佳实践 Promise.allasync/await 结合是现代 JavaScript 异步编程的核心模式,能显著提升代码可读性和执行效率。以下是关键实践方法和常见用法: #### 一、基本使用模式 ```javascript async function fetchAllData() { try { // 同时发起多个异步请求 const [userData, orders, settings] = await Promise.all([ fetch('/api/user'), fetch('/api/orders'), fetch('/api/settings') ]); // 顺序处理结果(数组解构保持顺序) const user = await userData.json(); const orderList = await orders.json(); const config = await settings.json(); return { user, orderList, config }; } catch (error) { // 统一错误处理(任一请求失败即触发) console.error("请求失败:", error); throw new Error("数据加载失败"); } } ``` **特点**: 1. `await Promise.all()` 暂停执行直到所有 Promise 完成 2. 数组解构 `[a,b,c]` 按声明顺序获取结果[^1] 3. try/catch 统一处理错误(任一失败即跳转 catch) #### 二、最佳实践原则 1. **错误处理优先** ```javascript // 明确捕获每个可能的错误点 async function safeFetch() { try { const results = await Promise.all([apiA(), apiB()]); // 进一步验证结果 if (!results[0].valid) throw new Error("数据校验失败"); } catch (err) { // 区分错误类型 if (err.name === 'AbortError') { console.warn("请求被取消"); } else { sentry.captureException(err); // 上报错误 } } } ``` 2. **动态任务处理** ```javascript async function processBatch(tasks) { // 动态生成Promise数组 const promises = tasks.map(task => db.query(`SELECT * FROM ${task.table}`) ); const results = await Promise.all(promises); return results.flat(); } ``` 3. **资源清理保障** ```javascript async function withCleanup() { const controller = new AbortController(); try { const [res1, res2] = await Promise.all([ fetch(url1, { signal: controller.signal }), fetch(url2, { signal: controller.signal }) ]); // ... } catch (err) { controller.abort(); // 失败时取消所有请求 } } ``` #### 三、常见应用场景 1. **并行 API 请求**(如 Vue/React 数据预取) ```javascript // Vue3 示例 (参考引用[2]) export default { async setup() { const [user, products] = await Promise.all([ fetchUser(), fetchProducts() ]); return { user, products }; } } ``` 2. **文件批量处理**(Node.js) ```javascript const fs = require('fs').promises; async function convertFiles(filePaths) { const readPromises = filePaths.map(path => fs.readFile(path, 'utf8') ); const contents = await Promise.all(readPromises); return contents.map(text => text.toUpperCase()); } ``` 3. **数据库联合查询** ```javascript async function getUserFullData(userId) { const [profile, orders, messages] = await Promise.all([ UserModel.findById(userId), OrderModel.find({ userId }), MessageModel.find({ receiverId: userId }) ]); return { profile, orders, messages }; } ``` #### 四、性能优化技巧 1. **限制并发量**(避免资源耗尽) ```javascript import pLimit from 'p-limit'; async function limitedParallel() { const limit = pLimit(5); // 最大并发数 const promises = urls.map(url => limit(() => fetch(url)) ); return Promise.all(promises); } ``` 2. **结果流式处理** ```javascript async function processAsCompleted() { const promises = urls.map(fetch); for await (const response of promises) { // 每个请求完成立即处理 renderPartial(await response.json()); } } ``` 3. **超时控制** ```javascript function withTimeout(promise, ms) { const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error("超时")), ms) ); return Promise.race([promise, timeout]); } await Promise.all([ withTimeout(fetchA(), 5000), withTimeout(fetchB(), 3000) ]); ``` #### 五、替代方案选择 | 场景 | 推荐方法 | 特点 | |------|----------|------| | 需全部成功 | `Promise.all` | 快速失败(任一失败即终止) | | 容忍部分失败 | `Promise.allSettled` | 返回所有结果状态[^1] | | 首结果优先 | `Promise.any` | 获取首个成功结果 | | 竞速场景 | `Promise.race` | 响应最快的结果(成功/失败) | > **关键提示**:浏览器中并行请求数有限制(HTTP/1.1 约 6 个),大量请求时需分批次执行或使用工作线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值