创建被拒绝的 JS 承诺的正确方法是什么?

What is a proper way to create a JS promise that is rejected?

如果只是为了试验 JS Promises 或 Promise.race() 等,需要创建一个被拒绝的 promise:

p = Promise.reject(Error("some unknown reason"));

但是这样一来,就会抛出异常。如果你沉默错误:

p = Promise.reject(Error("some unknown reason")).catch(err => {});

然后 p 实际上将是一个已解决的承诺。这是为什么?应该以这种方式创建被拒绝的承诺,还是应该做什么?如果使用 Promise.resolve(1).

,已解决的承诺会简单得多

创建被拒绝的承诺的正确方法是这样的:

let p = Promise.reject(new Error("some unknown reason"));

在某个地方,在您 return 回到事件循环之前,您需要对任何被拒绝的承诺有一个 .catch() 处理程序。如果您不这样做,系统将警告您有未处理的拒绝。这就是 Javascript 语言实现的状态。设计人员认为,不要让未处理的承诺拒绝被忽视是非常重要的(我同意 - 就像未处理的同步异常不会被忽视一样)。而且,在 JS 引擎的当前状态下,它们对未处理拒绝的检测略有不完善。有可能你可能会用那个被拒绝的承诺做一些事情,即 LATER 添加一个 .catch() 处理程序,但 JS 引擎不知道你以后要做什么。它只知道你已经回到了事件循环,而你还没有这样做。这看起来很麻烦,所以它会警告你。

如果你在上面放一个 .catch(),那么承诺会接受你 return 或从 .catch() 处理程序中抛出的任何东西(就像 try/catch 在同步世界)。所以,如果你这样做:

let p = Promise.reject(new Error("some unknown reason")).catch(err => {});

然后,您在 .catch() 和 return 中捕获了拒绝,或者没有从中抛出任何东西,因此承诺链现在已通过 undefined 解析值解析。那里没有 .catch() 的要求,但是如果您有特定的理由添加 .catch() (例如记录或清理代码或检查错误以确定正确的操作过程),但您想要promise 链以同样的原因被拒绝,那么你必须 return 一个新的被拒绝的 promise 或像这样抛出原始错误:

let p = Promise.reject(new Error("some unknown reason")).catch(err => {
    // do whatever you want here
    console.log(err);
    throw err;                 // rethrow to keep the promise chain rejected
});

或者像这样:

let p = Promise.reject(new Error("some unknown reason")).catch(err => {
    // do whatever you want here
    console.log(err);
    return Promise.reject(err);  // return rejected promise to keep the promise chain rejected
});

但是,您需要对该承诺做一些事情,以便在某种承诺链上下文中使用它,最终将有一个真正的 .catch() 处理程序。

例如(你提到Promise.race),你可以这样做:

function delay(t,v) {
    return new Promise(resolve => {
        setTimeout(resolve, t, v);
    });
}

let p1 = Promise.reject(new Error("You got rejected!!"));
let p2 = delay(100, "Got a good result");

Promise.race([p1, p2]).then(result => {
    console.log(result);
}).catch(err => {
    console.log(err.message);
});

这里不会有关于未处理的承诺拒绝的警告,因为我们将 p1 承诺(被拒绝)插入到 Promise.race() 中并且上面有一个 .catch() 处理程序.

Then p actually will be a resolved promise. Why is that?

因为您有一个空的 .catch() 没有 return 处理程序拒绝的承诺或没有抛出异常。所以,拒绝是 "caught" 和 "handled" 并且承诺链现在回到解决状态。由于 .catch() 处理程序没有 return 值,承诺链的解析值现在是 undefined.

Is a rejected promise supposed to be created this way, or what should be done?

是的,这是创建拒绝承诺的正确方法。但是,你需要用它做点什么,而不是让它自己坐在那里。最终用它完成的事情(return 从一些承诺链中处理它或将其他处理程序链接到它)需要尽快发生(就像在解释器返回事件循环之前)。如果您用真实代码展示了一个真实世界的用例,我们可以更好地建议如何处理这个问题。