JavaScript API数据未加载完成提前渲染HTML的问题解决咨询
解决方案
核心问题原因
forEach遍历调用异步函数unqReleaseCoversUrl时不会等待异步请求完成,会直接执行后续的数组过滤、函数返回逻辑,导致await loadTrackDetail结束时封面请求还未完成,coverUrlArray为空- 每次查询新曲目时未清空
coverUrlArray,导致旧数据不断累加
代码修改步骤
1. 修改unqReleaseCoversUrl函数
调整该函数为返回当前发行版的有效封面数组,避免直接修改全局变量产生副作用,同时增加异常兼容,单个封面请求失败不中断整体流程:
export const unqReleaseCoversUrl = async function (mbid) { try { const coverData = await GET_JSON( encodeURI(`${CONSTANTS.COVER_API_URL}${mbid}`) ); // 直接返回当前发行版的有效封面数组 return coverData.images .filter(image => image.thumbnails["500"]) .map(image => image.thumbnails["500"]); } catch (err) { console.warn(`获取发行版${mbid}封面失败:`, err); // 请求失败返回空数组,不中断整体流程 return []; } };
2. 修改loadTrackDetail函数
新增清空旧封面数据的逻辑,用Promise.all等待所有封面请求完成后再继续执行:
export const loadTrackDetail = async function (id) { try { // 每次查询前先清空旧封面数据,解决旧数据累加问题 details.coverUrlArray = []; const trackData = await GET_JSON( encodeURI( `${CONSTANTS.API_URL}${id}?inc=genres+artists+ratings+releases&fmt=json` ) ); details.trackDetails = { trackTitle: trackData.title ?? "No title provided", trackID: trackData.id, trackReleaseDate: trackData["first-release-date"] ?? "No date provided", trackLength: trackData.length ? CONVERT_MILLIS_TO_MINS_SECONDS(trackData.length) : "No duration provided", trackArtists: trackData["artist-credit"].length ? trackData["artist-credit"] : "No information on artists", trackReleasesBase: trackData["releases"].length ? trackData["releases"] : "No information on releases", trackReleasesCleanOne: trackData["releases"].length ? trackData["releases"].map((release) => ({ id: release.id, title: release.title, })) : "No information on releases", trackGenres: trackData["genres"].length ? trackData["genres"] : "No information on genres", trackRating: trackData.rating.value ?? "No rating yet", }; if (details.trackDetails.trackReleasesCleanOne.length > 0) { // 生成所有封面请求的Promise数组 const coverPromises = details.trackDetails.trackReleasesCleanOne.map((mbid) => unqReleaseCoversUrl(mbid.id) ); // 等待所有请求完成,扁平化结果后存入全局数组 const coverResults = await Promise.all(coverPromises); details.coverUrlArray = coverResults.flat(); } console.log(details.coverUrlArray); } catch (err) { throw err; } };
逻辑说明
- 控制器层代码无需修改,原有的
await detailsModel.loadTrackDetail(trackID)会等待所有封面数据准备完成后,再执行后续的渲染逻辑,此时传入renderCovers的数组已经包含全部有效封面地址 - 如果API有请求频率限制,可将
Promise.all替换为分批请求的逻辑,避免触发接口限流
内容的提问来源于stack exchange,提问作者Bertrand B
相关产品推荐
相关产品推荐

