我差点把头撞到墙上,因为我无法让下面的代码正常工作。我正在尝试使用 flickrApi 编写照片库代码,但在多个异步调用方面遇到问题。但也许有一个更干净的解决方案来编码这个。
单击照片集的链接时会调用 openPhotoset()。不幸的是,获取照片的描述我需要使用不同的方法,这意味着另一个异步调用。我正在循环访问数据,但因为我在循环中进行调用(即当我有可用的照片 ID 时),openPhotoset() 的延迟不会在循环之后解决,而是在循环之前解决。我读过并看到过在循环中使用 $.when() 的示例,用延迟填充数组并使用 $.when 检查,但我似乎在这方面失败了。这是我需要的解决方案还是还有其他救赎之路? ;)
我想在 openPhotoset() 中的所有调用完成后执行不同的函数。
function openPhotoset(photosetId) {
var currentPhotoset = [],
deferred = $.Deferred();
_requestPhotosOfSet(photosetId).done(function(data){
$(data.photoset.photo).each(function(i, photo){
var objPhoto = {};
objPhoto.id = photo.id;
objPhoto.title = photo.title;
objPhoto.farm = photo.farm;
objPhoto.server = photo.server;
objPhoto.secret = photo.secret;
// get photo description
requestPhotoInfo(photo.id).done(function(data) {
objPhoto.description = data.photo.description._content;
currentPhotoset.push(objPhoto);
}).then(function() {
// TODO: renders with each iteration, shouldnt!
var template = $('#li-gallery').html(),
result = Mustache.render(template, {currentPhotoset:currentPhotoset});
showGallery();
_$fyGallery.find('.gallery-list').html(result);
deferred.resolve();
});
});
});
return deferred;
}
最佳答案
您可以通过在几个地方将 .done()
更改为 .then()
来实现此目的,并重新排列一些内容 - 相当不错
很多。
我想您可能一直在寻找这样的东西:
function openPhotoset(photosetId) {
return _requestPhotosOfSet(photosetId).then(function(data) {
var promises = $(data.photoset.photo).map(function(photo) {
return requestPhotoInfo(photo.id).then(function(data) {
return {
id: photo.id,
title: photo.title,
farm: photo.farm,
server: photo.server,
secret: photo.secret,
description: data.photo.description._content
};
});
}).get();//.get() is necessary to convert a jQuery object to a regular js array.
return $.when.apply(null, promises).then(function() {
var template = $('#li-gallery').html(),
result = Mustache.render(template, {
currentPhotoset: Array.prototype.slice.apply(arguments)
});
showGallery();
_$fyGallery.find('.gallery-list').html(result);
});
});
}
这里的主要区别是创建一系列 Promise,而不是创建一系列照片对象,并允许 Promise 传达数据。这允许 $.when()
在所有 promise 都得到满足时触发回调 - 即当数据对象已为集合中的所有照片组成时。
请注意使用 .map()
而不是 .each()
,从而简化了 promise
的创建。
最后,openPhotoset()
返回的总体 promise 允许在完成整个过程后采取任何操作。只需链接 .then()
。
openPhotoset(...).then(function() {
// here, do whatever
});
<小时/>
编辑
如果内部工作被拉出来并重新表述为命名的 promise 返回函数 - getPhotoInfoObject()
和 renderData()
,那么整体模式可能更容易理解。
function openPhotoset(photosetId) {
function getPhotoInfoObject(photo) {
return requestPhotoInfo(photo.id).then(function(data) {
//$.extend() is much less verbose than copying `photo`'s properties into a new object longhand.
return $.extend(photo, {description: data.photo.description._content});
});
}
function renderData() {
var template = $('#li-gallery').html(),
currentPhotoset = Array.prototype.slice.apply(arguments),
result = Mustache.render(template, {
currentPhotoset: currentPhotoset
});
showGallery();
_$fyGallery.find('.gallery-list').html(result);
}
// With the inner workings pulled out as getPhotoInfoObject() and renderData(),
// the residual pattern is very concise and easier to understand.
return _requestPhotosOfSet(photosetId).then(function(data) {
var promises = $(data.photoset.photo).map(getPhotoInfoObject).get();
return $.when.apply(null, promises).then(renderData);
});
}
关于javascript - flickrapi (js) 循环中的多个异步调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26923881/