Adam
Adam

Reputation: 933

JavaScript for loop with innerHTML not updating during loop execution

I'm looping through an array, and during each iteration of the loop, I'm calling a url through ajax. I'd like to also update an .innerHTML such that it displays to keep the user informed as to which iteration of the loop is being processed. However, .innerHTML only displays the update when the script completes.

How can I make this notification display during my loop?

I'm also using the query ajax setting 'async: false'. I don't want to hammer my server with processing all of the ajax requests at once, as they are encoding video files which is CPU intensive. I don't really want to lock the browser up waiting for synchronous requests to complete either.

Is there a better way to do this?

My ultimate goal is to sequentially execute my combine.php script for each set of videos, while displaying a current status indicator to the user, and while not locking the browser up in the process. Your help is appreciated!

Code snippet here:

// process the loop of videos to be combined
    var status = document.getElementById('currentStatus');
    for (i=0; i< count; i++) {

        // change the display

        var fields = videos[i].split(":", 2);

        current = i +1;

        currentStatus.innerHTML = "<b>Multi-part Videos:</b>&nbsp;&nbsp;&nbsp; <h3 class='status'>Currently Updating Bout #" + fields[1] + " (" + current + " of " + count + " videos)</h3>";



        // run the combine 
        var dataString = 'videoId='+ fields[0]; 



        $.ajax({  
            type: "POST",  
            url: "combine.php",  
            data: dataString,  
            success: function(txt) {


                //deselect the checkbox

                document.combine.video[selected[i]].checked = false;
            },
            async: false 
        }); 

Upvotes: 0

Views: 2113

Answers (3)

Dexter
Dexter

Reputation: 18452

As others have alluded, your problem is caused because JavaScript is single threaded - while the single JS thread is waiting for your ajax request to return, it's not allowed to update the UI.

You can get around this by changing the request to async, and using the callback to trigger the request for the next object:

// trigger the loop of videos to be combined
var status = document.getElementById('currentStatus');
processVideo( 0 );

function processVideo( index ) {
    var fields = videos[index].split(":", 2);

    currentStatus.innerHTML = "<b>Multi-part Videos:</b>&nbsp;&nbsp;&nbsp; <h3 class='status'>Currently Updating Bout #" + fields[1] + " (" + current + " of " + count + " videos)</h3>";

    // run the combine 
    var dataString = 'videoId='+ fields[0]; 

    $.ajax({  
        type: "POST",  
        url: "combine.php",  
        data: dataString,  
        success: function() {
           processResponse( index);
        },
        async: true
    });
}

function processResponse( index ) {
   // this method is called each time the ajax request finishes
   if (index++ < count) {
      //deselect the checkbox
      document.combine.video[selected[index]].checked = false;

      processVideo( index );
   }
}

Upvotes: 1

Bao Nhan
Bao Nhan

Reputation: 180

If you want to update one by one while async is set to true, the next request can be put in the success callback function. The update status code should be inside that function too.

function ajaxRequest(i){

        // other processing
        .............

        $.ajax({  
            type: "POST",  
            url: "combine.php",  
            data: dataString,  
            success: function(txt) {

                //deselect the checkbox
                document.combine.video[selected[i]].checked = false;

                // update status
                currentStatus.innerHTML = .....
                // make next request
                if(i<lastOne){
                     ajaxRequest(i+1);
                }
            },
            async: true
        }); 
}

Upvotes: 0

Matt Ball
Matt Ball

Reputation: 359966

async: false will hang the entire browser until the ajax request completes. That is why you don't see the page update on each loop iteration.

Synchronous ajax requests typically make for terrible UX (do you like the page to freeze inexplicably?) and there is almost always a better way to do it. Since you're using jQuery, the Deferred Object API makes this easy.

Upvotes: 1

Related Questions