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

时间:2014-11-14 06:01:42

标签: javascript jquery jquery-deferred

我几乎把头撞到了墙上,因为我无法得到以下代码。我正在尝试使用flickrApi对照片库进行编码,并且遇到多个异步调用的问题。但也许有一个更清洁的解决方案来编码。

单击photoset的链接时会调用openPhotoset()。不幸的是,获取照片的描述我需要使用不同的方法,这意味着另一个异步调用。我正在遍历数据,但因为我在一个循环中进行调用(当我有照片ID可用时),openPhotoset()的延迟在循环之后但之前没有解决。我阅读并看过在循环中使用$ .when()的示例,使用deferreds填充数组并使用$ .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;

        }

2 个答案:

答案 0 :(得分:1)

你可以通过在几个地方更改.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);
        });
    });
}

这里的主要区别是创建一个promises数组而不是一个照片对象数组,并允许promises传递数据。这允许$.when()在满足所有承诺时启动回调 - 即,当为集合中的所有照片组成数据对象时。

请注意使用.map()代替.each(),从而简化promises的创建。

最后,openPhotoset()返回的整体承诺允许在完成整个过程时采取任何行动。只需链.then()

openPhotoset(...).then(function() {
    // here, do whatever
});

修改

如果内部工作被拉出并重新定义为命名的承诺返回函数 - 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);
    });
}

答案 1 :(得分:0)

我被deferreds和$ .when函数所蒙蔽,我没有注意到我需要的只是创建一个计数器并在每次requestPhotoInfo完成后倒计时并在渲染html之后