循环调用接口,确保所有返回数据都拿到了promise.all

这段代码展示了如何利用Promise.all并行发送多个axios请求,并将结果整合。在两个实例中,分别进行了不同的API调用,然后将返回的数据合并到数组中。第一个例子涉及社区查询,第二个例子涉及获取设备状态信息。
mounted () {
  let list = [1, 2, 3]
  let queue = list.map(item => {
    return new Promise(resolve => {
      this.$axios.get('ycxflzws/lzWebService.asmx/schphonebycommunityname',
        {
          params: {
            'communityname': '浙江华数广电网络'
          }
        }).then((res) => {
          console.log(res)
          resolve(res.status)
        })
    })
  })
  Promise.all(queue).then(result => {
    console.log(result)
  })
}

在这里插入图片描述
实例2:

getStageData () { // 获取状态信息(开关)(是否在线)(是否报警)
  let data = this.sbListObjArr.map(item => {
    return new Promise(resolve => {
      this.$axios({
        method: 'post',
        url: 'https://www.genetek.cc:8083/iotserver/sensor/electric/callacbmethod',
        headers: {
          'Content-Type': 'application/json;charset=utf-8'
        },
        data: {
          mac: item.deviceid, // 设备 98CC4D2148CB,
          method: 'GET_BOX_CHANNELS_REALTIME',
          projectCode: this.projectCode
        }
      }).then(res => {
        // console.log(res)
        let data = JSON.parse(res.data.data).data
        // console.log(data)
        for (let i = 0; i < data.length; i++) {
          data[i].xid = item.deviceid + '-' + data[i].addr
        }
        resolve(data)
      })
    })
  })
  Promise.all(data).then(result => {
    console.log('状态数据')
    for (let i = 0; i < result.length; i++) {
      this.lineStageArr = this.lineStageArr.concat(result[i]);
    }
  })
},
这是一个非常关键的问题。你说: > “后端接口还没有返回数据,loading 就关闭了” 这说明 **`loading` 状态在请求完成前就被设置为 `false`**,违背了我们的初衷 —— 只有当所有接口真正返回数据后才关闭 loading。 我们来排查这个问题的常见原因,并给出解决方案。 --- ### ❌ 问题原因分析 根据你描述的现象:“loading 提前关闭”,通常是因为: #### ✅ 原因 1:你在调用 `Promise.all` 前就设置了 `setLoading(false)` ```js setLoading(false); // 错误地提前关闭 await Promise.all([...]); ``` #### ✅ 原因 2:异步函数没有被 `await` 或 `.then()` 正确处理(比如忘记 `await`) ```js const loadUsers = async () => { const requests = [fetchUserData(1), fetchUserData(2), fetchUserData(3)]; Promise.all(requests); // ❌ 忘记 await setLoading(false); // loading 立刻关闭! } ``` 这是最常见的错误!即使用了 `async/await`,如果你不 `await Promise.all(...)`,JS 会继续往下执行,导致 `loading` 提前关闭。 #### ✅ 原因 3:`fetchUserData` 函数本身没有正确返回一个 Promise(比如内部同步执行或包装错误) 例如: ```js const fetchUserData = (userId) => { someAsyncApi(userId); // ❌ 忘记 return,或者没 await 内部异步操作 } ``` --- ### ✅ 正确做法:确保 `Promise.all` 被 `await`,且 loading 在 `finally` 中关闭 下面是修正后的完整、安全版本代码: ```jsx import React, { useState, useEffect } from 'react'; // 模拟 API 请求(必须返回 Promise) const fetchUserData = (userId) => { return fetch(`/api/user/${userId}`) // 真实接口示例 .then(res => res.json()) .catch(err => { console.error(`请求用户 ${userId} 失败`, err); throw err; // 让 Promise.all 感知到失败 }); }; // 或使用 axios // const fetchUserData = (userId) => axios.get(`/api/user/${userId}`).then(res => res.data); const UserList = () => { const [loading, setLoading] = useState(true); const [users, setUsers] = useState([]); useEffect(() => { const controller = new AbortController(); // 可选:支持取消请求 const loadUsers = async () => { try { const requests = [ fetchUserData(1), fetchUserData(2), fetchUserData(3) ]; console.log('开始并发请求...'); const results = await Promise.all(requests); // ✅ 必须 await console.log('所有请求完成:', results); // 只有在这里才会继续执行 setUsers(results); } catch (error) { console.error('至少一个请求失败:', error); // 根据需求决定是否清空 users 或显示错误 setUsers([]); } finally { // ✅ 最重要的地方:只有所有请求结束(无论成功失败)才关闭 loading setLoading(false); } }; loadUsers(); // 清理函数(可选) return () => { controller.abort(); }; }, []); if (loading) { return <div>加载中,请等待数据返回...</div>; } return ( <div> <h2>用户列表</h2> <ul> {users.map((user, index) => ( <li key={index}>ID: {user.id}, 名称: {user.name}</li> ))} </ul> </div> ); }; export default UserList; ``` --- ### 🔍 关键点验证 1. ✅ `Promise.all(requests)` 必须加 `await` → 否则 JS 不会等待,直接执行 `setLoading(false)` 2. ✅ `fetchUserData` 必须返回真正的异步 Promise → 检查你的实际接口函数是否 `return axios.get(...)` 或 `return fetch().then()` 3. ✅ `setLoading(false)` 必须放在 `finally` 块中 → 保证无论成功或失败都会执行,且是最后一步 4. ✅ 不要在 `try` 块外写 `setLoading(false)`,否则可能跳过 `catch` --- ### 🛠️ 如何调试? 你可以加一些日志来确认执行顺序: ```js console.log("1. 开始请求"); await Promise.all(requests); console.log("2. 所有请求已完成"); setLoading(false); console.log("3. loading 已关闭"); ``` 如果输出顺序是: ``` 1. 开始请求 3. loading 已关闭 2. 所有请求已完成 ``` → 那就是 **没有 await Promise.all**! --- ### ✅ 推荐最佳实践总结 | 要点 | 建议 | |------|------| | 并发请求 | 使用 `Promise.all` | | 等待完成 | 必须 `await` | | 关闭 loading | 放在 `finally` 中 | | 错误处理 | `try/catch` 包裹 `Promise.all` | | 防止内存泄漏 | 组件卸载时清理(如 `AbortController`) | --- ### ❧ 相关问题: 1. 如果其中一个接口失败,如何不让整个 Promise.all 失败? 2. 如何用 `Promise.allSettled` 实现“哪怕部分失败也要拿到成功结果”? 3. 为什么 `await` 缺失会导致逻辑错乱?JavaScript 事件循环是如何工作的? 4. 如何在 Redux 或 Zustand 中全局管理多个请求的 loading 状态?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值