JS Promises:Fulfill vs Resolve

问题描述 投票:10回答:3

我理解Promise存在于以下三种状态之一:Promise可以是待处理(未解析),履行(成功解决)或拒绝(解决失败)。

通过A+ Promise SpecMDN's documentation阅读,我很困惑他们都承认已完成和被拒绝的状态,但在Promise构造函数的定义中,他们指定了两个回调:resolve和reject。我们似乎可以互换地使用这两个术语;他们不是。

并不意味着成功:

re·solve /rəˈzälv/ verb
1. settle or find a solution to (a problem, dispute, or contentious matter).

是否意味着成功:

ful·fill /fo͝olˈfil/ verb
1. bring to completion or reality; achieve or realize (something desired, promised, or predicted).
2. carry out (a task, duty, or role) as required, pledged, or expected.

当我们真正实现承诺时,为什么我们在这里使用决心?是否有一个实例,我们传递给它的值可能会导致Promise被拒绝?

javascript promise
3个回答
4
投票

我们可以用另一个承诺来解决承诺。

首先回答你的第二个问题:是的,有一个实例,我们传递给它的值可能导致Promise被拒绝,也就是说,如果我们传递一个被拒绝的承诺,例如Promise.reject()

回答你的第一个问题是没有解决问题并且完成相同的事情:考虑我们传递给要解决的价值是未决承诺的情况。在这种情况下,我们自己的承诺不会立即解决:

a().then(() => new Promise(setTimeout)).catch(e => console.error(e));

在这种情况下,我们说承诺是“解决”另一个承诺,它仍然悬而未决。

这一切都发生在我们背后的then背后,因此可能更容易看一下a不支持承诺(采取回调)的复古案例,而且我们没有正确地展平事物:

// Old times and unflattened for exposition:
new Promise((resolve, reject) => a(function(result) {
  resolve(new Promise(setTimeout));
}, reject))
.then(() => console.log("after setTimeout"))
.catch(e => console.error(e));

在这里,我们更清楚地看到,决心被另一个承诺所呼唤。重要的是,已解决的承诺不会实现并触发"after setTimeout"消息,直到第二个承诺结算(来自undefined的非承诺setTimeout值),此时两个承诺都会实现(换句话说:这两个承诺刚刚形成了resolve chain) 。

这是理解已解决的不同于履行或甚至解决(履行或拒绝,未待决)的关键。

来自States and Fates

  • 州:履行,拒绝,待决。
  • 命运:已解决,尚未解决。

命运指的是单一承诺的命运是否已达到,并且由于解决链而不直接对应于任何状态转换。


2
投票

我认为,承诺已经解决或解决了,这是很常见的。承诺的解决是承诺从pending州转移并获得与该州相关的价值的过程。因此,如果承诺是fulfilledrejected,它将是一个已解决的承诺(因为它的解决过程已经结束)。如果承诺进入解决过程并且从未转换到任何其他状态,则表示承诺未解决(解决过程从未结束)。

关于其他术语rejectedfulfilled,它们是pending承诺可以转变的另外两个州。 reject是非常明显的IMO,它处理应该发生故障的情况。现在我同意fulfill可能有些含糊不清,因为它可能只是意味着承诺已成功完成(如在解决中)。它不应该描述解决过程,而是描述手头任务的成功(或没有错误)。

解决过程(解决承诺)可以在A+ spec中观察到。

编辑。

人们通常使用resolve作为第一个参数名称的原因是因为作为第一个参数传递的回调调用了解析过程。它不履行承诺(承诺仍然可以被拒绝),它只是开始解决承诺。 reject机制没有在规范中指定,它实际上是一种短路解决过程,以便承诺与reject解决(实际上没有解决你看到)。

以下是使用p拒绝resolve的一些示例:

这是点2.3.1

var p = new Promise(resolve => setTimeout(() => resolve(p), 0));

这是点2.3.2.3

var p = Promise.resolve(Promise.reject('reason'));

这是点2.3.3.2

var thenable = { get then() { throw new Error(); } }
var p = Promise.resolve(thenable);

这是点2.3.3.3.3

var thenable = {
    then: function(resolvePromise, rejectPromise){
        rejectPromise(new Error());
    }
}
var p = Promise.resolve(thenable);

这是点2.3.3.4.2

var thenable = {
    then: function(){
        throw new Error();
    }
}
var p = Promise.resolve(thenable);

我在这里使用Promise.resolve而不是传递给Promise构造函数的函数的第一个参数,但它们应该是相同的。很多时候传递给构造函数的resolve函数是:

var p = this;
var cb = function(x){
    resolve(p, x);
}

您当然可以将这些测试记录为:

var p = new Promise(function(resolve){
    resolve(thenable);
});

2
投票

具有Promise值的已解析的Error不会自动将Promise转换为拒绝Promise

var p = Promise.resolve(new Error("rejected"));
p.then(function(data) {
  console.log(data, p)
})

另见States and fates


如果您可以包含有关如何使用拒绝承诺而不是履行承诺的信息,我会认为这是一个完整的答案。

