Чи можуть обіцянки мати декілька аргументів на виконання?


127

Я слідую за специфікацією тут і не впевнений, чи дозволяє він виклик onFulf ispun з кількома аргументами. Наприклад:

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

такий, що мій код:

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

отримали б arg1і arg2?

Мене не цікавить, як це виконує будь-яка конкретна обіцянка, я хочу уважно стежити за специфікацією w3c за обіцянками.


Як підказку, я виявив, що використання github.com/then/promise (що є реалізованою базою ) показує, що він фактично не надає 2-го аргументу
badunk

2
Ви хочете використовувати Bluebird з .spread. - також перестаньте дбати про специфікацію, специфікація - це взаємодія між реалізаціями і мінімальна за дизайном.
Бенджамін Грюнбаум

Відповіді:


130

Я слідую за специфікацією тут і не впевнений, чи дозволяє він виклик onFulf ispun з кількома аргументами.

Ні, просто перший параметр буде розглянуто як значення роздільної здатності в конструкторі обіцянок. Ви можете вирішити складене значення, наприклад об'єкт або масив.

Мене не цікавить, як це виконує будь-яка конкретна обіцянка, я хочу уважно стежити за специфікацією w3c за обіцянками.

Ось де я вважаю, що ви помиляєтесь. Специфікація розрахована на мінімальний рівень і побудована для взаємодії між бібліотеками обіцянок. Ідея полягає у тому, щоб мати підмножину, яку, наприклад, ф'ючерси DOM, можуть надійно використовувати та бібліотеки можуть споживати. Обіцяючі впровадження роблять те, про що ви просите, .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', '!']);

2
Зауважте, що інші бібліотеки (наприклад, Q) також підтримують, .spreadяк Bluebird - причина цього не в специфікації, полягає в тому, що мінімізація специфікації є дійсно великою справою , щоб дозволити взаємодія між кодом і бібліотеками.
Бенджамін Грюнбаум

Друга примітка - можливо, ви захочете зателефонувати Promise.allдо масиву, перш ніж застосувати функцію, а не просто використовувати .thenїї для обробки деяких бібліотек цукру. Це не обов'язково, але це мило.
Бенджамін Грюнбаум

1
Promies.all є обов'язковим для вашої реалізації, хоча ви можете просто змінити реалізацію наreturn Promise.all(args).then(function(args){return fn.apply(this, args);})
Esailija

14
spread- зупинка. ES6 впроваджує руйнування та оператор спокою / розповсюдження, які позбавляють від потреби spreadпрямо. .then(([a, b, c]) => {})
Кріс Коваль

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
Приклад був би приємним і корисним з цією відповіддю!
Рахул Верма

19

Значення виконання обіцянки паралельно поверненому значенню функції, а причина відхилення обіцянки паралельно кинутому винятком функції. Функції не можуть повернути кілька значень, тому обіцянки не повинні мати більше 1 значення виконання.


4

Наскільки я можу сказати, читаючи специфікацію 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);
});

8
Q не підтримує багатозначні резолюції, оскільки обіцянки служать проксі-сервісами в результаті виклику функції, але можуть також проксі для віддалених об'єктів. В обох цих випадках масив є єдиним розумним поданням складного значення. З додаванням аргументів руйнування та "розповсюдження" в ES6 синтаксис стає справді приємним. Метод «розповсюдження» - це зупинка.
Кріс Коваль

Ну, ви завжди можете return Promise.of(x, y)замість скалярного значення від thenзворотного дзвінка.
Бергі

2

Ось рішення CoffeeScript.

Я шукав таке ж рішення і виявив, що щось відповіло на цю відповідь: Відхилення обіцянок з декількома аргументами (на зразок $ http) у 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

Повинно ->бути =>?
SherylHohman

1
@SherylHohman Ще в дні 2015 року це було написано за допомогою CoffeeScript ( coffeescript.org/#introduction ), а не синтаксисом ES6. Проста стрілка була простими функціями, а жирові стрілки майже такі ж, як і у ES6 (я думаю, що жирові стрілки ES6 були більш-менш запозичені у CoffeScript).
Валь Ентін

@SherylHohman Не соромтеся редагувати публікацію в ECMA, якщо хочете.
Валь Ентін

Дякую за Вашу відповідь. Я редагую лише для того, щоб уточнити, що це рішення кавового сценарію. З цього приводу ваша відповідь є такою, яка є, і може бути корисною для баз коду CoffeeScript. Дякуємо за вашу пропозицію редагувати: 1) Я недостатньо знайомий з CoffeeScript, щоб ризикувати редагувати / порушувати ваше рішення ;-). 2) Переклад вашого коду на сучасний JS слід вважати відхиленням від "початкового наміру вашої відповіді", тому не слід проходити огляд "редагування". Швидше хтось може опублікувати новий Відповідь, якщо це так схильно, переклавши ваш код. В ідеалі вони б
посилалися

0

Чудове запитання та чудова відповідь Бенджаміна, Криса та інших - велике спасибі!

Я використовую це в проекті і створив модуль на основі коду Бенджаміна Грюенвальда . Він доступний на 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()методу кілька аргументів , якщо значення обіцянки є Перший аргумент.

2.2.2.1 його потрібно викликати після виконання обіцянки, причому значення обіцянки є першим аргументом.


-1

Цитуючи статтю нижче, "" тоді "бере два аргументи, зворотний виклик для успішного випадку та інший для випадку відмови. Обидва необов'язкові, тому ви можете додати зворотний виклик лише для випадку успіху чи відмови."

Зазвичай я звертаюсь до цієї сторінки на будь-які основні запитання щодо обіцянок, повідомте мені, якщо я не прав

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


1
Це неправильно, new Promiseмає синтаксис, function(resolve, error)а thenмає синтаксис.then(function(arg) {
megawac

2
@megawac це насправді правильно просто погано - тоді приймає два (іноді 3) аргументи - це досить рідко
Бенджамін Груенбаум

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

2
Так, якщо ви уважно читаєте, саме на це стверджується ця відповідь - не дуже корисна в контексті цього питання, але не неправильна.
Бенджамін Груенбаум
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.