前端批量请求场景

文章目录

  • 一、批量请求
    • 1、Promise.allSettled
    • 2、返回值穿透
  • 二、案例
    • 1、 批量任务
    • 2、缓存优化
    • 3、另一种实现方式

一般时候前端都是简单的查询任务,复杂的数据获取都是后台处理好再返回,如果遇到接口流程化处理、数据组装,可以参考一下。

一、批量请求

1、Promise.allSettled

  • 假设有多个接口请求数据,可以用以下方案
  • 由于一部分借口会报错,用Promise.allSettled比Promise.all会更直观;或者Promise.all加上catch
// 模拟接口请求
import React, { useEffect, useState, useRef } from "react";// 模拟接口请求
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const delayError = (ms) =>new Promise((resolve, reject) => setTimeout(reject, ms));const batchApiPage = () => {const [imgList, setImgList] = useState([{url: "url1",},{url: "url2",},]);const [data, setData] = useState([]);const fetchData = async () => {const result = await Promise.allSettled([delay(2000),delayError(1000).then(() => "data2"),delay(1000).then(() => "data3"),]);console.log("result", result);};// 或者Promise.all改为这样 增加自定义catch
// const result = await Promise.all([
//    delay(2000),
//     delayError(1000).then(() => "data2").catch(() => "error2"),
//     delay(1000).then(() => "data3"),
//   ]);useEffect(() => {fetchData();}, []);return <div>213231</div>;
};export default batchApiPage;

2、返回值穿透

  • 每一次请求的参数可能不同,想要确定请求和结果之间的关系,可以把请求参数穿透到返回值(后台可以做,前端也可以做到)
  • 在tabs快速切换、数据唯一性方面,有所作用(比如返回值没有id,可以自设id)
