为什么 promise.join() 将一个函数作为它的最后一个参数?

Why does promise.join() take a function as its last parameter?

假设我在需要检索两个对象的过程中有一个步骤。我会使用 join() 来协调检索:

return promise.join(retrieveA(), retrieveB())
           .spread(function(A, B) {
               // create something out of A and B
           });

文档显示您还可以将处理程序作为最后一个参数传递:

return promise.join(retrieveA(), retrieveB(), function(A, B) {
           // create something out of A and B
       });

我很好奇这个选项存在的理由是什么。

you can also pass the handler as the last parameter. I'm curious as to what the rationale behind the existence of this option.

这不是 "option"。这是 join 函数的唯一目的。

Promise.join(promiseA, promiseB, …, function(a, b, …) { … })

完全等同于

Promise.all([promiseA, promiseB, …]).spread(function(a, b, …) { … })

但是,正如documentation中提到的,它

is much easier (and more performant) to use when you have a fixed amount of discrete promises

它使您无需使用该数组文字,并且不需要为数组结果创建中间承诺对象。

实际时间:添加.join的原因是让@spion开心。并非没有理由,使用 .join 意味着你有一个 static 和已知的 数量的承诺,这使得它与 TypeScript 一起使用变得更加容易。 Petka (Esailija) 喜欢这个想法,也喜欢它可以进一步优化的事实,因为它不必遵守其他形式必须遵守的奇怪保证。

随着时间的推移,人们(至少我)开始将它用于其他用例 - 即使用 promises 作为代理。

那么,让我们谈谈它在哪些方面做得更好:

静态分析

很难静态分析 Promise.all 因为它在一个数组上工作,该数组具有可能不同类型的未知类型的承诺。 Promise.join 可以被键入,因为它可以被看作是一个元组——所以例如对于 3 个承诺的情况,你可以给它一个 (Promise<S>, Promise<U>, Promise<T>, ((S,U,T) -> Promise<K> | K)) -> Promise<K> 的类型签名,这在类型安全的情况下根本无法完成Promise.all 的方式。

代理

在代理风格中编写 promise 代码时使用起来非常干净:

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

速度更快

因为它不需要产生缓存的给定承诺的值并保留所有检查 .all(...).spread(...) 做 - 它会执行得稍微快一些。

但是……你通常不应该在意。