Search code examples
javascriptinfinite-loopweb-worker

Javascript long loops without workers


I require a long loop (long enough to make the browser hang if I used it naively). The contents of this loop requires other javascript files/libraries and I dont like the idea of concatonating them all into one file as this would make it harder to maintain. So (as far as I understand) this rules out web workers, Are there any other solutions out there?

I need the contents of the loop to run as fast as possible so any delay that can be measured in ms is unacceptable, any fixed delay at all would not be ideal.

I might be able to concatonate them all into a blob at runtime and then feed that into a web worker, I havn't really looked into this to far b/c it doesn't seem like a good solution.


Solution

  • You will have to use an asynchronous approach for this.

    An example is to use a "dispatcher" function which invokes the work for each count and keep tracks of current count. It will make sure the next call is called asynchronous. When done the given callback is invoked.

    Example

    function startLoop(lFrom, lTo, workFunc, callback) {
    
        var i = lFrom - 1;
    
        (function loop() {
           if (++i <= lTo) {
               setTimeout(function() {
                   workFunc(i, loop);      // start worker for this count
               }, 9);                      // 9ms delay here - tweak as needed
           }
           else callback();                // done
        })();                              // self-invokes loop
    }
    

    Then in the worker function:

    function worker(i, callback) {
        // use i for what is needed, then
        callback();                        // will trigger next count
    }
    

    And of course, you can do batches instead of invoking a worker function for each count.

    For block based approach for more "heavy" data, see also my answer here.

    Simple demo below

    startLoop(0, 20, worker, function() {alert("done")});
    
    function startLoop(lFrom, lTo, workFunc, callback) {
    
            var i = lFrom - 1;
    
            (function loop() {
               if (++i <= lTo) {
                   setTimeout(function() {
                       workFunc(i, loop);      // start worker for this count
                   }, 9);                      // 9ms delay here - tweak as needed
               }
               else callback();                // done
            })();                              // self-invokes loop
        }
    
        function worker(i, callback) {
            // use i for what is needed, then
            document.querySelector("div").innerHTML += (i + "...");
            callback();                        // will trigger next count
        }
    <div></div>