简体   繁体   English

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

[英]flickrapi (js) multiple async calls in a loop

I allmost banged my head into the wall because I can't get the following code too work. 我全力以赴,因为我无法使以下代码正常工作。 I'm trying to code a photo gallery with the flickrApi and have problems with multiple async calls. 我正在尝试使用flickrApi编写一个照相馆,并遇到多个异步调用的问题。 But perhaps there is a cleaner solution to code this. 但是也许有一个更干净的解决方案对此进行编码。

openPhotoset() is called when clicking the link of a photoset. 单击照片集的链接时,将调用openPhotoset()。 Unfortunately getting the description of a photo I need to use a different method, which means another async call. 不幸的是,获得照片的描述后,我需要使用其他方法,这意味着需要进行另一个异步调用。 I'm looping through the data, but because I make the call in a loop (that's when I have the photo-id available) the deferred of openPhotoset() doesn't resolve after looping but before. 我正在遍历数据,但是因为我是在循环中进行调用(那是在我有可用的photo-id的情况下),所以openPhotoset()的延迟在循环之后但在解析之前无法解析。 I read and have seen examples of $.when() used in a loop, filling an array with deferreds and checking with $.when but I seem to fail horribly at it. 我阅读并看到了在循环中使用$ .when()的示例,用延迟填充了数组,并用$ .when检查,但是我似乎在这方面失败了。 Is this the solution I need or is there another road to salvation? 这是我需要的解决方案,还是另辟road径? ;) ;)

I want to execute different functions after all calls within openPhotoset() has completed. 我想在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;

        }

You can do this by changing .done() for .then() in a couple of places, and rearranging things a bit - well quite a lot. 您可以通过在几个地方将.done()更改为.then()并进行一些重新排列来完成此操作-相当多。

I think you've probably been searching for something like this : 我认为您可能一直在寻找这样的东西:

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);
        });
    });
}

The main difference here is the creation of an array of promises as opposed to an array of photo objects, and allowing the promises to convey the data. 这里的主要区别是创建了一个承诺数组,而不是一个照片对象数组,并允许这些承诺传达数据。 This allows $.when() to fire off a callback when all the promises are fulfilled - ie when data objects have been composed for all photos in the set. 当所有的诺言都得到满足时,即当为集合中的所有照片组成数据对象时,这允许$.when()触发回调。

Note the use of .map() instead of .each() , thus simplifying the creation of promises . 注意使用.map()代替.each() ,从而简化了promises的创建。

And finally, the overall promise returned by openPhotoset() allows whatever action to be taken on completion of the whole process. 最后, openPhotoset()返回的总体承诺允许在整个过程完成时采取任何措施。 Just chain .then() . 只是链.then()

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

EDIT 编辑

The overall pattern is probably easier to understand if the inner workings are pulled out and rephrased as named promise-returning functions - getPhotoInfoObject() and renderData() . 如果将内部工作方式拉出并改写为命名的承诺返回函数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);
    });
}

我对延迟和$ .when函数视而不见,以至于我没有注意到我需要做的就是创建一个计数器,并在每次requestPhotoInfo完成后以及在呈现html之后倒计数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM