0

This topic is covered in a few other questions, but I had some difficulty applying the suggested approaches into this use case. I have a checkbox list, where a user can select n sub-sites to publish their post to. since this list could grow to be 100+, I need an efficient way to perform an expensive task on each one. It's okay if it takes awhile, as long as Im providing visual feedback, so I planned to apply an "in progress" style to each checkbox item as its working, then move to the next item int he list once it is successfully published. Also note: I'm working in the WordPress wp_ajax_ hook but the PHP side of things is working well, this is focused on the JS solution.

This code is working right now (console.logs left in for debug), but I've seen multiple warnings against using async: true. How can I achieve a waterfall AJAX loop in a more efficient way?

//Starts when user clicks a button
 $("a#as_network_syndicate").click( function(e) {
    e.preventDefault(); //stop the button from loading the page

//Get the checklist values that are checked (option value = site_id)    
 $('.as-network-list').first().find('input[type="checkbox"]').each(function(){
        if($(this).is(':checked')){
            blog_id = $(this).val();

            console.log(blog_id+' started');

            $(this).parent().addClass('synd-in-progress');  //add visual feedback of 'in-progress'
            var process = as_process_syndication_to_blog(blog_id);

            console.log('finished'+blog_id);

            $(this).parent().removeClass('synd-in-progress');
        }
    });
});

function as_process_syndication_to_blog(blog_id){

    var data  = { 
            "post_id": $('#as-syndicate_data-attr').attr("data-post_id"),  //these values are stored in hidden html elements
            "nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
            "blog_id": blog_id
        };

    var result = as_syndicate_to_blog(data);

    console.log('end 2nd func');

    return true;
}
function as_syndicate_to_blog(data){
    $.ajax({
        type : "post",
        dataType : "json",
        async: false,
        url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
        data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id},
        success: function(response) {
            if(response.type == "success") {
                console.log(response);

                return response;
            } else {

            }
        },
        error: {

        }
    });
}
1
  • 1
    You shouldn't use a loop calling an AJAX function, but send the array (or object) as an AJAX parameter and let the server side code do the loop. Commented Nov 17, 2014 at 14:03

2 Answers 2

2

Indeed, doing synchronous AJAX request is bad because it will block the browser during the whole AJAX call. This means that the user cannot interact with your page during this time. In your case, if you're doing like 30 AJAX calls which take say 0.5 seconds, the browser will be blocked during 15 whole seconds, that's a lot.

In any case, you could do something following this pattern:

// some huge list
var allOptions = [];

function doIntensiveWork (option, callback) {
    // do what ever you want
    // then call 'callback' when work is done
    callback();
}

function processNextOption () {
    if (allOptions.length === 0)
    {
        // list is empty, so you're done
        return;
    }

    // get the next item
    var option = allOptions.shift();

    // process this item, and call "processNextOption" when done
    doIntensiveWork(option, processNextOption);

    // if "doIntensiveWork" is asynchronous (using AJAX for example)
    // the code above might be OK.

    // but if "doIntensiveWork" is synchronous,
    // you should let the browser breath a bit, like this:
    doIntensiveWork(option, function () {
        setTimeout(processNextOption, 0);
    });

}

processNextOption();

Notice: as said by Karl-André Gagnon, you should avoid doing many AJAX requests using this technique. Try combining them if you can, it will be better and faster.

Sign up to request clarification or add additional context in comments.

Comments

0

If you can't pass the whole block to the server to be processed in bulk, you could use a jQuery queue. This is using your sample code as a base:

var $container = $('.as-network-list').first();
$container.find('input[type="checkbox"]:checked').each(function(){
    var $input = $(this);
    $container.queue('publish', function(next) {
        var blog_id = $input.val(),
            $parent = $input.parent();

        console.log(blog_id+' started');

        $parent.addClass('synd-in-progress');  //add visual feedback of 'in-progress'
        as_process_syndication_to_blog(blog_id).done(function(response) {

            console.log(response);
            console.log('finished'+blog_id);

            $parent.removeClass('synd-in-progress');
            next();            
        });

   });
});

$container.dequeue('publish');

function as_process_syndication_to_blog(blog_id){

    var data  = { 
            "post_id": $('#as-syndicate_data-attr').attr("data-post_id"),  //these values are stored in hidden html elements
            "nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
            "blog_id": blog_id
        };

    return as_syndicate_to_blog(data).done(function(){ console.log('end 2nd func'); });
}
function as_syndicate_to_blog(data){
    return $.ajax({
        type : "post",
        dataType : "json",
        url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
        data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id}
    });
}

I don't have a test environment for this so you may need to tweak it for your use case.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.