使用GitHub API开展嵌套fetch请求时返回Promise而非实际数据
问题根源
你遇到的现象本质是异步流程时机错位:
- 执行
repos.map时是同步逻辑,此时每个组件对应的desc字段是多层嵌套fetch返回的Promise(异步操作),而非实际的解码文本 - 你没有等待这些异步操作全部完成,就直接把包含Promise的数组传入
setAppState做状态更新,因此最终拿到的desc自然是已兑现状态的Promise对象,而非它承载的纯文本内容。
调整方案
核心调整思路是:等待所有异步请求全部完成、拿到真实的文件解码内容后,再组装数据更新状态。可以借助async/await优化嵌套的Promise链式调用,代码可读性会大幅提升。
调整后的完整代码如下:
useEffect(() => { const fetchAllComponentInfo = async () => { const apiUrl = `https://api.github.com/repos/afhammk/components/contents` // 拉取仓库根目录下的一级条目(也就是各个组件文件夹) const rootRes = await fetch(apiUrl) const rootEntries = await rootRes.json() console.log("根目录条目", rootEntries) // 遍历每个组件文件夹,为每个文件夹生成对应的信息拉取Promise const componentInfoPromises = rootEntries.map(async (entry) => { // 拉取当前组件文件夹下的所有文件列表 const folderRes = await fetch(entry.url) const folderFiles = await folderRes.json() // 精准匹配description.txt文件,替代原逻辑硬取第一个文件的不稳定写法 const descFile = folderFiles.find(file => file.name === 'description.txt') let descContent = '' // 只有找到对应文件时才拉取内容,避免空数组触发的读取报错 if (descFile) { // 拉取description.txt的原始数据 const descRes = await fetch(descFile.url) const descData = await descRes.json() // 解码base64内容,清除换行符避免atob解码报错 descContent = atob(descData.content.replace(/\s/g, '')) } // 直接返回组装好的纯数据对象,desc已经是解码后的真实文本 return { name: entry.name, html_url: entry.html_url, desc: descContent } }) // 等待所有组件的信息拉取完成,得到纯对象数组 const finalComponentList = await Promise.all(componentInfoPromises) // 此时再更新状态,desc字段就是真实的文本内容,不再是Promise setAppState(finalComponentList) } // 启动异步拉取流程 fetchAllComponentInfo() }, []);
关键改动说明
- 异步流程时机修正:等所有
fetch请求全部拿到结果、完成base64解码后,再执行setAppState,从根本上避免把Promise对象存入状态 - 写法优化:用
async/await替代多层嵌套的.then链式调用,减少逻辑嵌套,更易排查问题 - 稳定性优化:原逻辑直接取文件夹下第一个文件拉取内容,一旦文件顺序变动就会拉错,调整为精准匹配
description.txt文件;解码base64时清除内容中的空白字符,避免GitHub API返回的带换行base64导致atob解码失败;增加空值判断,避免目标文件不存在时的代码报错
内容的提问来源于stack exchange,提问作者user15482647
相关产品推荐
相关产品推荐

