Promise.any() 和 Promise.race() 有什么区别

Ben*_*rth 17 javascript promise

Promise.any()和之间有什么区别Promise.race(),它们的用法有何不同?


来自MDN

此外,与返回第一个已解决值的 Promise.race() 不同,此方法返回第一个已解析值。此方法将忽略所有被拒绝的承诺,直到第一个解决的承诺。

所以这让我想到了resolvestable之间的区别。然后将我带到 MDN 承诺页面然后将我带到状态和命运

定居不是一种状态,只是一种语言上的便利。

所以我们有Promise.anyPromise.race为了语言方便?即没有区别。这种平等的另一个例子是“命运未决的承诺必然是未决的”。和“如果一个承诺不是待定的,即如果它被实现或被拒绝,我们说它被解决了。”。

所以如果一个 promise 被解决了,它就不是未解决的,所以它不是挂起的。那么,如果它不是待定的,它就已经解决了。所以解决了===解决了。

T.J*_*der 42

Promise.racePromise.any做不同的事情:

Promise.race 一旦您提供给它的任何承诺解决,就会立即解决,无论它们是被实现还是被拒绝。

Promise.any是只要你的任何给它的承诺入驻满足或他们拒绝了,在这种情况下,它拒绝用AggregateError

主要区别是:

  1. race当你给它的第一个承诺被拒绝时,它的承诺被拒绝;any不会,因为另一个承诺可能会被履行。

  2. any的承诺的拒绝原因将是一个AggregateError,但race拒绝原因将是被拒绝的承诺的拒绝原因。

因此,如果您向它们传递两个 Promise 的数组,并且其中一个被拒绝,然后另一个承诺被履行,则承诺 fromPromise.race将被拒绝(因为第一个要解决的承诺被拒绝)并且承诺 fromPromise.any将被拒绝实现了(因为虽然第一个 promise 被拒绝了,但第二个 promise 已经实现了)。例如:

const a = new Promise((_, reject) => setTimeout(reject,  100, new Error("a")));
const b = new Promise((resolve)   => setTimeout(resolve, 200, "b"));

Promise.race([a, b]).then(
    value => {
        console.log(`race: fulfilled with ${value}`);
    },
    reason => {
        console.log(`race: rejected with ${reason.message}`);
    }
);

Promise.any([a, b]).then(
    value => {
        console.log(`any:  fulfilled with ${value}`);
    },
    reason => {
        console.log(`any:  rejected with ${reason.errors.map(({message}) => message).join()}`);
    }
);
Run Code Online (Sandbox Code Playgroud)

使用具有Promise.any(或 polyfill)的 JavaScript 引擎,输出

种族:被拒绝
任何:满足b

在这里玩各种结果(如果您的浏览器还没有包含,则包含一个非常粗略的不完整替代品Promise.any):

race: rejected with a
any:  fulfilled with b
addFakeAnyIfMissing();

document.querySelector("input[value='Start Again']").addEventListener("click", run);

run();

function setupPromise(name) {
    return new Promise((resolve, reject) => {
        const div = document.querySelector(`[data-for="${name}"]`);
        const btnFulfill = div.querySelector("input[value=Fulfill]");
        const btnReject  = div.querySelector("input[value=Reject]");;
        const display    = div.querySelector(".display");
        btnFulfill.disabled = btnReject.disabled = false;
        display.textContent = "pending";
        btnFulfill.onclick = () => {
            resolve(name);
            display.textContent = `fulfilled with ${name}`;
            btnFulfill.disabled = btnReject.disabled = true;
        };
        btnReject.onclick = () => {
            reject(new Error(name));
            display.textContent = `rejected with Error(${name})`;
            btnFulfill.disabled = btnReject.disabled = true;
        };
    });
}

function run() {
    const a = setupPromise("a");
    const b = setupPromise("b");
    const raceDisplay = document.querySelector("[data-for=race] .display");
    const anyDisplay  = document.querySelector("[data-for=any]  .display");
    raceDisplay.textContent = anyDisplay.textContent = "pending";

    Promise.race([a, b]).then(
        value => {
            raceDisplay.textContent = `fulfilled with ${value}`;
        },
        reason => {
            raceDisplay.textContent = `rejected with ${reason.message}`;
        }
    );

    Promise.any([a, b]).then(
        value => {
            anyDisplay.textContent = `fulfilled with ${value}`;
        },
        reason => {
            anyDisplay.textContent = `rejected with ${reason.errors.map(({message}) => message).join()}`;
        }
    );
}

function addFakeAnyIfMissing() {
    if (!Promise.any) {
        // VERY ROUGH STANDIN, not a valid polyfill
        class AggregateError extends Error {}
        Object.defineProperty(Promise, "any", {
            value(iterable) {
                return new Promise((resolve, reject) => {
                    const errors = [];
                    let waitingFor = 0;
                    for (const value of iterable) {
                        const index = waitingFor++;
                        Promise.resolve(value).then(
                            value => {
                                resolve(value);
                                --waitingFor;
                            },
                            reason => {
                                errors[index] = reason;
                                if (--waitingFor === 0) {
                                    reject(Object.assign(new AggregateError(), {errors}));
                                }
                            }
                        );
                    }
                });
            },
            writable: true,
            configurable: true
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

提案中的这张图表可能会有所帮助:

Promise 环境中四个主要组合器

+????????????????????????+?????????????????????????????? ?????????????????????+?????????????????????+
| 姓名 | 说明 | |
+????????????????????????+?????????????????????????????? ?????????????????????+?????????????????????+
| Promise.allSettled | 不短路| 在 ES2020 中添加 |
| Promise.all | 拒绝输入值时的短路| 在 ES2015 中添加 |
| Promise.race | 输入值稳定时短路 | 在 ES2015 中添加 |
| Promise.any | 满足输入值时短路 | 这个提议|
+????????????????????????+?????????????????????????????? ?????????????????????+?????????????????????+

继续你的问题...

这种平等的另一个例子是“命运未决的承诺必然是未决的”。和“如果一个承诺不是待定的,即如果它被履行或被拒绝,我们说它被解决了。”。

所以如果一个 promise 被解决了,它就不是未解决的,所以它不是挂起的。那么,如果它不是待定的,则它已解决。所以解决了===解决了。

我可以看到你是如何到达那里的,但你不能那样颠倒它。:-) 一个已解决的承诺可能是挂起的。只是一个未解决的承诺肯定是悬而未决的。

这些州是:

  • 待办的
  • 完成
  • 拒绝了

您可以将一个 promise ( A)解析为另一个 promise ( B),这意味着虽然A可能仍处于挂起状态,但没有什么可以改变它将发生的事情;它的命运是封闭的,它会根据发生的事情来实现或拒绝B

以下是未决已解决承诺的示例:

<div data-for="a">
    Promise A
    <input type="button" value="Fulfill">
    <input type="button" value="Reject">
    <span class="display"></span>
</div>
<div data-for="b">
    Promise B
    <input type="button" value="Fulfill">
    <input type="button" value="Reject">
    <span class="display"></span>
</div>
<div data-for="race">
    <code>Promise.race([a, b])</code>:
    <span class="display"></span>
</div>
<div data-for="any">
    <code>Promise.any([a, b])</code>:
    <span class="display"></span>
</div>
<input type="button" value="Start Again">
Run Code Online (Sandbox Code Playgroud)

  • 感谢您提供所有代码示例。我怀疑这个答案将在未来几年对程序员有用! (7认同)