Say I have a step in a procedure that requires the retrieval of two objects. I would use join()
to coordinate the retrievals:
return promise.join(retrieveA(), retrieveB())
.spread(function(A, B) {
// create something out of A and B
});
The documentation shows that you can also pass the handler as the last parameter:
return promise.join(retrieveA(), retrieveB(), function(A, B) {
// create something out of A and B
});
I'm curious as to what the rationale behind the existence of this option.
Fact time: The reason .join
was added was to make @spion happy. Not without reason though, using .join
means you have a static and known number of promise which makes using it with TypeScript a lot easier. Petka (Esailija) liked the idea and also the fact it can be optimised further because it doesn't have to abide to weird guarantees the other form does have to abide to.
Over time, people started (at least me) using it for other use cases - namely using promises as proxies.
So, let's talk about what it does better:
It's hard to statically analyse Promise.all
since it works on an array with an unknown types of promises of potentially different types. Promise.join
can be typed since it can be seen as taking a tuple - so for example for the 3 promises case you can give it a type signature of (Promise<S>, Promise<U>, Promise<T>, ((S,U,T) -> Promise<K> | K)) -> Promise<K>
which simply can't be done in a type safe way for Promise.all
.
It's very clean to use when writing promise code in the proxying style:
var user = getUser();
var comments = user.then(getComments);
var related = Promise.join(user, comments, getRelated);
Promise.join(user, comments, related, (user, comments, related) => {
// use all 3 here
});
Since it doesn't need to produce the value of the given promises cached and to keep all the checks .all(...).spread(...)
does - it'll perform slightly faster.
But... you really usually shouldn't care.