调用Flickr API后图片src属性undefined问题求助
解决Flickr API调用后图片URL多数为undefined的问题
嘿,我刚好碰到过一模一样的问题!你现在的情况是:明明photoGallery数组里已经有数据了,但渲染后大部分图片的src都是undefined,只有一张能正常显示。核心问题出在异步请求的时序没处理对,咱们一步步理清楚:
问题根源分析
你的代码里,判断是否调用displayImage的条件是searchReceived == searchRequests——这个条件只会判断「所有搜索图片的请求是否完成」,但完全没考虑「每个图片获取尺寸信息的getSizes请求是否全部完成」。
举个例子:你发起了5个搜索请求,当第5个搜索请求返回后,searchReceived就等于searchRequests了,这时候你立刻调用displayImage,但这时候可能只有1个getSizes请求刚好完成,剩下4个还在等待Flickr服务器响应,对应的imageObject.url_small还没被赋值,自然就是undefined。
解决方案:等待所有异步请求完成再渲染
我们需要新增一个计数器,专门统计所有getSizes请求的完成情况,只有当所有getSizes请求都拿到数据后,再执行渲染。
修改后的代码步骤:
- 新增全局计数器,用于追踪
getSizes请求的总数和完成数:
let photoGallery = []; let searchRequests; let searchReceived; let totalSizesRequests = 0; // 新增:统计所有需要发起的getSizes请求数
- 在
searchFlickr开头重置计数器,避免多次搜索时数值累加:
function searchFlickr(searchArray) { photoGallery = []; searchRequests = searchArray.length; searchReceived = 0; totalSizesRequests = 0; // 重置计数器 let flickr_searchStr = ""; $('#Gallery figure').fadeOut(); searchArray.forEach(function (element) { flickr_searchStr = "https://api.flickr.com/services/rest/?method=flickr.photos.search&sort=relevance&content_type=7&format=json&nojsoncallback=1&per_page=1&text=" + element + API_KEY $.get(flickr_searchStr, function (data) { fetchImage(data); }) }) }
- 在
fetchImage里,每新增一个需要获取尺寸的图片,就把计数器加1:
function fetchImage(data) { searchReceived++ for (let i = 0; i < data.photos.photo.length; i++) { let imageObject = {id: data.photos.photo[i].id,title: data.photos.photo[i].title} photoGallery.push(imageObject); totalSizesRequests++; // 每添加一个图片,就增加getSizes请求计数 getSizes(imageObject); } }
- 修改
getSizes的回调逻辑,每次请求完成后减少计数器,当计数器为0时再渲染:
function getSizes(imageObject) { let getSizesStr = "https://api.flickr.com/services/rest/?method=flickr.photos.getSizes&format=json&nojsoncallback=1" + API_KEY + "&photo_id=" + imageObject.id; $.get(getSizesStr, function (data) { // 优化:通过label查找Small尺寸,避免依赖数组索引 const smallSize = data.sizes.size.find(size => size.label === "Small"); imageObject.url_small = smallSize ? smallSize.source : ""; totalSizesRequests--; checkIfReadyToDisplay(); }) // 新增:处理请求失败的情况,避免计数器永远不为0 .fail(function() { // 可以设置一个默认图片URL,或者留空 imageObject.url_small = ""; totalSizesRequests--; checkIfReadyToDisplay(); }); } // 抽成单独的判断函数,代码更清晰 function checkIfReadyToDisplay() { if (totalSizesRequests === 0) { displayImage(photoGallery); } }
额外说明
刚才把data.sizes.size[3]改成了通过label查找Small尺寸,是因为Flickr返回的尺寸数组顺序有可能发生变化,用label匹配比依赖索引更可靠,能避免后续出现意外报错。
总结
本质上就是异步操作的顺序问题:不能只等第一层搜索请求完成,必须等所有第二层获取图片尺寸的请求都完成后,再去渲染页面。用计数器追踪所有异步请求的状态,就能完美解决这个问题啦!
内容的提问来源于stack exchange,提问作者Jim Griffith
相关产品推荐
相关产品推荐