不确定使用resolve拒绝Promise的原因或预期结果?虽然最简单的方法是在reject称为resolve时将Promise.resolve(Promise.reject(/* Error here */))作为参数传递

var _reject = function(err) {
  return Promise.reject(err)
}

var resolver = function(resolve, reject) {  
    return resolve(_reject(new Error("reject within resolve")))
}

var p = new Promise(resolver);

p.then(function(data) {
  console.log("resolved", data)
},function(data) {
  console.log("rejected:", data, "promise:", p)
})

如果预期的结果是捕获错误或拒绝Promise传递给可能附加处理程序的resolve,同时保持"resolved" PromiseStatus,可以使用unhandledrejection事件,Promise.reject直接或铬/铬49+可以使用PromiseRejectionEvent

window.addEventListener("unhandledrejection", function(event) {
  // handle unhandled rejected `Promise`
  console.log("unhandledrejection:", event.reason, event.promise);
});

Promise.resolve(new PromiseRejectionEvent("Error", {
    // unhandled `rejected` `Promise` 
    promise: Promise.reject(new Error("custom rejection")),
    reason: "custom rejection"
  }))
  .then(function(data) {
    // `PromiseRejectionEvent` contains a `rejected`
    // `Promise` , which triggers `"unhandledrejection"` event
    // to handle rejected `Promise` here, resolve `.promise` 
    // object of `PromiseRejectionEvent`
    console.log("resolved:", data);
  }, function(err) {
    console.log("rejected", err)
})

也可以throwError构造函数中使用Promise而不使用resolvereject,这应该由onRejectedcatch处理

new Promise(function(resolve, reject) {
  throw new Error("reject within Promise constructor")
})
// catch here handles `Error` from `Promise` constructor
// will be `resolved` at `.then()` if `Error` not `throw`n to `.then()` 
// .catch(function(e) {
//  console.log("caught error:", e);
  /* return e : pass `e` to `.then()` as `resolved` `Promise` */
  /* throw e : pass `e` to `.then()` as `rejected` `Promise`  */
//})

.then(function(data) {
  console.log("resolved:", data)
}, function(err) {
  console.log("rejected:", err);
  throw err
})
.catch(function(e) {
  console.log("caught error:", e);
  /* return e : pass `e` to `.then()` as `resolved` `Promise` */
  /* throw e : pass `e` to `.then()` as `rejected` `Promise`  */
})

说明:根据应用程序和预期结果,有许多方法可以处理已解析和拒绝的Promise对象。


1
投票

实际上,解决回调并不意味着承诺将得到履行。

履行,拒绝,待决,解决,解决和锁定的条款在EcmaScript2015 specs, 25.4 Promise Objects中定义:

任何Promise对象都处于三种互斥状态之一:履行,拒绝和挂起:

  • 如果p将立即将一个Job列入职务调用函数p.then(f, r),那么就会实现一个承诺f
  • 如果p将立即将一个Job命名为函数p.then(f, r),则拒绝承诺r
  • 如果未履行或拒绝,则承诺正在等待。

如果一项承诺没有待决,即如果它已被履行或被拒绝,则该承诺将被解决。

如果一个承诺被解决或者它被“锁定”以匹配另一个承诺的状态,则该承诺得到解决。尝试解决或拒绝已解决的承诺无效。如果未解决,则承诺未得到解决。未解决的承诺始终处于暂挂状态。已解决的承诺可能正在等待,履行或拒绝。

简短概述,我将使用术语“自治”作为“锁定”的对立面。它们是promise的依赖情况的两个可能值:

+---------------------+------------+-----------+-----------+----------+
| action              | dependency | state     | resolved? | settled? |
+---------------------+------------+-----------+-----------+----------+
| new Promise()       | autonomous | pending   |    no     |    no    |
| - resolve(thenable) | locked-in  | pending*  |    yes    |    no    |
| - resolve(other)    | autonomous | fulfilled |    yes    |    yes   |
| - reject(any)       | autonomous | rejected  |    yes    |    yes   |
+---------------------+------------+-----------+-----------+----------+

* theable现在可以控制我们的promise对象的未来状态。

上面的引用提到了一个承诺被锁定以匹配“另一个承诺”的状态,但更准确地说,“其他承诺”也可能是一个非承诺“可以”,如在步骤11和12中可以看到的那样。 25.4.1.3.2中的过程描述

  1. 如果IsCallable(thenAction)是false,那么 一个。返回FulfillPromise(承诺,解决方案)。
  2. 执行EnqueueJob("PromiseJobs",PromiseResolveThenableJob,«promise,resolution,thenAction»)

使用thenable调用resolve的演示,这反过来会触发拒绝:

const thenable = { // Could be a promise object, but does not have to be
    then(success, fail) {
        setTimeout(() => fail("gotcha!"), 1000);
    }
}

const p = new Promise((resolve, reject) => {
    console.log("1. The promise is created as pending");
    setTimeout(() => {
        resolve(thenable);
        console.log("2. It's resolved with a thenable; it's not yet settled");
    }, 1000);
});

p.catch(err => 
   console.log(`3. It's settled as rejected with error message "${err}"`)
);
© www.soinside.com 2019 - 2024. All rights reserved.