promise.all有用,因为javascript是在一个线程中执行的吗?

时间:2014-04-03 17:09:40

标签: javascript promise q

例如,在kriskowal的Q中,人们可以做类似的事情:

promise1.then(function(p1){
  var p2 = makePromise2();
  var p3 = makePromise3();
  var p4 = makePromise4();
  return [p2, p3, p4];
})
.all(promises, function(){
  console.log('all promises fulfilled');
}, function(reason){
  console.log('a promise was rejected: ' + reason.toString());
});

鉴于javascript在单个线程中执行,这是否有任何好处,性能或其他方面,而不仅仅是执行一系列then()调用?

2 个答案:

答案 0 :(得分:17)

首先,JavaScript作为一种语言并没有提及并发性。实际上,在很多场景中,您可以创建和运行多线程JavaScript - Web中的WebWorkers,节点中以及自己在现有应用程序中集成JS引擎时。

事实上,JavaScript语言中没有任何异步(直到ES2015)。但是,实际上 - JavaScript与世界交互的主机环境实现了异步API。

虽然JavaScript DOM代码的执行是单线程的,但I / O操作实际上在不同的线程上运行,事件通知JavaScript线程的更改。有时,使用操作系统工具进行异步并发,就像Windows中的IOCP(I / O完成端口)一样。

我们以AJAX为例。假设我有一个URL列表,我将每个URL映射到XHR调用。

// with all
var a = ["url1","url2","url3"].map(makeAjaxPromise); // make 3 ajax calls
Promise.all(a).spread(function(res1,res2,res3){ // Q.all with Q
     alert("Everything loaded!");
});

这里,立即进行3次ajax调用。即使JavaScript在这种情况下在单个线程中运行 - 请求都是并行完成的,并且一旦完成使用“事件循环”就会通知线程,该事件循环在事件完成时通知代码,这反过来解决了承诺。

然而,当你这样做时

 makeAjaxPromise("url1").
 then(makeAjaxPromise.bind(null,"url2").
 then(makeAjaxPromise.bind(null,"url3").then(function(){
      alert("Everything loaded!"); // disregarding getting the data here
 });

它会发出一个请求,等待它完成,再制作另一个请求,等待它,然后再制作第三个请求,然后才解决。

所以 - 第一种情况:

  • JavaScript线程进行3次DOM API调用
  • DOM API获取这些调用并发出XHR请求,它立即将控制权交还给JavaScript
  • 当这些请求准备就绪时,它会通知JavaScript,如果可以自由运行,它会运行处理程序。

第二个案例

  • JavaScript线程进行DOM API调用。
  • DOM API获取调用,发出XHR请求,将控制权交还给JavaScript。
  • 当第一个请求准备就绪时,JavaScript会收到通知,并在下一行中运行: -JavaScript线程进行DOM API调用。
  • DOM API获取调用,发出XHR请求,将控制权交还给JavaScript。
  • 当第二个请求准备就绪时,JavaScript会收到通知并在下一行中运行: -JavaScript线程进行DOM API调用。
  • DOM API获取调用,发出XHR请求,将控制权交还给JavaScript。
  • 当第三次请求准备就绪时,JavaScript会收到通知并在下一行中运行:
  • 三人都准备好了。

所以在第二种情况下,请求不是并行进行的,JavaScript必须等待更多,可能是等待的三倍。

答案 1 :(得分:3)

关于一点的更多信息:

JavaScript通常在多线程环境中执行。

在客户端

除了工作者之外,每个iframe,窗口选项卡或打开的窗口都有自己的线程,它们都与窗口消息传递API进行通信,或者如果没有交叉源限制,您可以从中直接访问它们的文档属性。

一些DOM / HTML5 API提出了同步API,W3C的一些人正在努力使这些同步版本只能从Web Workers中使用,可能只有Dedicated Workers。

在服务器端

如果node.js默认在单个线程中运行JavaScript,它仍然可以生成具有自己的线程的其他节点进程并与它们通信。它实际上还提供了一些API的同步版本。

大多数其他服务器JS平台,如Wakanda,RingoJS,TeaJS,APE,SilkJS等都是多线程的,可以与同步API同步运行JavaScript(Wakanda还允许使用同步API或异步特定的API轻松使用异步API线程)