如果我拒绝承诺具有另一个Promise值,会发生什么?

时间:2016-08-29 02:31:22

标签: javascript promise

如果使用Promise(或Thenable)p的值解析Promise q,它实际上会成为Promise q的副本。如果q已解决,则p将使用相同的值进行解析。

Promise.resolve(Promise.resolve("hello"));
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: "hello"}

如果q被拒绝,则p将被拒绝并使用相同的值。

Promise.resolve(Promise.reject(new Error("goodbye")));
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: Error: goodbye}

通过Promise p解决/拒绝承诺q而不是直接使用相应的值,这与最终结果无关。中间Promise作为解决过程的一部分被消费,并且对消费者不可见。

如果q永远不会被解决或被拒绝,p也将永远保持待审。

Promise.resolve(new Promise(() => null)); // perpetually-pending promise
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

这些案例众所周知,但我从未见过如果Promise被拒绝(而不是已解决)与另一个Promise值会发生什么。拒绝过程是否也消耗中间承诺,或者它们是否完整传递?

如果确实消耗了它们,那该怎么办?

4 个答案:

答案 0 :(得分:7)

让我们看看如果我们拒绝承诺已解决的承诺p的承诺q会发生什么:

Promise.reject(Promise.resolve("hello"));
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: Promise}
Uncaught (in promise) Promise {
    [[PromiseStatus]]: "resolved", [[PromiseValue]]: "hello"}

或更明确地说:

const q = Promise.resolve("hello");
const p = Promise.reject(q);
p.then(null, x => console.log("Rejection value:", x));
Rejection value: Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: "hello"}

承诺q,拒绝价值,永远不会被解开! p的拒绝处理程序使用Promise q本身调用,而不是它包含的价值。

这也意味着p的拒绝处理程序在运行之前不需要等待q被解析。即使永远无法解析q,仍然可以调用p的拒绝处理程序。

Promise.reject(new Promise(() => null)); // Reject with perpetually-pending Promise
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: Promise}
Uncaught (in promise) Promise {
    [[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

最后,如果我们使用另一个被拒绝的承诺p拒绝承诺q,请让我们确认行为:

Promise.reject(Promise.reject(new Error("goodbye")));
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: Promise}
Uncaught (in promise) Error: goodbye(…)(anonymous function)
Uncaught (in promise) Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: Error: goodbye}

我们再次看到q未展开,p的拒绝处理程序将使用q本身进行调用,而不是q被拒绝的值

答案 1 :(得分:5)

所以,Jeremy的回答解释了会发生什么:

const p = Promise.reject(Promise.resolve(3)); 

p是被拒绝的承诺,拒绝价值Promise为3。

我们被教导相信承诺永远不会兑现承诺!嗯,这是一个特例。在这里,我们拒绝承诺与另一个承诺相矛盾的then

但为什么?!?

轻松运动。让我们先来看一些术语。

承诺从待处理开始,它可以成为:

  • 已履行 - 标记为已完成的值。
  • 拒绝 - 标记失败并有理由。

到目前为止一切顺利,但让我们考虑另外两个术语:

  • 已解决 - 表示已解决其他承诺值并正在跟踪它。
  • 已经解决 - 意味着它实际上已经实现或被拒绝 - 要么通过其解决后的承诺,要么自行解决。

呼。现在已经开始了:

Promise.resolve所做的是创建一个承诺已解决到另一个值。如果该值是一个承诺,它会跟踪它 - 否则它会立即与传入的值结算。如果您returnthen内的await async,也会发生这种情况。 {1}}功能。

Promise.reject做的是使用其他值创建承诺被拒绝。它没有机会遵循另一个承诺,因为它会立即被拒绝的结果创建。

此行为在rejectresolve中指定。特别是 - 我们正在创建promise capabilityresolve is special - 即查看" Promise Resolve Functions"。

好的,你告诉我发生了什么 - 但为什么?!?!?!?

好吧,让我们考虑其他选择。我们希望resolve模仿从then返回或等待async函数和reject来模仿throwthen中的async const p = Promise.resolve().then(() => { throw Promise.reject(5); }); 函数。

p

更清楚地看到将foo解析为5毫无意义!我们将承诺标记为正确完成,但显然没有正确完成。

类似地:

async function foo(){        抛出Promise.resolve(5);    }    FOO(); //没有人希望Promise能够解决。

如果拒绝使用未包装的值?

这意味着我们会丢失有关我们正在处理哪些拒绝的信息。唯一的选择是使用throw对象拒绝。

我应该碰到这个吗?

不,永远不会。你永远不应该SlideMenuController承诺,你应该始终reject with Errors

答案 2 :(得分:3)

承诺对象构建:

    new Promise( executor)

使用两个回调函数参数调用执行程序函数:

   executor( resolve, reject)

其中resolve被参数类型重载为

  1. 链接thenable的承诺:

    resolve( thenable);  // link the resolved promise to the final state of the thenable.
    

    已解决的承诺保持挂起状态,直到与其关联的承诺("已通过"解决)已解决,或

  2. 履行承诺的内容不是thenable

      resolve (notThenable);  // fulfill the promise with anything except a thenable.
    
  3. 成为javascript,"重载"在此上下文中,通过resolve在运行时检查参数类型和属性来执行,而不是在编译脚本时执行。 一个简单的解释是,您无法履行承诺或承诺之类的承诺。

    reject函数没有重载,也没有在运行时检查它的参数。如果承诺被承诺或其他thenable拒绝,则将其视为任何其他拒绝原因。承诺不会继续等待并被拒绝。用于拒绝的承诺作为理由参数传递给任何捕获承诺拒绝的函数。 一个简单的解释是,您可以拒绝任何您喜欢的承诺,但如果它不是Error对象或描述性原因,那么您就是自己!

答案 3 :(得分:-1)

Promise.resolve()可以获取价值,价值或承诺。它适应了它的行为。

Promise.reject()只占一个直接值。因此,如果您将Promise传递给它,它将会笨拙地试图将其视为直接值。

但是,您不会将承诺传递给Promise.reject。你可以这样做:

Promise.reject(myPromise); // weird and useless, and with no side effect
myPromise.then(e=>{console.log(e)}); // "consume" the promise
myPromise.then(e=>{console.log(e)}); // you can consume it as many times as you want