promiseはonFulfilledに複数の引数を持つことができますか?


127

ここでは仕様に従っていますが、複数の引数を指定してonFulfilledを呼び出すことができるかどうかはわかりません。例えば:

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

そのような私のコード:

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

両方arg1を受け取りarg2ますか?

特定のpromise実装がそれをどのように実行するかは気にしません。promiseのw3c仕様に厳密に従っていきたいと思います。


ヒントとして、私はgithub.com/then/promise(これはベアボーンの実装です)を使用すると、実際には2番目の引数を提供しないことが
わかりました

2
.spreadでBluebirdを使用したい。-また、仕様について気にする必要はありません。仕様は実装間の相互運用に関するものであり、設計上は最小限です。
Benjamin Gruenbaum 2014

回答:


130

ここでは仕様に従っていますが、複数の引数を指定してonFulfilledを呼び出すことができるかどうかはわかりません。

いいえ、最初のパラメータだけがpromiseコンストラクタで解決値として扱われます。オブジェクトや配列などの複合値で解決できます。

特定のpromise実装がそれをどのように実行するかは気にしません。promiseのw3c仕様に厳密に従っていきたいと思います。

それはあなたが間違っていると私が信じるところです。仕様は最小限になるように設計されており、promiseライブラリ間の相互運用のために構築されています。たとえば、DOMフューチャーが確実に使用でき、ライブラリが消費できるサブセットを用意することです。Promiseの実装は.spread、しばらくの間、あなたが求めることを実行します。例えば:

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

ブルーバードと一緒に。この機能が必要な場合の解決策の1つは、ポリフィルすることです。

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 2014

2番目の注意- Promise.all関数を適用する前に配列を呼び出して、.thenいくつかの糖ライブラリーを処理するためだけに関数を呼び出すのではなく、必須ではありませんが、かわいいです。
Benjamin Gruenbaum 2014

1
Promies.allは実装に必須ですが、実装を次のように変更することもできますreturn Promise.all(args).then(function(args){return fn.apply(this, args);})
Esailija

14
spread一時的なギャップです。ES6は、デストラクチャとレスト/スプレッドオペレーターを導入し、spread完全な必要性を排除します。.then(([a, b, c]) => {})
クリス・コワール2014

3
@KrisKowal .spread()は暗黙的に.all()を実行しますが、ES6分解構文は実行しません-> bluebirdjs.com/docs/api/spread.html
Gomino

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
例はこの答えでいいと役に立ちます
Rahul Verma

19

promiseの履行値は関数の戻り値に対応し、promiseの拒否理由は関数のスローされた例外に対応します。関数は複数の値を返すことができないため、promiseは複数のフルフィルメント値を持つことはできません。


4

ES6のPromise仕様標準のPromise仕様を読んでいる限り、実装がこのケースを処理するのを妨げる句はありませんが、次のライブラリには実装されていません。

私がそれらが複数の引数解決を省略した理由は、順序の変更をより簡潔にするためです(つまり、関数では1つの値しか返せないため、制御フローが直感的になりません)例:

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に構造化引数と「スプレッド」引数が追加されたため、構文は非常に良くなります。「スプレッド」方法は一時的なギャップです。
クリス・コワール2014

まあ、コールバックreturn Promise.of(x, y)からのスカラー値の代わりにいつでもできthenます。
Bergi 14

2

これがCoffeeScriptソリューションです。

私は同じ解決策を探していましたが、この答えから非常に興味深いものが見つかりました:AngularJSで複数の引数($ httpなど)を使用してプロミスを拒否する

この男の答えフロリアン

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年の昔、これはES6構文ではなく、CoffeeScript(coffeescript.org/#introduction)で記述されていました。単純な矢印は単純な関数であり、太い矢印はES6とほとんど同じです(ES6の太い矢印は、多かれ少なかれCoffeScriptから借りられていると思います)。
Val Entin

@SherylHohman必要に応じて、ECMAで自由に投稿を編集してください。
Val Entin

御返答いただき有難うございます。これはコーヒースクリプトソリューションであることを明確にするためにのみ編集します。それで、あなたの答えは現状のままであり、CoffeeScriptコードベースに役立つかもしれません。ただし、編集の申し出をありがとうございました。1)CoffeeScriptに精通していないため、ソリューションを編集/破壊するリスクがあります;-)。2)コードを最新のJSに変換することは、「元の回答の意図」からの逸脱と見なす必要があるため、「編集」レビューに合格しないでください。むしろ、誰かが新しい回答を投稿する可能性があります。理想的には、彼らは彼らのインスピレーションとしてあなたの答えにリンクします:-)
SherylHohman

0

Benjamin、Krisなどによる素晴らしい質問と素晴らしい回答-どうもありがとう!

私はこれをプロジェクトで使用しており、ベンジャミン・グルーエンヴァルトのコードに基づいたモジュールを作成しました。npmjsで利用できます。

npm i -S promise-spread

次に、コードで、

require('promise-spread');

次のようなライブラリを使用している場合 any-promise

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

他の人もこれが便利だと思うかもしれません!


0

ES6で割り当てを分解すると、ここで役立ちます。例:

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

0

JavaScriptの関数は任意の数の引数で呼び出すことができ、ドキュメントではonFulfilled()以下の句以外のメソッドの引数に制限を設けていないonFulfilled()ため、promiseの値が次の条件を満たす限り、メソッドに複数の引数を渡すことができると思います。最初の引数。

2.2.2.1 promiseの値を最初の引数として、promiseが満たされた後に呼び出す必要があります。


-1

以下の記事を引用すると、「 "then"は2つの引数を受け取ります。1つは成功の場合のコールバック、もう1つは失敗の場合のコールバックです。どちらもオプションなので、成功または失敗の場合にのみコールバックを追加できます。」

私は通常、このページで基本的な約束の質問を探します。間違っている場合はお知らせください

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


1
ザッツ間違っては、new Promise構文を持っていfunction(resolve, error)ながら、then構文を持っている.then(function(arg) {
megawac

2
@megawacそれは実際には正しいですが、ひどく入れられます-そして、2つの(場合によっては3つの)引数を受け入れます-それはあまり一般的ではありません
Benjamin Gruenbaum

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

2
はい、注意深く読んだ場合、それがこの答えが主張していることです-この質問のコンテキストではあまり役に立ちませんが、間違っていません。
Benjamin Gruenbaum 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.