Выполнить фоновое задание в Javascript - PullRequest
41 голосов
/ 21 июля 2009

У меня есть задача с интенсивным использованием процессора, которую нужно запустить на клиенте. В идеале я хотел бы иметь возможность вызывать функцию и запускать события прогресса с помощью jquery, чтобы я мог обновить пользовательский интерфейс.

Я знаю, что javascript не поддерживает многопоточность, но я видел несколько многообещающих статей, пытающихся имитировать многопоточность с помощью setTimeout.

Каков наилучший подход для этого? Спасибо.

Ответы [ 9 ]

38 голосов
/ 21 июля 2009

По сути, вы хотите разделить операцию на части. Допустим, у вас есть 10 000 элементов, которые вы хотите обработать, сохранить их в списке, а затем обработать небольшое количество элементов с небольшой задержкой между каждым вызовом. Вот простая структура, которую вы можете использовать:

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

Также обратите внимание, что Google Gears поддерживает работу в отдельном потоке . Firefox 3.5 также представил своих собственных сотрудников, которые делают то же самое (хотя они следуют стандарту W3 , в то время как Google Gears использует свои собственные методы.)

20 голосов
/ 29 августа 2011

Недавно мне пришлось решить аналогичную проблему, когда мне нужно было освободить поток пользовательского интерфейса при обработке некоторых данных для отображения.

Я написал библиотеку Background.js для обработки нескольких сценариев: последовательная фоновая очередь (на основе библиотеки WorkerQueue), список заданий, каждое из которых вызывается для каждого таймера, и итератор массива, помогающий разбить вашу работу на более мелкие куски. Примеры и код здесь: https://github.com/kmalakoff/background

Наслаждайтесь!

8 голосов
/ 21 июля 2009

Если вы можете принудительно использовать браузер или уже знаете, что это новая версия Firefox, вы можете использовать новую WebWorkers от Mozilla. Позволяет создавать новые темы.

4 голосов
/ 21 июля 2009

В зависимости от ваших требований, вы можете легко выйти с помощью Gears. Gears поддерживает потоки, которые могут делать то, что вы хотите.

Как вы упомянули, setTimeout является другой опцией. В зависимости от типа вашей задачи вы можете передать каждую итерацию цикла отдельному вызову setTimeout с некоторым интервалом между ними, или вам может потребоваться разделить части вашего основного алгоритма на отдельные функции, которые можно вызывать по очереди так же, как вы бы назвали каждую итерацию.

2 голосов
/ 21 мая 2014

Вот мое решение проблемы, на случай, если кто-то захочет вставить простой для копирования кусок кода:

    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();
    };
2 голосов
/ 06 ноября 2012

Отличный ответ, Кевин! Я написал нечто подобное несколько лет назад, хотя и менее изощренно. Исходный код здесь, если кто-то хочет:

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

Все, что связано с методом run(), может быть поставлено в очередь как задача. Задачи могут ставить себя в очередь для выполнения работы по частям. Вы можете назначать приоритеты задачам, добавлять / удалять их по своему усмотрению, приостанавливать / возобновлять всю очередь и т. Д. Хорошо работает с асинхронными операциями - я изначально использовал это для управления несколькими одновременными запросами XMLHttp.

Основное использование довольно просто:

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

Комментарии заголовка в файле .js предоставляют более продвинутые примеры.

1 голос
/ 21 июля 2009

Это очень простой пример того, как создавать потоки в JavaScript. Обратите внимание, что вы должны прерывать ваши функции потока (инструкция yeld). Если вы хотите, вы можете использовать setTimeout вместо цикла while для периодического запуска планировщика. Также обратите внимание, что этот пример работает только с JavaScript версии 1.7+ (firefox 3+) Вы можете попробовать это здесь: 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) { }
}

Вывод:

0 (foo) 0 (bar) 1 (foo) 1 (bar) 2 (foo) 2 (bar) 3 (foo) 3 (bar) 4 (foo) 4 (bar) 
1 голос
/ 21 июля 2009

Моя самая сильная рекомендация - отображать простой loading.gif во время операции. Пользователь часто принимает некоторую продолжительность, если ему «сказали», что это может занять некоторое время.

Ajaxload - GIF-генератор загрузки Ajax

0 голосов
/ 16 ноября 2013

Кажется, эта проблема была решена в самом узле.
требуется child_process, который включен в nodejs 0.10.4

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...