Promise 可以对 onFulfilled 有多个参数吗?

Posted

技术标签:

【中文标题】Promise 可以对 onFulfilled 有多个参数吗?【英文标题】:Can promises have multiple arguments to onFulfilled? 【发布时间】:2014-05-11 12:30:00 【问题描述】:

我遵循规范 here,但我不确定它是否允许使用多个参数调用 onFulfilled。例如:

promise = new Promise(function(onFulfilled, onRejected)
    onFulfilled('arg1', 'arg2');
)

这样我的代码:

promise.then(function(arg1, arg2)
    // ....
);

会同时收到arg1arg2

我不关心任何特定的 Promise 实现是如何做到的,我希望严格遵循 w3c 的 Promise 规范。

【问题讨论】:

作为提示,我发现使用github.com/then/promise(这是一个准系统实现)表明它实际上不提供第二个参数 您想将 Bluebird 与 .spread 一起使用。 - 另外,不要再关心规范了,规范都是关于实现之间的 interop 的,并且在设计上是最小的。 【参考方案1】:

我在这里遵循规范,但我不确定它是否允许使用多个参数调用 onFulfilled。

不,只有第一个参数将被视为 promise 构造函数中的分辨率值。您可以使用对象或数组等复合值进行解析。

我不关心任何特定的 Promise 实现是如何做到的,我希望严格遵循 w3c 的 Promise 规范。

这就是我认为你错的地方。该规范被设计为最小化,并且是为 Promise 库之间的互操作而构建的。这个想法是有一个子集,例如 DOM 期货可以可靠地使用并且库可以使用。 Promise 实现暂时可以满足您对.spread 的要求。例如:

Promise.try(function()
    return ["Hello","World","!"];
).spread(function(a,b,c)
    console.log(a,b+c); // "Hello World!";
);

Bluebird。如果您想要此功能,一种解决方案是填充它。

if (!Promise.prototype.spread) 
    Promise.prototype.spread = function (fn) 
        return this.then(function (args) 
            return Promise.all(args); // wait for all
        ).then(function(args)
         //this is always undefined in A+ complaint, but just in case
            return fn.apply(this, args); 
        );
    ;

这可以让你做到:

Promise.resolve(null).then(function()
    return ["Hello","World","!"]; 
).spread(function(a,b,c)
    console.log(a,b+c);    
);

轻松地使用原生承诺fiddle。或者使用现在(2018 年)在浏览器中很常见的传播:

Promise.resolve(["Hello","World","!"]).then(([a,b,c]) => 
  console.log(a,b+c);    
);

或者等待:

let [a, b, c] = await Promise.resolve(['hello', 'world', '!']);

【讨论】:

请注意,其他库(如 Q)也支持 .spread,如 Bluebird - 它不在规范中的原因是保持规范最小化是真的很重要为了允许代码和库之间的互操作。 第二个注意事项 - 在应用函数之前,您可能希望在数组上调用 Promise.all 而不仅仅是 .then 处理一些糖库提供的。这不是强制性的,但它很可爱。 Promies.all 在您的实现中是强制性的,尽管您可以将实现更改为 return Promise.all(args).then(function(args)return fn.apply(this, args);) spread 是权宜之计。 ES6 引入了解构和 rest/spread 运算符,这完全消除了对spread 的需要。 .then(([a, b, c]) => ) @KrisKowal 请注意 .spread() 隐式执行 .all() 但 ES6 解构语法没有 -> bluebirdjs.com/docs/api/spread.html【参考方案2】:

你可以使用 E6 解构:

对象解构:

promise = new Promise(function(onFulfilled, onRejected)
    onFulfilled(arg1: value1, arg2: value2);
)

promise.then((arg1, arg2) => 
    // ....
);

数组解构:

promise = new Promise(function(onFulfilled, onRejected)
    onFulfilled([value1, value2]);
)

promise.then(([arg1, arg2]) => 
    // ....
);

【讨论】:

这个答案很好,很有帮助的例子!【参考方案3】:

promise 的实现值与函数的返回值相似,promise 的拒绝原因与函数抛出的异常相似。函数不能返回多个值,因此 Promise 的履行值不得超过 1 个。

【讨论】:

【参考方案4】:

据我所知,阅读 ES6 Promise specification 和 standard promise specification 没有任何条款阻止实现处理这种情况 - 但是它没有在以下库中实现:

