Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is promise.all useful given that javascript is executed in a single thread?

In, for example, kriskowal's Q, one can do something like:

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());
});

Given that javascript executes in a single thread, does this have any benefit, performance or otherwise, over simply doing a series of then() calls?

like image 672
bblack Avatar asked Apr 03 '14 17:04

bblack


1 Answers

First of all - JavaScript as a language does not say anything about concurrency. In fact, in a lot of scenarios you can create and run multithreaded JavaScript - WebWorkers in the web, in node, and when integrating a JS engine in an existing app yourself.

In fact, there is nothing asynchronous in the JavaScript language (Until ES2015). However, in practice - host environments which are how JavaScript interacts with the world implement asynchronous APIs.

While execution of JavaScript DOM code is single threaded, I/O operations actually run on a different thread and events notify the JavaScript thread of changes. Sometimes, using an operating system facility for asynchronous concurrency completely like IOCP (I/O completion ports) in Windows.

Let's take AJAX for example. Let's say I have a list of URLs and I map each of them to an XHR call.

// 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!");
});

Here, 3 ajax calls are made at once. Even though JavaScript runs in a single thread in this case - the requests are all made in parallel, and the thread gets notified once they are complete using an "event loop" that notifies code when events completed which in turn resolves the promises.

However, when you do

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

It'll make a single request, wait for it to complete, make another one, wait for it, make a third one only then and only then resolve.

So - first case:

  • JavaScript thread makes 3 DOM API calls
  • DOM API gets these calls and makes XHR requests, it yields control back to JavaScript immediately
  • When those requests are ready, it notifies JavaScript and it runs the handler if it is free to do so.

Second case

  • JavaScript thread makes a DOM API call.
  • DOM API gets call, makes an XHR request, yields control back to JavaScript.
  • When the first request is ready, JavaScript gets notified and it runs the next in line: -JavaScript thread makes a DOM API call.
  • DOM API gets call, makes an XHR request, yields control back to JavaScript.
  • When the second request is ready, JavaScript gets notified and it runs the next in line: -JavaScript thread makes a DOM API call.
  • DOM API gets call, makes an XHR request, yields control back to JavaScript.
  • When the thirdrequest is ready, JavaScript gets notified and it runs the next in line:
  • All three ready.

So in the second case, the requests are not made in parallel and JavaScript has to wait a lot more, possibly three times as much.

like image 61
Benjamin Gruenbaum Avatar answered Oct 21 '22 19:10

Benjamin Gruenbaum