Могат ли обещанията да имат множество аргументи за onFulfilled?

Следвам спецификацията тук и не съм сигурен дали позволява onFulfilled да бъде извикан с множество аргументи . Например:

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

така че моят код:

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

ще получи и arg1 и arg2?

Не ме интересува как го прави някаква конкретна реализация на обещания, искам да следвам отблизо спецификацията на w3c за обещания.


person badunk    schedule 31.03.2014    source източник
comment
Като подсказка открих, че използването на github.com/then/promise (което е barebones реализация) показва, че всъщност не предоставя втория аргумент   -  person badunk    schedule 01.04.2014
comment
Искате да използвате Bluebird с .spread. - също, спрете да се интересувате от спецификацията, спецификацията е изцяло за взаимодействието между реализациите и е минимална по дизайн.   -  person Benjamin Gruenbaum    schedule 01.04.2014


Отговори (9)


Следвам спецификацията тук и не съм сигурен дали позволява onFulfilled да бъде извикан с множество аргументи.

Не, само първият параметър ще се третира като стойност на резолюцията в конструктора на обещанието. Можете да разрешите със съставна стойност като обект или масив.

Не ме интересува как го прави някаква конкретна реализация на обещания, искам да следвам отблизо спецификацията на w3c за обещания.

Тук вярвам, че грешите. Спецификацията е разработена да бъде минимална и е създадена за взаимодействие между библиотеки за обещания. Идеята е да има подмножество, което фючърсите на 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);    
});

С естествени обещания на спокойствие цигулка. Или използвайте разпространение, което сега (2018 г.) е обичайно в браузърите:

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

Или с чакане:

let [a, b, c] = await Promise.resolve(['hello', 'world', '!']);
person Benjamin Gruenbaum    schedule 01.04.2014
comment
Обърнете внимание, че други библиотеки (като Q) също поддържат .spread като Bluebird - причината да не е в спецификацията е, че поддържането на спецификацията минимална е наистина голяма работа, за да се позволи взаимодействие между код и библиотеки. - person Benjamin Gruenbaum; 01.04.2014
comment
Втора забележка - може да искате да извикате Promise.all на масива, преди да приложите функцията, вместо просто да я .thening за обработка на някои захарни библиотеки, предоставени. Не е задължително, но е сладко. - person Benjamin Gruenbaum; 01.04.2014
comment
Promies.all е задължителен с вашето внедряване, въпреки че можете просто да промените изпълнението на return Promise.all(args).then(function(args){return fn.apply(this, args);}) - person Esailija; 01.04.2014
comment
Да, това трябваше да каже вторият коментар :) За да имитира това, което правят библиотеките. - person Benjamin Gruenbaum; 01.04.2014
comment
spread е временно прекъсване. ES6 въвежда деструктуриране и оператора rest/spread, което премахва необходимостта от spread направо. .then(([a, b, c]) => {}) - person Kris Kowal; 02.04.2014
comment
Мисля, че предполагате, че консумирам обещания и следователно решението е, че мога да използвам библиотека с обещания, за да поправя проблема си. Опитвам се да създам библиотека, за да определя дали мога да разреша (arg1, arg2) и дали потребителите на библиотеката могат да получават и двата аргумента като част от спецификацията. - person badunk; 03.04.2014
comment
@KrisKowal Имайте предвид, че .spread() имплицитно прави .all(), но синтаксисът за деструктуриране на ES6 не го прави -› bluebirdjs.com/docs/api/spread.html - person Gomino; 06.12.2016
comment
@BenjaminGruenbaum Не е същото да се използва: Promise.all(["Hello","World","!"]).then(([a,b,c]) => { console.log(a,b+c); }); ??? - person robe007; 17.09.2018
comment
@BenjaminGruenbaum Друг момент: Ако го направя: Promise.resolve([anAsyncFunction(),"World","!"]).then(([a,b,c]) => { console.log(a,b+c); }); това връща: Promise { <pending> } 'World !' - person robe007; 18.09.2018

Можете да използвате 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]) => {
    // ....
});
person Wookiem    schedule 29.12.2016
comment
Един пример би бил хубав и полезен с този отговор! - person vrintle; 12.11.2018

Стойността на изпълнение на обещание е паралелно на върнатата стойност на функция, а причината за отхвърляне на обещание е паралелно на хвърленото изключение на функция. Функциите не могат да връщат множество стойности, така че обещанията не трябва да имат повече от 1 стойност за изпълнение.

person Esailija    schedule 01.04.2014

