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

2024-05-28

有什么区别Promise.any() and Promise.race(),以及它们如何以不同的方式使用?


From MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any,

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

这让我想到了两者之间的区别resolved and settled。这让我想到了 MDN 的承诺page https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise, which then带我到状态与命运 https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md

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

所以我们有Promise.any and Promise.race为了语言方便?即那里is no不同之处。这种平等的另一个例子是“命运未决的承诺必然是悬而未决的”。 “如果一个承诺没有悬而未决,即如果它要么被履行,要么被拒绝,我们就说这个承诺已经解决。”。

因此,如果一个承诺得到解决,它就不是未解决的,因此它不是悬而未决的。那么,如果没有悬而未决,那就解决了。于是解决===解决了。


Promise.race and Promise.any做不同的事情:

Promise.race一旦你提供的任何承诺得到解决,无论它们是被履行还是被拒绝,它都会立即得到解决。

Promise.any一旦您提供任何承诺,就会立即解决已实现或者他们是all被拒绝,在这种情况下,它会被拒绝AggregateError.

主要区别是:

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

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

因此,如果您将两个承诺的数组传递给它们,并且其中一个承诺被拒绝,那么随后另一个承诺将得到履行,来自的承诺Promise.race将被拒绝(因为第一个解决的承诺被拒绝)并且来自Promise.any将会实现(因为虽然第一个承诺被拒绝,但第二个承诺实现了)。例如。:

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

使用具有以下功能的 JavaScript 引擎Promise.any(或填充),输出



race: rejected with a
any:  fulfilled with b
  

在这里尝试不同的结果(有一个very粗糙不完整的替代品Promise.any如果您的浏览器还没有包含它):

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

这张图表来自提案 https://github.com/tc39/proposal-promise-any可能有帮助:

Promise 景观中的四个主要组合器 https://v8.dev/features/promise-combinators.


+−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−+
| name               | description                                     |                 |
+−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−+
| Promise.allSettled | does not short-circuit                          | Added in ES2020 |
| Promise.all        | short-circuits when an input value is rejected  | Added in ES2015 |
| Promise.race       | short-circuits when an input value is settled   | Added in ES2015 |
| Promise.any        | short-circuits when an input value is fulfilled | this proposal   |
+−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−−−−−−−−−−−−−−−−+  

继续你的问题...

这种平等的另一个例子是“命运未决的承诺必然是悬而未决的”。 “如果一个承诺没有悬而未决,即如果它要么被履行,要么被拒绝,我们就说这个承诺已经解决。”。

因此,如果一个承诺得到解决,它就不是未解决的,因此它不是悬而未决的。那么,如果没有悬而未决,那就解决了。于是解决===解决了。

我可以看到你是如何到达那里的,但你不能那样颠倒它。 :-) 已解决的承诺可能会悬而未决。这只是一个未解决的承诺是确实待办的。

这些州是:

  • pending
  • 实现了
  • rejected

你可以解决一个承诺(A)到另一个承诺(B),这意味着虽然A可能仍然悬而未决,没有什么可以改变将要发生的事情;它的命运是注定的,它的实现或拒绝取决于所发生的事情B.

(有关此内容的更多信息,请参阅我的博客文章我们来谈谈如何谈论承诺 https://thenewtoys.dev/blog/2021/02/08/lets-talk-about-how-to-talk-about-promises/.)

以下是待解决的承诺的示例:

const b = new Promise((resolve, reject) => {
    setTimeout(() => {
        if (Math.random() < 0.5) {
            resolve("all good");
        } else {
            reject(new Error("ugh"));
        }
    }, 100);
});

// (Being verbose for clarity)
const a = new Promise((resolve, reject) => {
    resolve(b);
    // Now, `a` is pending, but resolved
    // No matter what else we do, `a`'s fate is tied to
    // `b`'s. For instance, this does nothing:
    resolve("foo");
    // Neither does this:
    reject(new Error("foo"));
});

b
.then(value => {
    console.log(`b was fulfilled: ${value}`);
})
.catch(reason => {
    console.log(`b was rejected: ${reason.message}`);
});

a
.then(value => {
    console.log(`a was fulfilled: ${value}`);
})
.catch(reason => {
    console.log(`a was rejected: ${reason.message}`);
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Promise.any() 和 Promise.race() 有什么区别 的相关文章

随机推荐