Promise.allSettled в реализации Babel ES6

Я использую babel для транспиляции своего [email protected] кода, и я застрял на обещаниях.

Мне нужны функции типа allSettled, которые я мог бы использовать, например, в q и bluebird или angular.$q.

В core-js Promise babel нет метода allSettled.

В настоящее время я использую q.allSettled как обходной путь:

import { allSettled } from 'q';

Есть ли что-то подобное в babel polyfill? В качестве альтернативы, какой алгоритм мне лучше всего попробовать реализовать?


person Zlatko    schedule 01.06.2015    source источник


Ответы (7)


В качестве альтернативы, какой алгоритм мне лучше всего попробовать реализовать?

  1. создать новое обещание с помощью функции исполнителя
  2. использовать массив счетчиков / результатов в области исполнителя
  3. зарегистрируйте обратный вызов then () с каждым родительским обещанием, сохраняя результаты в массиве
  4. разрешить / отклонить обещание с шага 1, когда счетчик указывает, что все родительские обещания выполнены
person the8472    schedule 01.06.2015
comment
Хорошо, но пока я буду использовать Q (который, вероятно, делает то же самое). - person Zlatko; 01.06.2015
comment
Что касается вашего шага 4, как я узнаю, что нужно отклонить новое обещание? - person ; 19.08.2016
comment
@torazaburo, ты прав, ты никогда не откажешься, в этом суть allSettled :) Может быть, какой-то тайм-аут, но это другой вариант использования, не отражающий то, что делает q.allSettled. - person Zlatko; 19.08.2016

Ответ 2019

Было предложение добавить эту функцию в стандарт ECMAScript, и оно было принято! Дополнительные сведения см. В Promise.allSettled docs. .

Оригинальный ответ

Если вы посмотрите на реализацию q.allSettled вы увидите, что на самом деле это довольно просто реализовать. Вот как вы можете реализовать это с помощью ES6 Promises:

function allSettled(promises) {
    let wrappedPromises = promises.map(p => Promise.resolve(p)
        .then(
            val => ({ status: 'fulfilled', value: val }),
            err => ({ status: 'rejected', reason: err })));
    return Promise.all(wrappedPromises);
}
person Michael Kropat    schedule 19.08.2016
comment
Майкл - я тоже ищу такое решение (Promise.all, которое выполняет все обещания, а затем фиксирует все ошибки в массиве) - чтобы использовать вашу функцию allSettled, я бы сделал npm install q, а затем do const q = require ('q'); в моем приложении? - person Roger Dodger; 01.03.2019
comment
@RogerDodger Код, который я написал, предполагает, что вы используете среду выполнения с поддержкой ES6, поэтому в основном любой текущий браузер или современная версия Node. Или вы используете полифилл обещаний. В любом случае вам не нужно импортировать Q или любую другую библиотеку обещаний. - person Michael Kropat; 01.03.2019
comment
Черт, в феврале 2020 года Edge по-прежнему не поддерживает Promise.allSettled, спасибо за полифил из вашего исходного ответа! - person Big Money; 08.02.2020
comment
Зачем заключать обещание в Promise.resolve(p)? чтобы быть уверенным, что это определенно обещание? - person OlehZiniak; 25.11.2020
comment
@OlehZiniak Да, именно так. Это может быть удобно, если у вас есть смешанный массив обещаний и значений, не являющихся обещаниями. Другой вариант - в этом случае allSettled выдает ошибку. - person Michael Kropat; 25.11.2020

2020 ответ:

Другие ответы пытаются реализовать сами Promise.allSettled. Это уже было сделано в рамках проекта core-js.

Вам нужно сделать babel polyfill Promise.allSettled за вас с помощью core-js. Вы настраиваете его для этого с помощью @babel/preset-env следующим образом:

presets: [
    ['@babel/preset-env', {
        useBuiltIns: 'usage',
        corejs: {version: 3, proposals: true},
    }],
],

В вашем артефакте сборки это добавит вызов require("core-js/modules/esnext.promise.all-settled"), который monkey изменяет функцию .allSettled на promises API.

person Ivan Rubinson    schedule 16.03.2020

const allSettled = promises =>
  Promise.all(promises.map(promise => promise
    .then(value => ({ state: 'fulfilled', value }))
    .catch(reason => ({ state: 'rejected', reason }))
  ));