Доколкото мога да преценя, четейки спецификацията на ES6 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);
});
person megawac    schedule 01.04.2014
comment
Q не поддържа многостойностни разделителни способности, тъй като обещанията служат като прокси за резултата от извикване на функция, но могат също да прокси за отдалечени обекти. И в двата случая масивът е единственото разумно представяне на съставна стойност. С добавянето на аргументи за деструктуриране и „разпръскване“ в ES6, синтаксисът става наистина хубав. Методът на „разпространение“ е междинен. - person Kris Kowal; 02.04.2014
comment
Е, винаги можете да return Promise.of(x, y) вместо скаларна стойност от обратното извикване then. - person Bergi; 26.07.2014

Деструктурирането на присвояването в ES6 би помогнало тук. Например:

let [arg1, arg2] = new Promise((resolve, reject) => {
    resolve([argument1, argument2]);
});
person Ravi Teja    schedule 10.04.2020

Ето решение на CoffeeScript.

Търсих същото решение и намерих нещо много интересно от този отговор: https://stackoverflow.com/questions/17686612/rejecting-promises-with-multiple-arguments-like-http-in-angularjs

отговорът на този човек Флориан

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
person Val Entin    schedule 08.07.2015
comment
Трябва ли -> да бъде =>? - person SherylHohman; 03.05.2020
comment
@SherylHohman Преди дни през 2015 г. това беше написано с CoffeeScript (coffeescript.org/#introduction), а не ES6 синтаксис. Простата стрелка беше прости функции, а дебелите стрелки са почти същите като ES6 (предполагам, че дебелите стрелки ES6 са повече или по-малко заимствани от CoffeScript). - person Val Entin; 06.05.2020
comment
@SherylHohman Чувствайте се свободни да редактирате публикацията в ECMA, ако искате. - person Val Entin; 06.05.2020
comment
Благодаря ви за отговора. Ще редактирам само за да поясня, че това е решение за скрипт за кафе. С това отговорът ви остава такъв, какъвто е и може да бъде полезен за кодовите бази на CoffeeScript. Благодаря за предложението ви за редактиране обаче: 1) Не съм достатъчно запознат с CoffeeScript, за да рискувам да редактирам/счупя вашето решение ;-). 2) Превеждането на вашия код в модерен JS трябва да се счита за отклонение от първоначалното намерение на вашия отговор, поради което не трябва да преминава преглед за „редактиране“. По-скоро някой може да публикува нов отговор, ако е склонен, превеждайки вашия код. В идеалния случай те биха се свързали обратно към вашия отговор като свое вдъхновение :-) - person SherylHohman; 06.05.2020

Страхотен въпрос и страхотен отговор от Benjamin, Kris и други - много благодаря!

Използвам това в проект и създадох модул, базиран на кода на Benjamin Gruenwald. Предлага се на npmjs:

npm i -S promise-spread

След това във вашия код направете

require('promise-spread');

Ако използвате библиотека като any-promise

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

Може би и други намират това за полезно!

person AndreasPizsa    schedule 04.02.2016

Тъй като функциите в Javascript могат да бъдат извикани с произволен брой аргументи и документът не поставя никакво ограничение върху аргументите на метода onFulfilled() освен клаузата по-долу, мисля, че можете да подадете множество аргументи към метода onFulfilled(), стига стойността на обещанието да е е първият аргумент.

2.2.2.1 трябва да се извика, след като обещанието е изпълнено, със стойността на обещанието като първи аргумент.

person Jazzepi    schedule 31.03.2014

За да цитирам статията по-долу, „„след това“ приема два аргумента, обратно извикване за случай на успех и друг за случай на неуспех. И двата са незадължителни, така че можете да добавите обратно извикване само за случая на успех или неуспех.“

Обикновено разглеждам тази страница за всякакви основни въпроси относно обещанието, уведомете ме, ако греша

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

person Michael Voznesensky    schedule 31.03.2014
comment
Това е неправилно, new Promise има синтаксис function(resolve, error), докато then има синтаксис .then(function(arg) { - person megawac; 01.04.2014
comment
@megawac всъщност е правилен, просто е казано зле - след това приема два (понякога 3) аргумента - просто е доста необичайно - person Benjamin Gruenbaum; 01.04.2014
comment
@BenjaminGruenbaum afaik това е .then(function(/*resolve args*/){/*resolve handler*/}, function(/*reject args*/){/*reject handler*/}) - person megawac; 01.04.2014
comment
Да, ако четете внимателно, това е, което този отговор твърди - не е много полезно в контекста на този въпрос, но не е неправилно. - person Benjamin Gruenbaum; 01.04.2014