在 Javascript 中执行后台任务

IT技术 javascript multithreading
2021-02-24 01:43:24

我有一个需要在客户端上运行的 CPU 密集型任务。理想情况下,我希望能够使用 jquery 调用该函数并触发进度事件,以便我可以更新 UI。

我知道 javascript 不支持线程,但我看过一些很有前途的文章,试图使用 setTimeout 来模拟线程。

用于此的最佳方法是什么?谢谢。

6个回答

基本上,您要做的是将操作分成几部分。因此,假设您有 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 使用自己的方法。)

不适用于像树视图这样的现有控件,它不支持分解像更新树这样的任务,这涉及迭代每个节点。
2021-05-04 01:43:24
谢谢。这对我来说非常有效,但我正在处理一系列数据,所以它可能不是每个人的最佳解决方案。
2021-05-14 01:43:24

我最近有一个类似的问题需要解决,我需要在处理一些要显示的数据时保持 UI 线程空闲。

我编写了一个库 Background.js 来处理一些场景:一个顺序后台队列(基于 WorkerQueue 库),一个作业列表,其中每个都在每个计时器上调用,以及一个数组迭代器,以帮助将您的工作分解为更小的块. 示例和代码在这里:https : //github.com/kmalakoff/background

享受!

如果您可以强制使用浏览器,或者您已经知道它是 Firefox 的新版本,则可以使用Mozilla的新WebWorkers它允许您生成新线程。

根据您的要求,您可以使用 Gears 轻松下车。Gears 支持线程,它可以做你想做的事。

正如您所提到的, setTimeout 是另一种选择。根据您的任务类型,您可以将循环的每次迭代交给单独的 setTimeout 调用,中间有一些间距,或者您可能需要将主算法的各个部分分成单独的函数,这些函数可以在与您调用每次迭代的方式相同。

+1,但齿轮“工人”并不完全是其他环境所称的“线程”。
2021-04-17 01:43:24
Firefox 3.5 也有 W3 标准化工人。有关链接,请参阅我的答案。
2021-05-15 01:43:24

很好的答案凯文!几年前我写了一些类似的东西,虽然不那么复杂。如果有人想要,源代码在这里:

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

任何带有run()方法的东西都可以作为任务排队。任务可以重新排队以分块执行工作。您可以对任务进行优先级排序,随意添加/删除它们,暂停/恢复整个队列等。适用于异步操作 - 我最初的用途是管理多个并发 XMLHttpRequest。

基本用法非常简单:

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

.js 文件中的标题注释提供了更高级的示例。