许诺可以对onFulfilled有多个参数吗?


127

我在这里遵循规范并且不确定是否允许使用多个参数调用onFulfilled。例如:

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

这样我的代码:

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

会同时收到arg1arg2

我不在乎任何特定的Promise实现如何实现,我希望严格遵循w3c规范来实现Promise。


作为提示,我发现使用github.com/then/promise(这是一个准系统的实现)表明它实际上没有提供第二个参数
badunk

2
您想将Bluebird与.spread一起使用。-而且,不要再关心规范了,规范只是关于实现之间的互操作,并且在设计上是最小的。
Benjamin Gruenbaum '04

Answers:


130

我在这里遵循规范,不确定是否允许使用多个参数调用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!";
});

蓝鸟。如果您需要此功能,一种解决方案是对其进行填充。

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

带着原生的诺言轻松自在地摆弄。或使用在浏览器中现在很普遍的价差(2018):

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

或等待:

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

2
请注意,其他库(如Q)也支持.spreadBluebird等-不在规范中的原因是,为了使代码与库之间互操作,将规范保持在最低限度确实很大
Benjamin Gruenbaum'4

第二点-您可能想Promise.all在应用函数之前先调用数组,而不是仅使用.then它来处理某些糖库提供的功能。它不是强制性的,但很可爱。
Benjamin Gruenbaum '04

1
Promies.all对于您的实施是强制性的,尽管您可以将实施更改为return Promise.all(args).then(function(args){return fn.apply(this, args);})
Esailija 2014年

14
spread是权宜之计。ES6引入了解构和剩余/扩展运算符,从而消除了spread直接使用的需求。.then(([a, b, c]) => {})
克里斯·科瓦尔

3
@KrisKowal请注意,.spread()隐式地执行.all(),但ES6
分解

66

您可以使用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
一个示例将很好并且对这个答案有帮助
拉胡尔·维尔玛

19

一个诺言的实现值与一个函数的返回值平行,而一个诺言的拒绝原因与一个函数的抛出异常平行。函数不能返回多个值,因此promise的实现值不能超过1。


4

据我所知,阅读ES6 Promise规范标准Promise规范时,没有子句会阻止实现处理这种情况-但是在以下库中未实现:

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

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

8
Q不支持多值解析,因为Promise可以作为函数调用结果的代理,但也可以代理远程对象。在这两种情况下,数组都是复合值的唯一明智的表示形式。通过在ES6中添加解构和“扩展”参数,语法变得非常好。“传播”方法是权宜之计。
克里斯·科瓦尔

好吧,您总是可以return Promise.of(x, y)代替then回调中的标量值。
Bergi 2014年

2

这是CoffeeScript解决方案。

我一直在寻找相同的解决方案,但发现这个问题很令人困惑:在AngularJS中拒绝带有多个参数(例如$ http)的promise

这个家伙弗洛里安的答案

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

1
@SherylHohman早在2015年,它是使用CoffeeScript(coffeescript.org/#introduction)而不是ES6语法编写的。简单箭头是简单的功能,粗箭头与ES6几乎相同(我想ES6粗箭头或多或​​少是从CoffeScript借来的)。
Val Entin

@SherylHohman如果愿意,可以随时在ECMA中编辑该帖子。
Val Entin

感谢您的答复。我将仅编辑以阐明这是一个咖啡脚本解决方案。这样一来,您的答案将保持不变,并且可能对CoffeeScript代码库很有用。感谢您提供的编辑建议,但是:1)我对CoffeeScript不太熟悉,可能冒着编辑/破坏您的解决方案的风险;-)。2)将您的代码转换为现代JS应该被视为偏离“您的答案的原始意图”,因此不应通过“编辑”审查。相反,如果愿意的话,有人可以发布新的答案,以翻译您的代码。理想情况下,他们
会将

0

本杰明·克里斯(Benjamin),克里斯(Kris)等人提出的好问题和好答案-非常感谢!

我在项目中使用了它,并根据Benjamin Gruenwald的代码创建了一个模块。在npmjs上可用:

npm i -S promise-spread

然后在您的代码中,执行

require('promise-spread');

如果您使用的是诸如 any-promise

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

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



0

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

2.2.2.1必须在实现诺言之后调用它,第一个参数是诺言的值。


-1

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

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

http://www.html5rocks.com/zh-CN/tutorials/es6/promises/


1
那是不正确的,new Promise具有语法function(resolve, error)then具有语法.then(function(arg) {
megawac 2014年

2
@megawac实际上是正确的,只是放错了位置-然后接受了两个(有时是3个)参数-这非常不常见
Benjamin Gruenbaum 2014年

@BenjaminGruenbaum afaik其.then(function(/*resolve args*/){/*resolve handler*/}, function(/*reject args*/){/*reject handler*/})
megawac 2014年

2
是的,如果您仔细阅读,这就是这个答案的意思-在该问题的上下文中不是很有用,但并非不正确。
本杰明·格伦鲍姆
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.