// 随机数
// Math.random() 肯定能取到0 增大上限再往下取整就可以扩大包含范围
const random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;// 模拟接口请求
const delay = (parms) =>new Promise((resolve) => {// Math.random() 肯定能取到0 增大上限再往下取整就可以扩大包含范围const data = random(10, 15);setTimeout(() =>resolve({data,}),1000,);});
const result = await delay() // {data: 12} // 参考结果const param = {key: "value",};
const resultUnip = await delay().then((res) => {return {...res,param,};
});// 结果
//   {
//     "data": 11,
//     "param": {
//         "key": "value"
//     }
// }

二、案例

1、 批量任务

  • 假设有多张图片,需要先调用接口上传图片得到url链接,再调用不同接口获取每张图对应的属性数据,一般采取以下方案
  • 要求一张图一张图进行,这样对上传接口压力较小;一张图上传完成、数据获取完成,才进行下一张
  • 完整案例在下方
  • 注意图片上传错误、获取数据错误的捕获,有可能需要展示是否错误的提示
  • 由于是异步阻塞的模式,loading状态比较好控制和获取
import React, { useEffect, useState, useRef } from "react";// 随机数
// Math.random() 肯定能取到0 增大上限再往下取整就可以扩大包含范围
const random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;// 只是延迟
const delay = (ms) =>new Promise((resolve) => setTimeout(() => resolve(""), ms));// 假设有多张图片,需要先调用接口上传图片得到url链接,再调用不同接口获取每张图对应的数据,一般采取以下方案const batchApiPage = () => {const [imgList, setImgList] = useState([{url: "url1",file: "file1",},{url: "url2",file: "file2",},]);const [data, setData] = useState([]);const getUrl = async (file) => {const result = await delay(1000).then((res) => {return `https://img.url/${random(10, 20)}`;});return result;};const getImgData1 = async (url) => {await delay(1000);return `imgdata1-${url}`;};const getImgData2 = async (url) => {await delay(1000);return `imgdata2-${url}`;};const getImgData3 = async (url) => {await delay(1000);return `imgdata3-${url}`;};const dataApiConfig = [{title: "获取图片数据1",key: "imgdata1",api: getImgData1,},{title: "获取图片数据2",key: "imgdata2",api: getImgData2,},{title: "获取图片数据3",key: "imgdata3",api: getImgData3,},];// 获取图片数据const getImgData = async (imgItem) => {try {const { url, file } = imgItem;// 上传图片// 注意这里没有catch 会被try catch 捕获 succ表示是否成功const urlRes = await getUrl(file).then((res) => {return res;});// 通过图片url去获取不同接口数据const dataApiRes = await Promise.all(dataApiConfig.map((item) => {// 穿透参数 key,return (item.api(urlRes).then((res) => ({ key: item.key, data: res }))// 这里的catch 没有data字段 表示接口失败.catch(() => ({ key: item.key })));}),);// 合并数据const dataObj = dataApiRes.reduce((acc, cur) => {acc[cur.key] = cur;return acc;}, {});// 返回结果 包含图片url,是否成功,不同接口数据return {url: urlRes,succ: true,data: dataObj,};} catch (error) {console.log("error", error);return {url: "",succ: false,data: {},};}};const fetchData = async () => {for (let i = 0; i < imgList.length; i++) {const imgItem = imgList[i];const result = await getImgData(imgItem);setData((prevData) => [...prevData, result]);}};useEffect(() => {fetchData();}, []);useEffect(() => {console.log("data", data);}, [data]);return <div>213231</div>;
};export default batchApiPage;

2、缓存优化

  • 由于图片可能很多达到几十张,那么可以缓存已经请求到的数据
  • 缓存数据,如果图片上传过,就不用再上传;如果数据请求过,就不再请求,使用缓存数据。
import React, { useEffect, useState, useRef } from "react";// 随机数
// Math.random() 肯定能取到0 增大上限再往下取整就可以扩大包含范围
const random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;// 只是延迟
const delay = (ms) =>new Promise((resolve) => setTimeout(() => resolve(""), ms));// 假设有多张图片,需要先调用接口上传图片得到url链接,再调用不同接口获取每张图对应的数据,一般采取以下方案const batchApiPage = () => {const [imgList, setImgList] = useState([{url: "url1",file: "file1",},{url: "url2",file: "file2",},]);const [data, setData] = useState([]);const cacheData = useRef({});const getUrl = async (file) => {const result = await delay(1000).then((res) => {return `https://img.url/${random(10, 20)}`;});return result;};const getImgData1 = async (url) => {await delay(1000);return `imgdata1-${url}`;};const getImgData2 = async (url) => {await delay(1000);return `imgdata2-${url}`;};const getImgData3 = async (url) => {await delay(1000);return `imgdata3-${url}`;};const dataApiConfig = [{title: "获取图片数据1",key: "imgdata1",api: getImgData1,},{title: "获取图片数据2",key: "imgdata2",api: getImgData2,},{title: "获取图片数据3",key: "imgdata3",api: getImgData3,},];// 获取图片数据const getImgData = async (imgItem) => {try {const { url, file } = imgItem;// 上传图片// 注意这里没有catch 会被try catch 捕获 succ表示是否成功let urlRes = url;if (file) {await getUrl(file).then((res) => {// 更新 imgList 里面的urlurlRes = res;setImgList((prevImgList) =>prevImgList.map((item) => {if (item.file === file) {// 缓存图片urlitem.url = urlRes;// 把file清空item.file = null;}return item;}),);});}// 通过图片url去获取不同接口数据const dataApiRes = await Promise.all(dataApiConfig.map((item) => {// 穿透参数 key 如果有缓存数据 直接返回缓存数据 直接通过节省时间const cacheDataByKey =cacheData.current[urlRes] && cacheData.current[urlRes][item.key];return cacheDataByKey? Promise.resolve({ key: item.key, data: cacheDataByKey }): item.api(urlRes).then((res) => {// 初始化缓存数据 避免undefined keycacheData.current[urlRes] = cacheData.current[urlRes] || {};cacheData.current[urlRes][item.key] = res;return { key: item.key, data: res };})// 这里的catch 没有data字段 表示接口失败.catch(() => ({ key: item.key }));}),);// 合并数据const dataObj = dataApiRes.reduce((acc, cur) => {acc[cur.key] = cur;return acc;}, {});// 返回结果 包含图片url,是否成功,不同接口数据return {url: urlRes,succ: true,data: dataObj,};} catch (error) {console.log("error", error);return {url: "",succ: false,data: {},};}};const fetchData = async () => {// 清空setData([]);for (let i = 0; i < imgList.length; i++) {const imgItem = imgList[i];const result = await getImgData(imgItem);setData((prevData) => [...prevData, result]);}};useEffect(() => {console.log("data", data);}, [data]);return (<div onClick={fetchData} style={{ cursor: "pointer" }}>21312323123</div>);
};export default batchApiPage;

