0

I have some code in jQuery that iterate through children in div using each(). Every text inside is splitted into words. Each word is processed with 'for' loop. This function can take a long time and can freeze the browser so...

Is there a way to create asynchronous loop inside another asynchronous loop but one is waiting for other to finish?

Could anyone tell me the right direction?

I came up with something like this:

var queue = [];
var nlevel = 0;

function work() {
    nlevel = queue.length-1;

    var arr = queue[nlevel][0];
    var process = queue[nlevel][1];
    var cnt = queue[nlevel][2];
    var item = arr[cnt];

    process.apply(item);

    cnt++;
    queue[nlevel][2] = cnt;

    if (cnt < arr.length) {
        setTimeout(work, 1);
    } else {
        if (queue.length>1) {
            queue.pop();
            setTimeout(work, 1);
        }
    }
}

function each(arr, process) {
    queue.push([arr, process, 0]);

    setTimeout(work, 1);
}


each(['one', 'two', 'three'], function() {
    alert(this);

    each([1, 2, 3, 4], function() {
        alert(this);
    });
});

but It has some major bug and I couldn't fix it.

1
  • 4
    I'm sure there is a solution, but we can't really help much without seeing the actual code you have and a little more of a specific description about what in that code you want to change. Commented Feb 6, 2012 at 23:19

4 Answers 4

3

You can use Web Workers to run multiple scripts in background threads. But they are not supported in every browsers. See this article from Mozilla or simple ask Google: https://developer.mozilla.org/En/Using_web_workers

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

Comments

1

You can use SetTimeout(0,...) periodically to "yield" control to the browser to prevent freezing the browser (but it will not execute any faster, in fact it will probably be slightly slower).

See this answer for an example of the technique, I can't be more specific without seeing your code.

Comments

0

One way you could do this is to create a queue of work items to be processed:

var queue = [];

Place items to be processed in this queue instead of processing right away:

queue.push(item);

Then start a timer loop for processing items:

var delayBetweenItems = 10;
var processItemFromQueue = function() {
    if (queue.length) {
        item = queue.shift();
        doStuff(item);
        setTimeout(delayBetweenItems, processItemFromQueue);
    }
};
setTimeout(processItemFromQueue, delayBetweenItems);

1 Comment

Jacob shouldn't your setTimeout functions have the arguments reversed so that the function is passed first then the delay? It would then read as setTimeout(processItemFromQueue, delayBetweenItems);. Reference MDN setTimeout()
0

Assuming that your current code is something similar to this:

function processWord(word, i, j) {
   // do something with the current word, where
   // (if it's needed) i is the index into the elements
   // and j is the index into the current element's words
}

$("#divId").children().each(function(i) {
    var words = $(this).text().split(" "),
        j;
    for(j = 0; j < words.length; j++) {
       processWord(words[j], i, j);
    }
});

You can rewrite that to do both the outer (i) and inner (j) loops with setTimeout():

// assumes the same processWord() function as above

(function (){
    var $items = $("#divId").children(),
        words,
        i, j,
        iMax, jMax;

    function doIteration() {
       if (j === jMax) {
          if (++i === iMax)
             return;

          // outer loop processing
          words = $($items[i]).text().split(" ");
          jMax = words.length;
          j = 0;
       }
       if (j < jMax) {
          // inner loop processing
          processWord(words[j], i, j);
          j++;
       }

       setTimeout(doIteration, 1);
    }

    iMax = $items.length;
    i = j = jMax = -1;
    doIteration();
})();

Working demo: http://jsfiddle.net/sp8Wr/

The doIteration() function simulates a nested loop by processing some counters appropriately and calling itself via setTimeout() to do the next iteration. The immediately-executed-anonymous-function wrapping the whole thing is not essential to the process, it is there just to restrict the scope of the variables.

Yes this could probably be done much better, but this is just what I came up with on the fly - obviously you'll modify it as appropriate for your own processing.

(If you don't care what order the words get processed in as long as the processWord() function gets the correct values of i and j associated with each word this can easily be made much tidier, but I don't have time to do a neater version that processes in order.)

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.