Execute Background Task In Javascript

JavascriptMultithreading

Javascript Problem Overview


I have a cpu intensive task that I need to run on the client. Ideally, I'd like to be able to invoke the function and trigger progress events using jquery so I can update the UI.

I know javascript does not support threading, but I've seen a few promising articles trying to mimic threading using setTimeout.

What is the best approach to use for this? Thanks.

Javascript Solutions


Solution 1 - Javascript

Basically, what you want to do is to divide the operation into pieces. So say you have 10 000 items you want to process, store them in a list and then process a small number of them with a small delay between each call. Here's a simple structure you could use:

function performTask(items, numToProcess, processItem) {
    var pos = 0;
    // This is run once for every numToProcess items.
    function iteration() {
        // Calculate last position.
        var j = Math.min(pos + numToProcess, items.length);
        // Start at current position and loop to last position.
        for (var i = pos; i < j; i++) {
            processItem(items, i);
        }
        // Increment current position.
        pos += numToProcess;
        // Only continue if there are more items to process.
        if (pos < items.length)
            setTimeout(iteration, 10); // Wait 10 ms to let the UI update.
    }
    iteration();
}

performTask(
    // A set of items.
    ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'],
    // Process two items every iteration.
    2,
    // Function that will do stuff to the items. Called once for every item. Gets
    // the array with items and the index of the current item (to prevent copying
    // values around which is unnecessary.)
    function (items, index) {
        // Do stuff with items[index]
        // This could also be inline in iteration for better performance.
    });

Also note that Google Gears has support to do work on a separate thread. Firefox 3.5 also introduced its own workers that do the same thing (although they follow the W3 standard, while Google Gears uses its own methods.)

Solution 2 - Javascript

I had a similar problem to solve recently where i needed to keep my UI thread free while crunching some data to display.

I wrote a library Background.js to handle a few scenarios: a sequential background queue (based on the WorkerQueue library), a list of jobs where each is called on every timer, and an array iterator to help break up your work into smaller chunks. Examples and code here: https://github.com/kmalakoff/background

Enjoy!

Solution 3 - Javascript

If you can enforce the browser to be used, or you otherwise already know it to be a new version of Firefox, you could use the new WebWorkers from Mozilla. It allows you to spawn new threads.

Solution 4 - Javascript

Depending on what your requirements are, you may get off easily by using Gears. Gears supports threads, which could do what you want.

As you mentioned, setTimeout is the other option. Depending on the type of your task, you can hand off each iteration of a loop to a separate setTimeout call with some spacing in between, or you may need to separate pieces of your main algorithm into separate functions which can be called one by one in a same manner as you'd call each iteration.

Solution 5 - Javascript

Great answer Kevin! I wrote something similar a few years back, though less sophisticated. Source code is here if anyone wants it:

http://www.leapbeyond.com/ric/jsUtils/TaskQueue.js

Anything with a run() method can be queued as a task. Tasks can re-queue themselves to perform work in chunks. You can prioritize tasks, add/remove them at will, pause / resume the entire queue, etc. Works well with asynchronous operations - my original use for this was to manage several concurrent XMLHttpRequests.

Basic usage is pretty simple:

var taskQueue = new TaskQueue();
taskQueue.schedule("alert('hello there')");

The header comments in the .js file provide more advanced examples.

Solution 6 - Javascript

Here is my solution to the problem, in case someone wants simple copy-pasteable piece of code:

    var iterate = function (from, to, action, complete) {
        var i = from;
        var impl = function () {
            action(i);
            i++;
            if (i < to) setTimeout(impl, 1);
            else complete();
        };
        impl();
    };

Solution 7 - Javascript

This is a very basic example of how to create threads in JavaScript. Note that is is up to you to interrupt your thread functions (yeld instruction). If you want, you can use a setTimeout instead of my while loop to run the scheduler periodically. Note also that this example only works with JavaScript version 1.7+ (firefox 3+) you can try it here: http://jslibs.googlecode.com/svn/trunk/jseval.html

//// thread definition
function Thread( name ) {

    for ( var i = 0; i < 5; i++ ) {
       
        Print(i+' ('+name+')');
        yield;
    }
}

//// thread management
var threads = [];

// thread creation
threads.push( new Thread('foo') );
threads.push( new Thread('bar') );

// scheduler
while (threads.length) {
   
    var thread = threads.shift();
    try {
        thread.next();
        threads.push(thread);
    } catch(ex if ex instanceof StopIteration) { }
}

The output is:

0 (foo) 0 (bar) 1 (foo) 1 (bar) 2 (foo) 2 (bar) 3 (foo) 3 (bar) 4 (foo) 4 (bar) 
   

Solution 8 - Javascript

My strongest recommendation is to display a simple loading.gif during the operation. User often accepts some duration if they have been "told" that it could take some time.

Ajaxload - Ajax loading gif generator

Solution 9 - Javascript

use requestIdleCallback().

Then you will use the browsers idle time to process your task.

Sample found in: https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API

Solution 10 - Javascript

Seems this problem has been solved in node itself.
require child_process which is included in nodejs 0.10.4

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRobView Question on Stackoverflow
Solution 1 - JavascriptBlixtView Answer on Stackoverflow
Solution 2 - JavascriptKevinView Answer on Stackoverflow
Solution 3 - JavascriptSinan TaifourView Answer on Stackoverflow
Solution 4 - JavascriptJani HartikainenView Answer on Stackoverflow
Solution 5 - JavascriptrkagererView Answer on Stackoverflow
Solution 6 - JavascriptironicView Answer on Stackoverflow
Solution 7 - JavascriptFranck FreiburgerView Answer on Stackoverflow
Solution 8 - JavascriptdbdView Answer on Stackoverflow
Solution 9 - JavascriptFrank34View Answer on Stackoverflow
Solution 10 - JavascriptChris WegenerView Answer on Stackoverflow