静下心来的个人专栏
上一篇

链式Promise——finally

广告
选中文字可对指定文章内容进行评论啦,→和←可快速切换按钮,绿色背景文字可以点击查看评论额。
大纲

链式Promise使用finally

promise的finally方法的行为与thencatch方法截然不同,它将前一个promise的状态和值复制到其返回的promise中。这意味着原始Promise fullfiled返回一个值,那么finally将返回一个以相同值fullfiled的promise。

const promise = Promise.resolve(42);

promise.finally(() => {
  console.log("Finally called.");
}).then(value => {
  console.log(value); // 42
});

这里,settlement handler没有从promise接收到一个fullfiled值,因此该值被复制到从finally方法调用返回的新的promise中。新的promise用值42来实现,因此fullfilment handler接收42作为参数。请记住,即使返回的 Promise 和 Promise 具有相同的值,它们也不是同一个对象,如您在此示例中所见:

const promise1 = Promise.resolve(42);

const promise2 = promise1.finally(() => {
  console.log("Finally called.");
});

promise2.then(value => {
  console.log(value); // 42
});

console.log(promise1 === promise2); // false

在这段代码中,promise1.finally() 的返回值存储在promise2 中,此时可以确定它与promise1 不是同一个对象。finally() 的调用总是从原始promise中复制状态和值。 这也意味着当 finally() 被一个rejected的 promise 调用时,它又会返回一个rejected的 promise,如下例所示:

const promise = Promise.reject(43);

promise.finally(() => {
  console.log("Finally called.");
}).catch(reason => {
  console.error(reason); // 43
});

此示例中的 Promise Promise 以 43 的原因rejected。同样,settlement handler无法访问此信息,因为它没有作为参数传入,因此它返回一个新的 Promise,但由于相同的原因rejected。 然后,您可以使用catch() 来检索原因。

 

特殊情形

finally() 工作方式的一个例外是在settlement handler内部抛出错误或返回rejected的promise时。 在这种情况下,finally() 返回的 Promise不会保持原始 Promise 的状态和值,而是以抛出的错误为原因rejected。 这是一个例子:

const promise1 = Promise.reject(43);

promise1.finally(() => {
  throw 44;
}).catch(reason => {
  console.error(reason); // 44
});

const promise2 = Promise.reject(43);

promise2.finally(() => {
  return Promise.reject(44);
}).catch(reason => {
  console.error(reason); // 44
});

因为在此示例中settlement handler抛出 44 或返回Promise.reject(44),返回的 Promise 被拒绝,值为 44,并输出到控制台而不是 43。由于在settlement handler中抛出错误,原始promise的状态和值会丢失。

 

在第 1 章中,您看到了如何使用settlement handler根据对 fetch() 的调用来切换应用程序的加载状态。 使用promise链重写该示例,并混合本章前面的一些错误处理,这是一个完整的示例:

 

const appElement = document.getElementById("app");
const promise = fetch("books.json");

appElement.classList.add("loading");

promise.then(response => {
  if (response.ok) {
    console.log(response.status);
  } else {
    throw new Error(`Unexpected status code: ${response.status} ${response.statusText}`);
  }
}).finally(() => {
  appElement.classList.remove("loading");
}).catch(reason => {
  console.error(reason.message);
});

与 try-catch 语句不同,您不希望 finally() 成为链的最后一部分,以防万一它抛出错误。 所以先调用 then() 来处理来自 fetch() 的响应,然后将 finally() 添加到链中以触发 UI 更改,最后 catch() 为整个链添加错误处理程序。这就是传递前一个promise状态的settlement handler有帮助的地方:如果fullfilment handler最终抛出错误,结算fullfilment handler将传递该rejection状态,以便reject handler可以访问它。

版权声明:著作权归作者所有。

X

欢迎加群学习交流

联系我们