在JavaScript中并行执行函数

3

我听说JavaScript是单线程的,对吗?那么如何实现并行执行(同时)多个函数呢?

我有以下脚本,并且我想告诉你每个XML文件大小为4.6MB。

myfunction('sample1.xml');
myfunction('sample2.xml');
myfunction('sample3.xml');
    .
    .
myfunction('sample15.xml');

function myfunction(name) {

    $.ajax({
        type: "GET",
        url: name,
        dataType: "xml",
        success: parseXml
    });

    function parseXml(xml) {

        //searching the xml file 


    }

}

我的目标是加速搜索xml文件的过程,为此,我认为并行执行很好。那么,在JavaScript函数中是否可以进行并行执行?或者有什么方法可以加快我的函数执行速度。


2
JavaScript不是同时进行的(并行)。请求是一个接一个地发送的,但浏览器可以同时处理多个HTTP请求。当浏览器处理请求并等待响应时,JavaScript处于非活动状态。当每个响应返回时,JavaScript回调被调用。 - cookie monster
你可以将多线程任务委托给服务器端脚本(例如C#),这样做的好处是可以提高效率。 - ale
1
你可以将这些函数委托给Web Worker(http://www.html5rocks.com/en/tutorials/workers/basics/),这是目前在JavaScript中创建多个处理上下文的唯一方法。在使用JavaScript时不必担心线程,它使用事件流循环,并且如何执行取决于实现方式,您不应该担心JavaScript中的线程,因为您无法控制它的执行方式。您唯一可以用来提高性能的工具就是代码本身,以及您使用的算法。 - user3417400
2
@cookiemonster - 我会把“JavaScript is simply inactive”改为“JavaScript是空闲的,可以在等待响应时做其他事情”。 - Igor
@Igor:你说得对,这样更好。这使得JS没有任何暂停变得清晰明了。 - cookie monster
1个回答

4
你可以触发任意数量的ajax请求,它们将默认异步执行并行。问题在于,当ajax请求准备就绪时,你的浏览器会执行parseXML,因此你可能仍然会冻结你的浏览器。
你可以使用Mark Gabriel的响应来推迟parseXML的执行。
setTimeout(function(){ parseXML(xml) }, 0)

这样的做法可以防止浏览器冻结,但最终会顺序执行parseXML。

根据您在parseXML中要做的具体操作,使用WebWorkers以并行浏览器进程执行XML解析可能更好。这样,您将打开一个后台进程来执行特定的任务。您创建工作者并将文件名作为消息发送,然后等待工作者返回您从parseXML中期望的任何内容。

var worker = new Worker('/js/parseXML.js');
worker.addEventListener('message', function (e) {
        console.log('Webworker answer is',e);
    }, false);

worker.postMessage('sample1.xml'); // Send data to our worker.

parseXML.js的内容如下:

importScripts("/js/jquery.js");

self.addEventListener('message', function (e) {
    console.log('Webworker received', e.data);
    $.ajax({
        type: "GET",
        url: e.data,
        dataType: "xml",
        success: parseXml
    });

    function parseXml(xml) {
        //searching the xml file 
        self.postMessage(parsedXML);
    };
}, false);

请记住,如果您计划将字符串、数组或哈希作为parseXML的返回值,则此逻辑才有意义。在Web Worker内部无法操作主脚本的全局对象,也不能返回复杂对象。

你使用 worker 的解决方案是正确的,但由于 JavaScript 是单线程的,请求不会并行发送。启动大量的 AJAX 请求将会按顺序逐个处理,无论你是否使用超时。 - thomaux
这要看情况。用一个WebWorker (m*1) 解析 m 个请求与用 m 个WebWorker 分别解析每个请求 (1*m) 是不同的。在这种情况下,我会创建 n 个WebWorker,并让每个WebWorker解析 m/n 个请求 (n*m/n)。我已经为 (1*m) 的情况制作了一个POC,链接如下:http://bl.ocks.org/amenadiel/4d4c3cba4c47f8a44ba0 - ffflabs
我指的是你的开场白:“您可以触发任意数量的Ajax请求,它们将并行执行,因为它们默认是异步的。” 但从JS的角度来看,它们不会并行执行。 - thomaux
哦,关于这个,触发是立即的。但解决方案是排队的。 - ffflabs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接