Promise.allSettled 在 babel ES6 实现中

Promise.allSettled in babel ES6 implementation

我正在使用 babel 转译我的 node.js@0.10.x 代码,但我受困于 promises。

我需要可以在 qbluebirdangular.$q 中使用的 allSettled 类型的功能。

在 babel 的 core-js Promise 上,没有 allSettled 方法。

目前我正在使用 q.allSettled 作为解决方法:

import { allSettled } from 'q';

babel polyfill 中有类似的东西吗?或者,哪个算法适合我尝试实施?

Alternatively, which is a good algorithm for me to try to implement?

  1. 使用 executor function
  2. 创建一个新的承诺
  3. 在执行器范围内使用一个counter/result数组
  4. 注册一个 then() 回调,每个父承诺将结果保存在数组中
  5. resolve/reject 当计数器指示所有父承诺都已完成时从步骤 1 开始承诺

这是我对类似事情的尝试,我有新闻通讯服务,在我的例子中,我希望我的 allSettled 承诺用所有结果(拒绝和解决)的数组来解决,按顺序,一旦所有 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;
}

这是对相同功能的另一种看法:spex.batch

使用方法source code would be too much to re-post here, so here's just an example from the batch processing

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' ]

这只是为了简化对所发生错误列表的快速访问。

2019 年答案

详情有a proposal to add this function to the ECMAScript standard, and it has been accepted! Check out the Promise.allSettled docs

原答案

如果您看一下 implementation of 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);
}

2020 年答案:

其他答案试图做的是自己实施 Promise.allSettled。这已经由 core-js 项目完成。

你需要做的是通过 core-js 为你制作 babel polyfill Promise.allSettled。你配置它的方式是通过 @babel/preset-env 像这样:

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

在您的构建工件中,这将添加对 require("core-js/modules/esnext.promise.all-settled") 的调用,该调用将 .allSettled 函数猴子修补到承诺 API.

我的实现如下

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

取自here