在Javascript中执行后台任务
我有一个CPU密集型任务,我需要在客户端上运行。 理想情况下,我想能够调用该函数,并使用jquery触发进度事件,以便我可以更新UI。
我知道JavaScript不支持线程,但我已经看到一些有希望的文章,试图模仿使用setTimeout的线程。
什么是最好的方法来使用这个? 谢谢。
我有一个类似的问题,最近要解决的问题,我需要保持我的UI线程免费,同时处理一些数据显示。
我编写了一个Background.js库来处理几个场景:一个顺序的后台队列(基于WorkerQueue库),一个在每个计时器上调用每个计时器的作业列表,以及一个数组迭代器来帮助将工作分解成更小的块。 示例和代码在这里: https : //github.com/kmalakoff/background
请享用!
基本上,你要做的就是把手术分成几块。 所以说你有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也引入了自己的工作人员 (尽pipe他们遵循W3标准 ,而Google Gears使用自己的方法)。
如果您可以强制使用浏览器,或者您已经知道它是Firefox的新版本,则可以使用Mozilla中的新WebWorker 。 它允许你产生新的线程。
根据您的要求,您可以使用Gears轻松下车。 Gears支持线程,可以做你想做的。
正如你所提到的,setTimeout是另一种select。 根据您的任务types,您可以将每个循环的迭代切换到一个单独的setTimeout调用,其间有一定的间距,或者您可能需要将主algorithm的各个部分分离为单独的函数,这些函数可以逐个调用就像你每次迭代所调用的一样。
凯文很好的回答! 我几年前写了类似的东西,虽然不太复杂。 源代码在这里,如果有人想要它:
任何使用run()
方法的东西都可以作为一个任务排队。 任务可以重新排队,以大块方式执行工作。 您可以优先考虑任务,随意添加/删除它们,暂停/恢复整个队列等。与asynchronous操作一起工作良好 – 我最初使用的是pipe理多个并发的XMLHttpRequests。
基本用法很简单:
var taskQueue = new TaskQueue(); taskQueue.schedule("alert('hello there')");
.js文件中的标题注释提供了更高级的示例。
这里是我对这个问题的解决scheme,以防有人想要简单的可复制粘贴的代码:
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(); };
我最强烈的build议是在操作过程中显示一个简单的load.gif。 如果用户“被告知”可能需要一些时间,用户通常会接受一段时间。
Ajaxload – Ajax加载gif生成器
这是如何在JavaScript中创build线程的一个非常基本的例子。 请注意,是由你来中断你的线程函数(yeld指令)。 如果你愿意,你可以使用setTimeout而不是我的while循环来定期运行调度器。 还要注意,这个例子只适用于JavaScript版本1.7+(火狐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)
似乎这个问题已经在节点本身解决了。
需要包含在nodejs 0.10.4中的child_process