ajaxjqueryasynchronoushttp-status-code-200

How do I rewrite this function to be asynchronous?


I have a function that pulls images from an API to insert them in an animated scroller. It looks like this (simplified for clarity):

function getPhotos(id) {
    $.when(Service.getPhotos(id))
        .then(function(results) {
            var photos = results.photos,
                scroller = $("#scroller");

            // Add the photos to the scroller
            for (var i = 0; i < photos.length; i++) {
                var photo = photos[i].url;

                // Only add a photo if its URL is valid
                if (photoExists(photo) == 200) {
                    scroller.append("<li><img src='" + photo + "' /></li>");    
                } else {
                    console.log("Photo " + photo + " doesn't exist");
                }
            }
        })
        .fail(function(err) {
            console.log(err);
        });
}

However, the photo URLs don't always resolve to valid images, so I run them through the photoExists() function:

function photoExists(photo) {
    var http = jQuery.ajax({
        type: "HEAD",
        url: photo,
        async: false
    });

    return http.status;
}

If a given photo URL returns a status code of 200, then I know the image exists and I insert it into the scroller; otherwise, I skip over it so that I don't insert a broken image.

The problem here is that async: false – because this isn't asynchronous, the whole UI locks up until everything completes, which can be a very long time depending on how many photo URLs I have to loop through.

If I use async: true, however, then the photoExists() function attempts to return the status code before the AJAX request itself actually completes – so photoExists(photo) never returns 200, resulting in nothing being added to the scroller.

How would I adjust this so that photoExists() can run asynchronously and therefore avoid locking up the UI, but still return the correct status code so I can insert the photos into the scroller properly?


Solution

  • You need to provide a callback function for your photoExists function. Something like this:

    function photoExists(photo, callback) {
        var http = jQuery.ajax({
            type: "HEAD",
            url: photo,
            async: true,
            success: function(){
                callback(photo, true);
            },
            error: function(){
                callback(photo, false);
            }
        });
    }
    

    Then use it like so:

    for (var i = 0; i < photos.length; i++) {
        var photo = photos[i].url;
    
        // Only add a photo if its URL is valid
        photoExists(photo, function(photo, isSuccessful){
            if (isSuccessful) {
                scroller.append("<li><img src='" + photo + "' /></li>");    
            } else {
                console.log("Photo " + photo + " doesn't exist");
            }
        });
    }
    

    Added photo to callback function to avoid possible closure issues with the for loop