javascript - flickrapi (js) 循环中的多个异步调用

标签 javascript jquery jquery-deferred

我差点把头撞到墙上,因为我无法让下面的代码正常工作。我正在尝试使用 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/

相关文章:

javascript - 使用 Fetch GET 请求设置查询字符串

jquery - 有条件地添加到 jQuery .when

javascript - 如何附加 v-on :click event to html element

JavaScript 浮点好奇心

jquery - 简单解释为什么数据表使用 $.fn.dataTableExt.afnSortData

javascript - 当一组 deferred 中的一个失败时如何处理

javascript - 如何在 JQuery 语句成功时制作简单的延迟

javascript - CKEditor - 反射(reflect)样式,也包括具有复杂选择器的样式

javascript - Google Cloud Functions - 通过 SSL 连接到 Cloud SQL

javascript - 在不刷新页面的情况下更改调整大小的内容?