使用async/await与forEach调用Fetch API后函数返回空数组问题
异步请求导致数组返回为空的问题分析与解决
问题原因
- forEach不支持异步等待:你在
forEach的回调里用了async,但forEach会直接跑完所有回调函数,不会等待每个fetch请求完成。当函数执行到return pokemons时,所有异步请求还在后台运行,数组自然是空的,所以pokemons.length返回0。 - 浏览器Console的快照机制:你展开数组能看到内容,是因为浏览器Console显示的是数组的引用快照。当后续异步请求完成、数据被push进数组后,你展开时浏览器会读取数组的最新状态,但
console.log执行的瞬间数组确实是空的。
Fetch请求的潜在问题
当前代码存在未处理的错误场景:如果请求返回res.ok为false(比如ID不存在),第一个then分支没有返回值,会导致第二个then接收到undefined,此时访问data.id会直接抛出Cannot read properties of undefined的错误,必须处理这种情况。
修复方案
方案1:Promise.all + map(推荐,并行请求)
把forEach换成map,让每个异步请求返回一个Promise,再用Promise.all等待所有请求完成,最后返回处理后的数组:
async function fetchPoke(IDs) { const pokemonPromises = IDs.map(async (id) => { const url = `https://pokeapi.co/api/v2/pokemon/${id}`; const res = await fetch(url); if (!res.ok) { console.log(`${id} not found`); return null; // 返回null,后续过滤掉无效项 } const data = await res.json(); return { id: data.id, name: data.name, image: data.sprites.other.dream_world.front_default }; }); // 等待所有请求完成 const pokemons = await Promise.all(pokemonPromises); // 过滤掉无效的null项 return pokemons.filter(pokemon => pokemon !== null); }
方案2:for...of循环(串行请求)
用for...of遍历IDs,这样可以等待每个请求完成后再执行下一个:
async function fetchPoke(IDs) { const pokemons = []; for (const id of IDs) { const url = `https://pokeapi.co/api/v2/pokemon/${id}`; const res = await fetch(url); if (!res.ok) { console.log(`${id} not found`); continue; // 跳过无效ID } const data = await res.json(); pokemons.push({ id: data.id, name: data.name, image: data.sprites.other.dream_world.front_default }); } return pokemons; }
调用注意事项
因为fetchPoke现在是async函数,返回的是Promise,所以必须用await或者.then()获取结果:
// 方式1:用.then() fetchPoke(yourRandomIDs).then(pokemons => { console.log(pokemons); // 此时数组有正确的长度和内容 }); // 方式2:在async函数里用await async function loadPokemons() { const pokemons = await fetchPoke(yourRandomIDs); console.log(pokemons); } loadPokemons();
内容的提问来源于stack exchange,提问作者K3nzie
相关产品推荐
相关产品推荐