Или, если вы настаиваете на полифилле:

if (Promise && !Promise.allSettled) {
  Promise.allSettled = function (promises) {
    return Promise.all(promises.map(function (promise) {
      return promise.then(function (value) {
        return { state: 'fulfilled', value: value };
      }).catch(function (reason) {
        return { state: 'rejected', reason: reason };
      });
    }));
  };
}

Взято из здесь

person Marko Bonaci    schedule 21.01.2021
comment
@chunk_split, спасибо, я обновил core.js до v3, поэтому теперь у меня есть собственный allSettled, и полифилл больше не нужен. - person Marko Bonaci; 14.05.2021

Вот моя попытка сделать что-то подобное, у меня есть служба информационных бюллетеней, и в моем случае я хотел, чтобы мое обещание allSettled разрешалось с массивом всех результатов (отклонения и разрешения), IN ORDER, когда все email_promises улажено (все письма разошлись):

Newsletter.prototype.allSettled = function(email_promises) {
    var allSettledPromise = new Promise(function(resolve, reject) {
        // Keep Count
        var counter = email_promises.length;

        // Keep Individual Results in Order
        var settlements = [];
        settlements[counter - 1] = undefined;

        function checkResolve() {
            counter--;
            if (counter == 0) {
                resolve(settlements);
            }
        }

        function recordResolution(index, data) {
            settlements[index] = {
                success: true,
                data: data
            };
            checkResolve();
        }

        function recordRejection(index, error) {
            settlements[index] = {
                success: false,
                error: error
            };
            checkResolve();
        }

        // Attach to all promises in array
        email_promises.forEach(function(email_promise, index) {
            email_promise.then(recordResolution.bind(null, index))
                .catch(recordRejection.bind(null, index));
        });
    });
    return allSettledPromise;
}
person stujo    schedule 07.10.2015

Вот еще один пример той же функциональности: spex.batch

исходный код было бы слишком много для повторного использования. -публикуйте здесь, так что вот только пример из пакетной обработки о том, как его использовать:

var spex = require('spex')(Promise);

// function that returns a promise;
function getWord() {
    return Promise.resolve("World");
}

// function that returns a value;
function getExcl() {
    return '!';
}

// function that returns another function;
function nested() {
    return getExcl;
}

var values = [
    123,
    "Hello",
    getWord,
    Promise.resolve(nested)
];

spex.batch(values)
    .then(function (data) {
        console.log("DATA:", data);
    }, function (reason) {
        console.log("REASON:", reason);
    });

Это выводит:

DATA: [ 123, 'Hello', 'World', '!' ]

Теперь давайте исправим ошибку, изменив getWord на это:

function getWord() {
    return Promise.reject("World");
}

Теперь вывод:

REASON: [ { success: true, result: 123 },
  { success: true, result: 'Hello' },
  { success: false, result: 'World' },
  { success: true, result: '!' } ]

т.е. весь массив рассчитан, сообщая о результатах, привязанных к индексу.

И если вместо сообщения всей причины мы вызовем getErrors():

console.log("REASON:", reason.getErrors());

тогда вывод будет:

REASON: [ 'World' ]

Это просто для упрощения быстрого доступа к списку возникших ошибок.

person vitaly-t    schedule 15.10.2015

моя реализация будет ниже

Promise.prototype.myAllSettled = function (arr = []) {
  return new Promise(function processIterable(resolve, reject) {
    let result = [];
    arr.forEach((item) => {
      item
        .then((value) => {
          result.push({ status: "fulfilled", value: value });
          if (arr.length === result.length) resolve(result);
        })
        .catch((err) => {
          result.push({ status: "rejected", reason: `${err}` });
          if (arr.length === result.length) resolve(result);
        });
    });
  });
};
person Vikas Tiwari    schedule 01.06.2020
comment
Привет, Викас, это немного старый вопрос. Прямо сейчас вам даже не нужна библиотека для этого, она изначально поддерживается во всех основных браузерах: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ - person Zlatko; 03.06.2020
comment
но не в электроне - person johnsimer; 09.09.2020
comment
Проблема заключается в том, что он переупорядочивает обещания на основе того, которое выполняется первым, это не то, как ведет себя нативная функция. - person Ferrybig; 23.09.2020