سؤال

How do you go about knowing when a For Loop is done iterating and attach a callback.

This is a sample loop of many loops within a function that inserts records into indexedDB.

 if (Object.hasOwnProperty("Books")) {
            for (var i = 0, j = Object["Books"].length; i < j; i++) {
                server.Book.add({
                    title: Object["Books"][i].Cat,
                    content: Object["Books"][i]
                });
            }
        }

I need to be able to know when each of the if statements loops are finished then attach a callback. All the loops are being fired asynchronously, and I need to run a function_final() just when all loops are finished not when they are fired.

EDIT

What I have tried so far :

 InsertDB = {
  addBook: function(Object) {
    return $.Deferred(function() {
        var self = this;
        setTimeout(function() {
        if (Object.hasOwnProperty("Book")) {                
            for (var i = 0, j = Object["Book"].length; i < j; i++) {
                server.Book.add({
                    title: Object["Book"][i].id,
                    content: Object["Book"][i]
                });
            }
            self.resolve();
        }
        }, 200);
   });  
 },
  addMagaz: function(Object) {
  return $.Deferred(function() {
        var self = this;
        setTimeout(function() {

        if (Object.hasOwnProperty("Magaz")) {
            for (var i = 0, j = Object["Magaz"].length; i < j; i++) {                  
                server.Magaz.add({
                    content: Object["Magaz"][i]
                });
            }
            self.resolve();
        }
        }, 2000);
   });  
},
addHgh: function(Object) {
    return $.Deferred(function() {
        var self = this;
        setTimeout(function() {

        if (Object.hasOwnProperty("MYTVhighlights")) {
            for (var i = 0, j = Object["MYTVhighlights"].length; i < j; i++) {
                server.MYTVhighlights.add({
                    content: Object["MYTVhighlights"][i]
                });
            }
            self.resolve();
         }
        }, 200);
   });  

  }, ect...

then on a AJAX success callback :

 success: function(data){
 var Object = $.parseJSON(data);

    $.when(InsertDB.addBook(Object),
    InsertDB.addMagaz(Object),
    InsertDB.addUser(Object),
    InsertDB.addArticles(Object),
    InsertDB.addHgh(Object),
    InsertDB.addSomeC(Object),
    InsertDB.addOtherC(Object)).done(final_func);

 function final_func() {
    window.location = 'page.html';
  }

Here final_func is fired before looping ends..

Thanks

هل كانت مفيدة؟

المحلول 2

Since you've said that server.Book.add() is asynchronous, you will need a method of knowing when that asynchronous operation is completed and you can then use that to build a system for knowing when all of them are done. So, the pivotal question (which I already asked as a comment earlier and you have not responded to) is how you can know when server.Book.add() is actually complete. If you're using an indexedDB, then somewhere inside that function, there is probably a request object that has an onsuccess and onerror methods that will tell you when that specific operation is done and that information needs to get surfaced out to server.Book.add() in some way, either as a completion callback or as a returned promise (those two options are how $.ajax() operates for it's asynchronous behavior.

Let's suppose that server.Book.add() returns a promise object that is resolved or rejected when the asychronous .add() operation is complete. If that was the case, then you could monitor the completion of all the operations in your loop like this:

    if (obj.hasOwnProperty("Books")) {
        var promises = [], p;

        for (var i = 0, j = obj["Books"].length; i < j; i++) {
            p = server.Book.add({
                title: obj["Books"][i].Cat,
                content: obj["Books"][i]
            });
            promises.push(p);
        }
        $.when.apply($, promises).done(function() {
            // this is executed when all the promises returned by
            // server.Book.add() have been resolved (e.g. completed)
        }).error(function() {
            // this is executed if any of the server.Book.add() calls
            // had an error
        });
    }

Let's suppose that instead of server.Book.add() returning a promise, it has a couple callbacks for success and error conditions. Then, we could write the code like this:

    if (obj.hasOwnProperty("Books")) {
        var promises = [], p;

        for (var i = 0, j = obj["Books"].length; i < j; i++) {
            (function() {
                var d = $.Deferred();
                server.Book.add({
                    title: obj["Books"][i].Cat,
                    content: obj["Books"][i],
                    success: function() {
                        var args = Array.prototype.slice.call(arguments, 0);
                        d.resolve.apply(d, args);
                    },
                    error: function() {
                        var args = Array.prototype.slice.call(arguments, 0);
                        d.reject.apply(d, args);
                    }
                });
                promises.push(d.promise());
            })();
        }
        $.when.apply($, promises).done(function() {
            // this is executed when all the promises returned by
            // server.Book.add() have been resolved (e.g. completed)
        }).error(function() {
            // this is executed if any of the server.Book.add() calls
            // had an error
        });
    }

So, since you've not disclosed how server.Book.add() actually indicates its own completion, I can't say that either of these blocks of code work as is. This is meant to demonstrate how you solve this problem once you know how server.Book.add() communicates when it is complete.

Promises/Deferreds are not magic in any way. They don't know when an operation is completed unless that operation calls .resolve() or .reject() on a promise. So, in order to use promises, your async operations have to participate in using promises or you have to shim in a promise to an ordinary completion callback (as I've done in the second code block).

FYI, I also change your Object variable to obj because defining a variable named Object that conflicts with the built-in Object in the javascript language is a bad practice.

نصائح أخرى

You can use JavaScript closures, just like this:

if (Object.hasOwnProperty("Books")) {
    for (var i = 0, j = Object["Books"].length; i < j; i++) {
        (function(currentBook)
            server.Book.add({
                title: currentBook.Cat,
                content: currentBook
            });
        )(Object["Books"][i]);
    }

    function_final();
}

For more information about closures you can refer here.

use jquery when functionality

$.when( function1 , function2 )
  .then( myFunc, myFailure );

I'd write something like this in pure JS, consider it as pseudo code:

var totalForLoopsCount = 3; //Predict for loops count here
var forLoopsFinished = 0;

function finalFunction()
{
    alert('All done!');
}

function forLoopFinished()
{
    forLoopsFinished++;
    if(forLoopsFinished == totalForLoopsCount)
    {
        finalFunction();
    }
}

var length = 10; //The length of your array which you're iterating trough

for(var i=0;i<length;i++)
{
    //Do anything        

    if(i == length-1)
    {
        forLoopFinished();
    }
}

for(var i=0;i<length;i++)
{
    //Do anything        

    if(i == length-1)
    {
        forLoopFinished();
    }
}

for(var i=0;i<length;i++)
{
    //Do anything    

    if(i == length-1)
    {
        forLoopFinished();
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top