RSVP.promise (#L516-544) Q promise (#787)

我认为他们省略多参数解析的原因是为了使更改顺序更简洁(即,由于您只能在函数中返回一个值,这会使控制流不那么直观)示例:

new Promise(function(resolve, reject) 
   return resolve(5, 4);
)
.then(function(x,y) 
   console.log(y);
   return x; //we can only return 1 value here so the next then will only have 1 argument
)
.then(function(x,y) 
    console.log(y);
);

【讨论】:

Q 不支持多值解析,因为 Promise 充当函数调用结果的代理,但也可以代理远程对象。在这两种情况下,数组是复合值的唯一合理表示。随着在 ES6 中添加解构和“扩展”参数,语法变得非常好。 “传播”方法是权宜之计。 嗯,你总是可以用return Promise.of(x, y) 代替then 回调中的标量值。【参考方案5】:

在 ES6 中解构赋值会有所帮助。例如:

let [arg1, arg2] = new Promise((resolve, reject) => 
    resolve([argument1, argument2]);
);

【讨论】:

【参考方案6】:

这是一个 CoffeeScript 解决方案。

我一直在寻找相同的解决方案,并从这个答案中发现了一些非常有趣的东西:Rejecting promises with multiple arguments (like $http) in AngularJS

这家伙的回答Florian

promise = deferred.promise

promise.success = (fn) ->
  promise.then (data) ->
   fn(data.payload, data.status, additional: 42)
  return promise

promise.error = (fn) ->
  promise.then null, (err) ->
    fn(err)
  return promise

return promise 

并使用它:

service.get().success (arg1, arg2, arg3) ->
    # => arg1 is data.payload, arg2 is data.status, arg3 is the additional object
service.get().error (err) ->
    # => err

【讨论】:

应该->=> 吗? @SherylHohman 早在 2015 年,这是用 CoffeeScript (coffeescript.org/#introduction) 而非 ES6 语法编写的。简单箭头是简单的函数,而粗箭头与 ES6 几乎相同(我猜 ES6 的粗箭头或多或​​少是从 CoffeScript 借来的)。 @SherylHohman 如果需要,请随时在 ECMA 中编辑帖子。 感谢您的回复。我将仅进行编辑以澄清这是一个咖啡脚本解决方案。有了这个,你的答案就可以了,并且可能对 CoffeeScript 代码库有用。但是,感谢您提供编辑的提议:1)我对 CoffeeScript 不够熟悉,无法冒编辑/破坏您的解决方案的风险;-)。 2) 将您的代码翻译成现代 JS 应被视为偏离“您的答案的初衷”,因此不应通过“编辑”审查。相反,如果愿意,有人可以发布一个新的答案,翻译您的代码。理想情况下,他们会链接回您的答案作为他们的灵感:-)【参考方案7】:

本杰明、克里斯等人提出了很好的问题和很好的回答 - 非常感谢!

我在一个项目中使用它并创建了一个基于Benjamin Gruenwald's code 的模块。它在 npmjs 上可用:

npm i -S promise-spread

然后在你的代码中,做

require('promise-spread');

如果您使用的是 any-promise 等库

var Promise = require('any-promise');
require('promise-spread')(Promise);

也许其他人也觉得这很有用!

【讨论】:

【参考方案8】:

由于 javascript 中的函数可以使用任意数量的参数调用,并且除了下面的子句之外,文档对 onFulfilled() 方法的参数没有任何限制,我认为您可以将多个参数传递给 onFulfilled()方法,只要 promise 的值是第一个参数。

2.2.2.1 它必须在promise 完成后调用,promise 的值作为它的第一个参数。

【讨论】:

【参考方案9】:

引用下面的文章,““then”有两个参数,一个用于成功情况的回调,另一个用于失败情况。两者都是可选的,因此您可以只为成功或失败情况添加回调。”

我通常会查看此页面以了解任何基本的承诺问题,如果我错了,请告诉我

http://www.html5rocks.com/en/tutorials/es6/promises/

【讨论】:

错了,new Promise 的语法是 function(resolve, error)then 的语法是 .then(function(arg) @megawac 它实际上是正确的,只是放错了 - 然后接受两个(有时是 3 个)参数 - 这很不常见 @BenjaminGruenbaum afaik 它的.then(function(/*resolve args*/)/*resolve handler*/, function(/*reject args*/)/*reject handler*/) 是的,如果你仔细阅读,这就是这个答案所声称的 - 在这个问题的上下文中不是很有用但不是不正确的。

以上是关于Promise 可以对 onFulfilled 有多个参数吗?的主要内容,如果未能解决你的问题,请参考以下文章

promise 实现

JS promise

ES6 Promise Javascript

js promise实现原理

Promise 的 .then 和 .catch 是如何工作的?

[Es6]原生Promise的使用方法