遍历请求后端数据引出的数组forEach异步操作的坑

有一个列表数据,每项数据里有一个额外的字段需要去调另外一个接口才能拿到,后端有现有的这2个接口,现在临时需要前端显示出来,所以这里需要前端先去调列表数据的接口拿到列表数据,然后再遍历请求另外一个接口去拿到对应的字段数据,最后再塞到列表数据里,具体可以看下面的示例代码。

forEach 中异步操作

/*** 获取要展示的列表数据*/
async function getData() {const list = await $getListData()// 遍历请求list.forEach(async (item) => {const res = await $getExtraInfo({id: item.id})item.extraInfo = res.extraInfo})// 打印下最终处理过的额外数据console.log(list)
}
getData()/*** 模拟请求列表数据*/
function $getListData() {return new Promise((resolve) => {setTimeout(() => {resolve([{ id: 1, name: '我是第一项数据' },{ id: 2, name: '我是第二项数据' },{ id: 3, name: '我是第三项数据' }])}, 3000)})
}/*** 模拟请求额外数据*/
function $getExtraInfo({ id }) {return new Promise((resolve) => {setTimeout(() => {resolve({extraInfo: `我是 id 为:${id} 的额外数据`})}, 1000 * id)})
}

上面的代码看着好像也没啥问题,一般我们前端项目调试时,很多人可能喜欢直接在控制台用 console.log 打印,这里我们把代码复制粘贴到浏览器控制台中回车运行,直接看控制台确实也能拿到添加了 extraInfo 的列表数据,这里建议你多等几秒再去展开控制台查看折叠的数据,原因后面再说:


其实这里有一个坑,你会发现我们不同时间点去点开控制台折叠的信息时,展示出来的数据可能会不一样。其实是因为当我们在浏览器中用 console 打印一个引用数据类型的时候,是实时获取的当前时间点对象的实际值,所以当不同时间点我们展开数据查看时,就会存在看到的打印结果与预期不一致的情况。

为了避免浏览器打印的问题,我们直接换到 node 环境来执行上面的代码,然后就能看到不一样的地方了:

从截图就能看到这里我们最终打印出来的居然是原始的列表数据,自己添加的 extraInfo 字段压根没生效。

造成这样结果的原因其实是 forEach 不支持异步,即使你代码中有任何异步操作都会被直接忽略当成同步代码来运行,解决方式有两种:

for 循环中异步操作

for 循环中是可以直接有异步操作的(for of 也是支持异步的),每一次循环会等到 await 后面的异步代码返回数据时再进行下一次循环,而 forEach 这里会直接忽略掉 await 进行下一次循环。

async function getData() {const list = await $getListData()// 遍历请求for (let i = 0; i < list.length; i++) {const res = await $getExtraInfo({id: list[i].id})list[i].extraInfo = res.extraInfo}console.log(list)
}

map 中异步操作

map 看着和 forEach 似乎没大多差别,但是 map 中是可以有异步操作的,因为 map 是可以有 return 返回值的,而 forEach 无返回值,上面的问题用 map 来改写:

async function getData() {const list = await $getListData()// 遍历请求const promiseList = list.map(async (item) => {const res = await $getExtraInfo({id: item.id})item.extraInfo = res.extraInforeturn item})Promise.all(promiseList).then(result => {console.log('我是拿到的最终数据', result)})
}

map 中包含 await 时每次循环 return 的就是一个 promise,然后我们通过 Promise.all 就可以等待所以异步操作完成后拿到对应的数据。

forEach 和 map 的区别

forEach 和 map 两者回调函数的参数都是一样的:item(当前每一项)、index(索引值)、arr(原数组),其中最大的一个不同点就是返回值,forEach 只是执行每次传入的回调函数,map 会把每次遍历执行回调函数的返回值,继续返回组成一个新的数组返回,如果当次循环没有 return 任何数据,默认就是 undefined。其中的差异我们从下面的手写版中也能很容易看出来。

自定义版手写 forEach 方法:

Array.prototype.customForEach = function (callback) {for (let i = 0; i < this.length; i++) {callback(this[i], i, this)}
}

自定义版手写 map 方法:

Array.prototype.customMap = function (callback) {const arr = []for (let i = 0; i < this.length; i++) {const res = callback(this[i], i, this)arr.push(res)}return arr
}

最后总结:开发中如果不是纯遍历处理数据时 forEach、map 这些要少用,每次遍历时还有其他异步操作或副作用时,直接 for 循环一把梭最稳妥,代码逻辑也最好理解。

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

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

相关文章

生产环境中秒杀接口并发量剧增与负载优化策略探讨

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 1. 实施限流措施 1.1 令牌桶算法&#xff1a; 1.2 漏…

红酒知识百科:从入门到精通

红酒&#xff0c;这个深邃而迷人的世界&#xff0c;充满了无尽的知识与奥秘。从葡萄的选择、酿造工艺&#xff0c;到品鉴技巧&#xff0c;每一步都蕴藏着深厚的文化底蕴和精细的技艺。今天&#xff0c;就让我们一起踏上这场红酒知识之旅&#xff0c;从入门开始&#xff0c;逐步…

gpt-4o看图说话-根据图片回答问题

问题&#xff1a;中国的人口老龄化究竟有多严重&#xff1f; 代码下实现如下&#xff1a;&#xff08;直接调用openai的chat接口&#xff09; import os import base64 import requests def encode_image(image_path): """ 对图片文件进行 Base64 编码 输入…

【刷题汇总 -- 求最小公倍数、数组中的最长连续子序列、字母收集】

C日常刷题积累 今日刷题汇总 - day0081、求最小公倍数1.1、题目1.2、思路1.3、程序实现 -- 穷举法1.2、程序实现 -- 辗转相除法 2、数组中的最长连续子序列2.1、题目2.2、思路2.3、程序实现 3、字母收集3.1、题目3.2、思路3.3、程序实现 4、题目链接 今日刷题汇总 - day008 1、…

Windows C++ vs2022环境中下载、安装和使用osmesa

第一步&#xff1a;安装 MinGW-w64 请参考这篇文章进行安装&#xff1a; 在Windows中安装MinGW-w64最新版本 第二步&#xff1a;安装DirectX SDK 请参考这篇文章进行安装&#xff1a; 下载安装Microsoft DirectX SDK(June 2010) 第三步&#xff1a;安装Windows SDK 请参考这篇…

oracle索引字段存储数据过长,导致索引失效

1&#xff1a;短位数据&#xff0c;索引生效 2&#xff1a;长位索引&#xff0c;索引不生效 此问题发现于6月中旬&#xff0c;线上问题优化。引以为戒。 解决&#xff1a; 并未解决索引不生效问题&#xff0c; 但是基于优化查询&#xff0c;是的查询保持毫秒级

第一个基于FISCOBCOS的前后端项目(发行转账)

本文旨在介绍一个简单的基于fiscobcos的前后端网站应用。Springbootjs前后端不分离。 所使用到的合约也是一个最基本的。首先您需要知道的是完整项目分为三部分&#xff0c;1是区块链平台webase搭建&#xff08;此项目使用节点前置webase-front即可&#xff09;&#xff0c;2是…

语义分割和实例分割区别?

语义分割&#xff1a;将图像中的每个像素分配给其对应的语义类别&#xff0c;其主要针对于像素&#xff0c;或者说它是像素级别的图像分割方法。&#xff1a;语义分割的目的是为了从像素级别理解图像的内容&#xff0c;并为图像中的每个像素分配一个对象类。 实例分割&#xf…

DMA方式的知识点笔记

苏泽 “弃工从研”的路上很孤独&#xff0c;于是我记下了些许笔记相伴&#xff0c;希望能够帮助到大家 目录 1. DMA基本概念 2. DMA传送过程 易错点 DMA控制器操作流程 3. DMA传送方式 这是单总线的结果 &#xff08;CPU说了算 所以不会产生于CPU的冲突&#xff09; 这…

新浪API系列:支付API打造无缝支付体验,畅享便利生活(3)

在当今数字化时代&#xff0c;支付功能已经成为各类应用和平台的必备要素之一。作为开发者&#xff0c;要构建出安全、便捷的支付解决方案&#xff0c;新浪支付API是你不可或缺的利器。新浪支付API提供了全面而强大的接口和功能&#xff0c;帮助开发者轻松实现在线支付的集成和…