3、另一种实现方式

  • 同样是获取图片数据,这里通过依次检查dataList每一条数据,发现未上传,就去上传图片,然后再调用图片数据接口;
  • 如果上传过就直接调用图片数据接口;
  • 一直按照顺序查找未完成的图片,之前是loading状态,最后complete,这样保持对loading的确定。
import { Button } from "antd";
import React, { useEffect, useState } from "react";
const PromisePage = () => {const [dataList, setDataList] = useState([]);const [currentBlob, setCurrentBlob] = useState("");const handleClick = () => {console.log("测试开始");setDataList([{blob: "blob1",file: true,url: "",watermark: "",hasUpload: false,},{blob: "blob4",file: true,url: "",watermark: "",hasUpload: true,value: "blob4_value",hasData: true, // 缓存数据},{blob: "blob3",file: true,url: "",watermark: "",hasUpload: true,value: "blob3_value",},{blob: "blob2",file: true,url: "",watermark: "",hasUpload: false,},]);};const uploadImg = () => {console.log("uploadImg");const imgItem = dataList.find((item) => item.hasUpload === false && item.blob === currentBlob,);if (imgItem && !imgItem.apiOnce) {setDataList((pre) =>pre.map((item) => {if (item.blob === imgItem.blob) {// console.log("模拟接口 item",);return { ...item, apiOnce: true };}return item;}),);console.log("模拟上传 start", currentBlob);setTimeout(() => {console.log("模拟上传 end", currentBlob);// 随机值const random = Math.random();if (random > 0.5) {setDataList((pre) =>pre.map((item) => {if (item.blob === imgItem.blob) {// console.log("模拟接口 item",);const url = currentBlob + "url";getData(url);return { ...item, value: url };}return item;}),);} else {setDataList((pre) =>pre.map((item) => {if (item.blob === imgItem.blob) {getData("error"); // fun(false, {})return { ...item, value: imgItem.blob, imgFailed: true };}return item;}),);}}, 2000);}};const getData = (url) => {// 模拟接口console.log("模拟接口 start", currentBlob, url);((url) => {})(url); // 异步setTimeout(() => {console.log("模拟接口 end", currentBlob, url);setDataList((pre) =>pre.map((item) => {if (item.blob === currentBlob) {// console.log("模拟接口 item",);return { ...item, hasData: true };}return item;}),);}, 2000);};useEffect(() => {if (dataList.length === 0) return;let blob = "";let flag = false;dataList.forEach((item) => {// 判断是否有缓存数据 或者请求数据完成if (!item.hasData && !flag) {blob = item.blob;flag = true;}});if (blob) {setCurrentBlob(blob);}if (flag) {// console.log("loading...");} else {console.log("complete...");}}, [dataList]);useEffect(() => {if (currentBlob) {const imgItem = dataList.find((item) => item.blob === currentBlob);if (imgItem?.hasUpload) {getData(imgItem.value); // 缓存数据} else {uploadImg();}}}, [currentBlob]);return (<div><Button type="primary" onClick={handleClick} style={{ marginRight: 10 }}>测试</Button>{/* 重置按钮 */}<Buttontype="primary"onClick={() => {setDataList([]);setCurrentBlob("");}}>重置按钮</Button></div>);
};
export default PromisePage;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/913141.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/913141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

芊芊妙音:智能变声,玩转声音魔法

在当今丰富多彩的社交和娱乐环境中&#xff0c;声音的魅力正逐渐被更多人发现和利用。无论是线上社交、短视频创作还是直播互动&#xff0c;一个独特而有趣的声音总能让人眼前一亮&#xff0c;甚至成为个人风格的一部分。《芊芊妙音》正是这样一款能够帮助用户轻松实现声音变换…

安防监控视频汇聚平台EasyCVR v3.7.2版云端录像无法在web端播放的原因排查和解决方法

有用户反馈&#xff0c;在使用EasyCVR视频汇聚平台时&#xff0c;发现云端录像无法在Web页面正常播放。为帮助大家高效解决类似困扰&#xff0c;本文将详细剖析排查思路与解决方案。 用户软件版本信息&#xff1a; 问题排查与解决步骤&#xff1a; 1&#xff09;问题复现验证…

vxe-upload vue 实现附件上传、手动批量上传附件的方式

vxe-upload vue 实现附件上传、手动批量上传附件的方式 查看官网&#xff1a;https://vxeui.com 安装 npm install vxe-pc-ui4.6.47// ... import VxeUIAll from vxe-pc-ui import vxe-pc-ui/lib/style.css // ...createApp(App).use(VxeUIAll).mount(#app) // ...上传附件支…

leaflet【十一】地图瓦片路径可视化

前言 在开发调试过程当中&#xff0c;如果引入的是公司内部的Gis地图信息或者一些第三方定制来的Gis地图数据&#xff0c;当某一些地图块数据缺失的时候&#xff0c;要打开F12去一个个找那些链接&#xff08;去找对应的xy与layer&#xff09;失效、那么你可能需要使用以下插件…

ES6从入门到精通:模块化

ES6 模块化基础概念ES6 模块化是 JavaScript 官方标准&#xff0c;通过 import 和 export 语法实现代码拆分与复用。模块化特点包括&#xff1a;每个文件是一个独立模块&#xff0c;作用域隔离。支持静态分析&#xff0c;依赖关系在编译时确定。输出的是值的引用&#xff08;动…

stm32 USART串口协议与外设——江协教程踩坑经验分享

江协stm32学习&#xff1a;9-1~9-3 USART串口协议与外设 一、串口通信基础知识 1、通信类型&#xff1a; 全双工通信&#xff1a;通信双方能够同时进行双向通信。一般有两根通信线&#xff0c;如USART中的TX&#xff08;发送&#xff09;和RX&#xff08;接收&#xff09;线&am…

深度学习中的一些名词

向前传播 forward pass 在机器学习中&#xff0c;输入的feature, 通过预测模型&#xff0c;输出预测值&#xff0c;此过程称之为向前传播&#xff1b; 向后传播 backward pass 为了将预测与真实值的产值减小&#xff0c;需要根据差值&#xff0c;更新模型中的参数&#xff0c;此…

鸿蒙系统(HarmonyOS)应用开发之手势锁屏密码锁(PatternLock)

项目概述 基于鸿蒙&#xff08;OpenHarmony&#xff09;平台开发的手势密码锁应用&#xff0c;旨在为用户提供安全、便捷且具有良好交互体验的身份验证方式。通过手势图案输入&#xff0c;用户可以轻松设置和验证密码&#xff0c;提升设备的安全性和个性化体验。 功能特点 手…

vue文本插值

好的&#xff0c;我们来详细讲解 Vue 中最基础的数据展示方式&#xff1a;文本插值和在其内部使用的 JavaScript 表达式。 1. 文本插值 (Text Interpolation) 知识点: 文本插值是 Vue 中最基本的数据绑定形式。它使用“Mustache”语法&#xff08;双大括号 {{ }}&#xff09;…

Python:线性代数,向量内积谐音记忆。

目录1 先说结论2 解释3 欢迎纠错4 论文写作/Python 学习智能体------以下关于 Markdown 编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、…

小程序导航设置更多内容的实现方法

在小程序中实现导航栏设置更多内容&#xff0c;可以通过以下几种方式实现&#xff1a; 1. 使用原生导航栏自定义按钮 javascript // app.json 或页面.json中配置 {"navigationBarTitleText": "首页","navigationBarTextStyle": "black&q…

SpringBoot 解决配置文件有黄色波浪线

在application.properties配置文件中有黄色波浪线&#xff0c;是警告!! 原因&#xff1a;编码格式不一致&#xff01;&#xff01; 解决&#xff1a;Settings| Editor | File Encodings | 选择UTF-8

在 Vue 3 中全局使用 Suspense 组件

Suspense 是 Vue 3 引入的一个内置组件&#xff0c;不需要引用可以直接用。用于处理异步依赖的等待状态。虽然 Suspense 主要用于异步组件&#xff0c;但你也可以全局地使用它来管理整个应用的加载状态。 全局 Suspense 的基本用法 1. 在根组件中使用 Suspense // main.js 或…

笔记/计算机网络

Content 计算机网络部分核心概念十大网络协议一览 计算机网络部分核心概念 1. 什么是计算机网络&#xff1f;它最基本的功能是什么&#xff1f; 计算机网络是指通过某种传输介质将多台独立的计算机或设备连接起来&#xff0c;实现数据交换和资源共享的系统。其最基本的功能是数…

时频图数据集更正程序,去除坐标轴白边及调整对应的标签值

当数据集是时频图时可能有一个尴尬的问题&#xff0c;就是数据集制作好后&#xff0c;发现有白边。 其实这也不影响训练模型&#xff0c;可能对模型训练效果的影响也是微乎其微的&#xff0c;于是大多数情况我会选择直接用整张图片训练模型。但是&#xff0c;有的情况下&#x…

mv重命名报错:bash:未预期的符号 ‘(‘附近有语法错误

文章目录 一、报错背景二、解决方法2.1、方法一&#xff1a;文件名加引号2.2、方法二&#xff1a;特殊字符前加\进行转义 一、报错背景 在linux上对一文件执行重命名时报错。原因是该文件名包含空格与括号。 文件名如下&#xff1a; aa &#xff08;1).txt执行命令及报错如下…

Unity-MMORPG内容笔记-其三

继续之前的内容&#xff1a; 战斗系统 无需多言&#xff0c;整个项目中最复杂的部分&#xff0c;也是代码量最大的部分。 属性系统 首先我们要定义一系列属性&#xff0c;毕竟所谓的战斗就是不断地扣血对吧。 属性系统是战斗系统的核心模块&#xff0c;负责管理角色的所有…

Linux入门篇学习——Linux 帮助手册

目录 一、Linux 帮助手册 1.怎么打开帮助手册 2.安装依赖 3.使用手册查看命令 一、Linux 帮助手册 1.怎么打开帮助手册 打开 ubuntu &#xff0c;输入 man 命令打开帮助手册&#xff0c;直接在控制台输入 man 就可以了&#xff0c; man 手册一共有 9 页&#xff0c…

2025年后端主流框架对比和竞争格局及趋势发展

2025年的后端开发呈现出云原生主导、性能革命、AI深度融合的技术格局&#xff0c;主流框架在细分领域持续分化&#xff0c;新兴技术快速渗透关键场景。以下是基于行业实践与技术演进的深度解析&#xff1a; 一、主流框架竞争态势与核心能力 1. Java生态&#xff1a;企业级市场的…

bRPC简介

bRPC基础介绍。 什么是RPC? 互联网上的机器大都通过TCP/IP协议相互访问&#xff0c;但TCP/IP只是往远端发送了一段二进制数据&#xff0c;为了建立服务还有很多问题需要抽象&#xff1a; 数据以什么格式传输&#xff1f;不同机器间&#xff0c;网络间可能是不同的字节序&am…