0

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

5
  • Does server.Book.add return a promise? Commented Apr 25, 2014 at 6:28
  • I think that is exactly a task fo js Promise. Create promises for your loops. Resolve once loop is finished. Wrap promises in when. Attach single callback in then. Commented Apr 25, 2014 at 6:28
  • Yes it does. It is a IndexedDB plugin called DB.js and you can attach a .done(). Please see updated post, added what I have tried Commented Apr 25, 2014 at 6:37
  • If server.Book.add() is an asynchronous operation, how do you know when it's done? Does it return a promise? Does it have an option for a completion/success callback? Without that information, you can't know when they are all done. Commented Apr 25, 2014 at 15:16
  • As a side note, it's a really bad practice to define your own variable named Object as that conflicts with the built-in Object definition. Commented Apr 25, 2014 at 15:36

4 Answers 4

1

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.

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

1 Comment

This is a very informative article. It did not solve my problem. but thank you for your time.
0

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.

7 Comments

Thank you alot bro. I came up with something very close with the logic but not as well written.I tried to set up a counter for each iteration to be compared against the object's lenght. this is a great help. Thanks again
server.book uses DB.js which is a wrapper for indexedDB aaronpowell.github.io/db.js
Counters can be used too. That's what $.when() has inside it and what we all did before we had promises.
I am still new to promises and callbacks. I need to dig deeper into it, but I think i get the drift.
What Does the error an Object could not be cloned ? in Node webkit. I keep getting this error while trying to insert records
|
0

use jquery when functionality

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

1 Comment

This is basically a comment, not an answer.
0

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

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.