关于Web worker中同步请求的意见

时间:2012-12-28 10:24:56

标签: javascript ajax xmlhttprequest web-worker

我想知道你对此有何看法。建议在Web worker中使用同步请求(XMLHttpRequest)?我能找到什么问题?

我一直在我的应用中测试这个,我没有发现任何问题。但是由于jQuery和AJAX的旧体验,我害怕这种同步行为。 我的应用程序从数据库中的几个表中获取大量数据,这需要一些时间。对于从表中检索到的每一组数据,我需要立即处理它,以免过多地延迟整个过程。同时,用户正在与浏览器进行交互,因此可以阻止它,我认为网络工作者可以正常工作。 你认为这是一个很好的解决方案吗?或者我应该尝试使用asynchronus请求吗?

谢谢。

2 个答案:

答案 0 :(得分:18)

我没有确凿的事实,但是因为你要求提出意见...... :)

Chrome中存在一个明显的问题:太多的Web Workers可能导致无声崩溃(根据this bug report,大约60-100封)。一般的问题是Web Workers是资源密集型的,至少对于v8。

假设您最终要进行多个HTTP调用,如果您正在Web Worker中进行同步HTTP调用:

  • 从某种意义上说,您正在为异步Web Workers交换异步HTTP调用,这只会在混合中添加另一个中介,您仍然需要异步管理事物。
  • 如果您使用更简单,资源效率更高的路线并且只使用一个Web Worker,您将花费大量时间等待它给您回复。
  • 另一方面,如果您使用多个Web Workers,您可能需要跟踪哪一个是免费的,哪一个是忙的等等,在这种情况下,您将创建一个本地调度程序,而不是使用浏览器中的内容。
  • 最后,Web Workers很昂贵(显然),你最终可能会创建多个Web Workers,这样他们就可以坐下来等待HTTP调用完成。

我不认为自己是这方面的专家,所以请把它当作它的价值。

更新:为各种方案添加一些优点/缺点。

在使用Web Worker时,在选择进行同步和异步HTTP调用时会想到一些优点/缺点:

  • 通常,同步请求将更容易编写,并将导致易于遵循的代码。同步请求的缺点是它们可能会鼓励编写应该分成单独的小函数的长函数。
  • 如果您正在进行一次调用,那么两种方法之间完成所需的时间没有区别,而同步更好,因为它更简单一些。我说它只是有点简单,因为一个回调监听器的单个异步调用非常简单。
  • 如果您正在进行必须按特定顺序进行的多次调用,例如加载用户的个人资料数据,然后根据他们的地址获取本地天气,则同步调用会更好,因为它更容易编写和更容易阅读。阅读它的主要内容是调用中的顺序依赖性将通过选择同步调用及其在函数中的顺序来清楚地概述。呼叫越多,这就越重要。如果有很多电话,复杂性的差异可能会很大。
  • 如果必须进行多次不需要以任何特定顺序发生的调用,则异步请求更好,因为整个过程可能比同步请求快几个数量级。您拨打的电话越多或连接速度越慢,总耗用时间的差异就越大;这种差异会迅速增长(指数?)。从有人阅读代码的角度来看,我认为在这种情况下使用同步请求会有点误导,因为它表明即使没有,也会有一些顺序性质的呼叫。从编写一系列不依赖于彼此的异步请求的角度来看,它应该不会太糟糕,因为你只需设置一个计数器,进行所有调用,在每个回调中递增计数器,然后你就完成了当计数器等于您拨打的电话数时。

更新:@rbrundritt在这个答案中提出了一个非常有趣且相关的observation in a comment

  

我发现与网络工作者合作的一件事是他们看起来每个人都获得了自己的http限制。浏览器将并发http请求的数量限制在8或12左右,具体取决于限制前的浏览器,如果您有大量处理请求,这可能会成为瓶颈。我发现,如果我通过我的请求Web工作者,每个人可以在开始限制之前执行8到12个并发请求。对于某些应用来说,这可能是一个巨大的好处。

     

@rbrundritt

答案 1 :(得分:0)

我只是想添加一条注释(对于评论来说太长了),@ tiffon的答案中提到的〜60个网络工作者的限制似乎在Chromium中不再存在。我可以像这样在Chrome中创建500个工作程序,而不会出现错误/崩溃:

let workers = [];
for(let i = 0; i < 500; i++) {
  let worker = new Worker(URL.createObjectURL(new Blob([`console.log('cool${i}')`])));
  worker.postMessage({});
  workers.push(worker);
}
await new Promise(r => setTimeout(r, 15000));
for(let i = 0; i < workers.length; i++) {
  workers[i].terminate();
}

尽管如此,鉴于核心人数目前不超过64位,很难想象会有数百名工人适合这种情况。