前端批量請求場景

文章目錄

  • 一、批量請求
    • 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
英文地址,請注明出處:http://en.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…