软件开发面试题(C#语言,.NET框架)

1. 解释什么是委托&#xff08;Delegate&#xff09;&#xff0c;并举例说明它在C#中的用法。 委托是一种引用类型&#xff0c;它可以用于封装一个或多个方法。委托对象可以像方法一样调用&#xff0c;甚至可以用于创建事件处理程序。委托是C#中实现事件和回调函数的重要机制。…

【PyTorch][chapter 26][李宏毅深度学习][attention-1]

前言&#xff1a; attention 在自然语言处理&#xff0c;声音处理里面是一个很重要的技巧. attention 要解决的是输入的向量长度不定. 根据输入输出的不同,分为三种场景&#xff1a; 输入N个向量&#xff0c;输出N个向量,这是本章的重点 输入N个向量&#xff0c;输出向量不定 输…

施罗德数列SQL实现

在组合数学中,施罗德数用来描述从(0,0)到(n,n)的格路中,只能使用(1,0)、(0,1)、(1,1)三种移动方式,始终位于对角线下方且不越过对角线的路径数 DECLARE n INT 10 DECLARE i INT DECLARE rst INT DECLARE old INT1CREATE TABLE #rst (i INT ,rst int )INSERT INTO #rst values(…

3-7 使用深度学习解决温度即示数问题

3-7 使用深度学习解决温度即示数问题 直接上代码 %matplotlib inline import matplotlib.pyplot as plt import numpy as np import torch torch.set_printoptions(edgeitems2, linewidth75)设置Jupyter Notebook在单元格中内嵌显示图像&#xff0c;导入所需库并设置PyTorch的…

阿里发布大模型发布图结构长文本处理智能体,超越GPT-4-128k

随着大语言模型的发展&#xff0c;处理长文本的能力成为了一个重要挑战。虽然有许多方法试图解决这个问题&#xff0c;但都存在不同程度的局限性。最近&#xff0c;阿里巴巴的研究团队提出了一个名为GraphReader的新方法&#xff0c;通过将长文本组织成图结构&#xff0c;并利用…

2,区块链、数字货币及其应用场景(react+区块链实战)

2&#xff0c;区块链、数字货币及其应用场景&#xff08;react区块链实战&#xff09; 一、什么是区块链&#xff1f;1 ibloackchain&#xff08;1&#xff09;安装ibloackchain&#xff08;2&#xff09;Blance查询余额&#xff08;3&#xff09;Mine挖矿&#xff08;4&#x…

JavaScript中的拷贝技术探秘:浅拷贝与深拷贝的奥秘

最新技术资源&#xff08;建议收藏&#xff09; https://www.grapecity.com.cn/resources/ 前言 JavaScript中的浅拷贝和深拷贝是非常重要的概念&#xff0c;它们在处理对象和数组时具有不同的作用。在编程中&#xff0c;经常需要复制数据以便进行各种操作&#xff0c;但必须注…

小波与傅里叶变换的对比(Python)

直接上代码&#xff0c;理论可以去知乎看。 #Import necessary libraries %matplotlib inline import numpy as np import matplotlib.pyplot as plt import seaborn as snsimport pywt from scipy.ndimage import gaussian_filter1d from scipy.signal import chirp import m…

基于 sftp 的 NAS (局域网文件存储服务器)

局域网 NAS (文件存储服务器) 的基本功能有: 能够存储文件, 同时能够通过多个设备访问 (上传/下载) 文件. 这些功能通过 sftp 可以实现. sftp 是基于 SSH 的文件传输协议, SSH 全程加密传输, 使用 公钥 认证 (不使用密码/口令), 能够提供很高的安全性. 上文说到, 在 LVM 和 bt…

谷粒商城-个人笔记(集群部署篇三)

前言 ​学习视频&#xff1a;​Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强​学习文档&#xff1a; 谷粒商城-个人笔记(基础篇一)谷粒商城-个人笔记(基础篇二)谷粒商城-个人笔记(基础篇三)谷粒商城-个人笔记(高级篇一)谷粒商城-个…