广告
返回顶部
首页 > 资讯 > 精选 >JavaScript中使用Promises的三个错误是什么
  • 869
分享到

JavaScript中使用Promises的三个错误是什么

2023-06-27 10:06:41 869人浏览 安东尼
摘要

本篇内容介绍了“javascript中使用Promises的三个错误是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!将所有内容包装在 P

本篇内容介绍了“javascript中使用Promises的三个错误是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

将所有内容包装在 Promise 构造函数中

第一个错误也是最为明显的错误之一,但是我发现开发者犯这个错误的频率出奇的高。

当第一次学习 Promises 时,你会了解到 Promise 的构造函数,这个构造函数可以用来创建一个新的 Promises 对象。

也许因为人们通常是通过将一些浏览器 api(例如 setTimeout)包装在 Promise 构造函数中这种方式来开始学习的,所以在他们心中根深蒂固地认为创建 Promise 对象的唯一方法是使用构造函数。

因此,通常会这样写:

const createdPromise = new Promise(resolve => {  somePreviousPromise.then(result => {    // 对 result 进行一些操作    resolve(result);  });});

可以看到,为了对 somePreviousPromise 的结果 result 进行一些操作,有些人使用了 then,但是后来决定将其再次包装在一个 Promise 的构造函数中,为的是将该操作的结果存储在 createdPromise 的变量中,大概是为了稍后对该 Promise 进行更多操作。

这显然是没有必要的。then 方法的全部要点在于它本身会返回一个 Promise,它表示的是执行 somePreviousPromise 后再执行then 中的的回调函数,then 的参数是 somePreviousPromise成功执行返回的结果。

所以,上一段代码大致等价于:

const createPromise = somePreviousPromise.then(result => {  // 对 result 进行一些操作  return result})

如此编写,会简洁很多。

但是,为什么我说它只是大致等价呢?区别在哪里?

经验不足且不细心观察的话可能很难发现,实际上两者在错误处理上存在巨大的差异,这种差异比第一段代码的冗余问题更为重要。

假设 somePreviousPromise 出于某些原因失败了且抛出错误。例如,这个 Promise 里发送了一个 Http 请求,而 API 响应 500 错误。

事实证明,在上一段代码中,我们将一个 Promise 包装到另一个 Promise 中,我们根本无法捕获该错误。为了解决此问题,我们必须进行以下更改:

const createdPromise = new Promise((resolve, reject) => {  somePreviousPromise.then(result => {    // 对 result 进行一些操作    resolve(result);  }, reject);});

我们简单的在回调函数中添加了一个 reject 参数,然后通过将其作为第二个参数传递给 then 的方式来使用它。请务必记住,then 方法接受第二个可选参数来进行错误处理,这一点非常重要。

现在如果 somePreviousPromise 出于某些原因失败了,reject函数将会被调用,并且我们将能够一如往常地处理 createdPromise上的错误。

这样是否解决了所有问题?抱歉,并没有。

我们处理了 somePreviousPromise 自身可能发生的错误,但是我们仍然无法控制作为 then 方法第一个参数的回调函数中发生的情况。在注释区域 // 对 result 进行一些操作 执行的代码可能会有一些错误,如果这块地方的代码抛出任何错误,那 then 方法的第二个参数reject 依旧捕获不到这些错误。

这是因为作为 then 方法的第二个参数的错误处理函数只对 Promise 链上当前 then 之前发生的错误作出响应。

因此,最合适的(也是最终的)解决方案应该如下:

const createdPromise = new Promise((resolve, reject) => {  somePreviousPromise.then(result => {    // 对 result 进行一些操作    resolve(result);  }).catch(reject);});

注意,这次我们使用了 catch 方法 —— 因为它将在第一个 then之后被调用,它将捕获到 Promise 链上抛出的所有错误。无论是 somePreviousPromise 还是 then 中的回调失败了,Promise 都将按预期处理这些情况。

从上述示例可以发现,在 Promise 的构造函数中包装代码时,有很多细节问题需要处理。这就是为什么最好使用 then 方法创建新的 Promises 的原因,如第二段代码所示。它不仅看起来优雅,并且还可以帮助我们避免那些极端情况。

串行调用 then 与并行调用 then 的比较

由于许多程序员都有着面向对象编程背景,因此对他们来说,调用一个方法会更改一个对象,而非创建一个新的对象,这很稀松平常。

这或许也是我看到有人对于「在 Promise 上调用 then 方法时」到底发生了什么会感到困惑的原因。

比较下面两段代码:

const somePromise = createSomePromise();somePromise  .then(doFirstThingWithResult)  .then(doSecondThingWithResult);
const somePromise = createSomePromise();somePromise  .then(doFirstThingWithResult);somePromise  .then(doSecondThingWithResult);

它们所做之事是否相同?看起来似乎相同,毕竟,两段代码都在 somePromise 上调用了两次 then,对吗?

不,这又是一个非常普遍的误区。实际上,这两段代码做的事情完全不同。如果不完全理解两段代码中正在做的事情,可能会导致出现非常棘手的错误。

正如我们在之前的章节中所说,then 方法会创建一个完全新的、独立的 Promise。这意味着在第一段代码中,第二个 then 方法不是在 somePromise 上调用,而是在一个新的 Promise 对象上调用,这段代码表示等待 somePromise 的状态变为成功后立刻调用 doFirstThingWithResult。然后给新返回的 Promise 实例添加一个回调操作 doSecondThingWithResult

实际上,这两个回调将会一个接着一个地执行 —— 可以确保只有在第一个回调执行完成且没有任何问题之后,才会调用第二个回调。此外,第一个回调将会接收 somePromise 返回的值作为参数,但是第二个回调函数将接收 doFirstThingWithResult 函数返回的值作为参数。

另一方面,在第二段代码中,我们在 somePromise 上调用两次then 方法,基本上忽略了从该方法返回的两个新的 Promises 对象。因为 then 在完全相同的 Promise 实例上被调用了两次,因此我们无法确定首先执行哪个回调,这里的执行顺序是不确定的。

从某种意义上说,这两个回调应该是独立的,并且不依赖于任何先前调用的回调,我有时将其视为 “并行” 的执行。但是,当然,实际上,js 引擎同一时刻只能执行一个功能 —— 你根本无法知道它们将以什么顺序调用。

两段代码的第二个不同之处是,在第二段代码中 doFirstThingWithResultdoSecondThingWithResult 都会接收到同样的参数 —— somePromise 成功执行返回的结果,两个回调函数的返回值在这个示例中被完全忽略掉了。

创建后立即执行 Promise

这个误区出现的原因也是因为大部分程序员有着丰富的面向对象编程经验。

在面向对象编程的思想中,确保对象的构造函数自身不执行任何操作通常被认为是一种很好的实践。举个例子,一个代表数据库的对象在使用new 关键字调用其构造函数时不应该启动与数据库的链接。

相反,应该提供一个特定的方法,如调用一个名为 init 的方法 —— 它将显式地创建连接。这样,一个对象不会因为已被创建而执行任何期望之外的操作。它会按照程序员的明确要求来执行。

但这「不是 Promises 的工作方式」

考虑如下示例:

const somePromise = new Promise(resolve => {  // 创建 HTTP 请求  resolve(result);});

你可能会认为发出 HTTP 请求的函数未在此处调用,因为它包装在 Promise 构造函数中。实际上,许多程序员希望 somePromise 上执行 then 方法之后它才被调用。

但事实并非如此。创建该 Promise 后,回调将立即执行。这意味着当您在创建 somePromise 变量后进入下一行时,你的 HTTP 请求可能已被执行,或者说已存在执行队列里。

我们说 Promise 是 “eager” 的,因为它尽可能快地执行与其关联的动作。相反,许多人期望 Promises 是 “lazy” 的,即仅在必要时调用(例如,当 then 方法在 Promise 上首次被调用)。这是一个误区,Promise 永远是 eager 的,而非 lazy 的。

但是,如果您想要延迟执行 Promise,应该怎么做?如果您希望延迟发出该 HTTP 请求怎么办?Promises 中是否内置了某种奇特的机制,可以让您执行类似的操作?

答案有时会超出开发者们的期望。函数是一种 lazy 机制。仅当程序员使用 () 语法显式调用它们时,才执行它们。仅仅定义一个函数实际上并不能做任何事情。因此,要使 Promise 成为 “lazy”, 最佳方法是将其简单地包装在函数中!

具体代码如下:

const createSomePromise = () => new Promise(resolve => {  // 创建 HTTP 请求  resolve(result);});

现在,我们将 Promise 构造函数的调用操作包装在一个函数中。事实上它还没有真正被调用。我们还将变量名从 somePromise 更改为 createSomePromise,因为它不再是一个 Promise 对象 —— 而是一个创建并返回 Promise 对象的函数。

Promise 构造函数(以及带有 HTTP 请求的回调函数)仅在执行该函数时被调用。因此,现在我们有了一个 lazy 的 Promise,只有在我们真正想要它执行时才去执行它。

此外,请注意,它还附带提供了另一种功能。我们可以轻松地创建另一个可以执行相同操作的 Promise 对象。

如果出于某些奇怪的原因,我们希望进行两次相同的 HTTP 请求并同时执行这些请求,则只需要两次调用 createSomePromise 函数。又或者,如果请求由于任何原因失败了,我们可以使用相同的函数重新请求。

这表明将 Promises 包装在函数(或方法)中非常方便,因此对于 JavaScript 开发人员来说,使用这种模式开发应该要变得很自然而然。

而讽刺的是,如果你阅读过我写的文章 Promises vs Observables ,你就会知道编写 Rx.js 的程序员经常会犯一个与此相反的错误。他们对 Observable 进行编码,就好像它们是 “eager”(与 Promises 一致),而实际上它们是 ”lazy“ 的。因此,将 Observables 封装在函数或方法中通常没有任何意义,实际上甚至是有害的。

“JavaScript中使用Promises的三个错误是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: JavaScript中使用Promises的三个错误是什么

本文链接: https://www.lsjlt.com/news/309807.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • JavaScript中使用Promises的三个错误是什么
    本篇内容介绍了“JavaScript中使用Promises的三个错误是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!将所有内容包装在 P...
    99+
    2023-06-27
  • JavaScript常见的五个内存错误是什么
    这篇文章主要介绍“JavaScript常见的五个内存错误是什么”,在日常操作中,相信很多人在JavaScript常见的五个内存错误是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JavaScript常见的...
    99+
    2023-06-26
  • Javascript中三个取整函数是什么及怎么使用
    今天小编给大家分享一下Javascript中三个取整函数是什么及怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获...
    99+
    2022-10-19
  • JavaScript中三个点号是什么意思
    这篇文章主要介绍“JavaScript中三个点号是什么意思”,在日常操作中,相信很多人在JavaScript中三个点号是什么意思问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”...
    99+
    2022-10-19
  • java中的错误是什么
    在Java中,根据错误性质将运行错误分为两大类:错误和异常。 (推荐学习:java课程)Java中的所有异常都是由Throwable类的子类生成的对象,所有的异常类都是Throwable类的子类或子类的子类。Thro...
    99+
    2021-08-15
    java入门 java
  • javascript运行错误号指的是什么意思
    本文小编为大家详细介绍“javascript运行错误号指的是什么意思”,内容详细,步骤清晰,细节处理妥当,希望这篇“javascript运行错误号指的是什么意思”文章能帮助大家解决疑惑,下面跟着小编的思路慢...
    99+
    2022-10-19
  • python中slice的三个参数是什么
    小编给大家分享一下python中slice的三个参数是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、slice()函数有三个参数:start:索引开始的位...
    99+
    2023-06-15
  • Linux新手容易犯的7个错误是什么
    本篇内容介绍了“Linux新手容易犯的7个错误是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!7. 选择错误的 Linux 发行版Lin...
    99+
    2023-06-16
  • php中401错误指的是什么
    本文小编为大家详细介绍“php中401错误指的是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“php中401错误指的是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。PHP 401错误码是指服务器拒绝访问...
    99+
    2023-07-05
  • linux中500错误指的是什么
    这篇文章主要讲解了“linux中500错误指的是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“linux中500错误指的是什么”吧!在linux中,500错误指的是“500 Intern...
    99+
    2023-07-02
  • CSS中容易犯的10个错误提示分别是什么
    这篇文章将为大家详细讲解有关CSS中容易犯的10个错误提示分别是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。即使是CSS高手,也难免在书写CSS代码的...
    99+
    2022-10-19
  • 网页设计中7个令人抓狂的错误是什么
    这期内容当中小编将会给大家带来有关网页设计中7个令人抓狂的错误是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。所有人都知道网页设计的重要性,糟糕的网页设计会给用户带来糟糕的体验,从而影响网页的流量,或...
    99+
    2023-06-10
  • Vue3使用需要避免的错误是什么
    本篇内容主要讲解“Vue3使用需要避免的错误是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Vue3使用需要避免的错误是什么”吧!使用Reactive声明原始值数据声明在过去都是非常直接的,...
    99+
    2023-07-06
  • 服务器租用的三大误解是什么
    服务器租用的三大误解是:1、认为租用的服务器要失去数据管理权,用户的可访问性和控制权取决于服务器供应商和所选择的服务类型;2、认为云服务器更加靠谱,租用服务器支持定制和完全访问,具备更高水平的质量支持;3、认为服务器租用不如自建机房划算,租...
    99+
    2022-10-10
  • 服务器租用的三大误区是什么
    服务器租用的三大误区是:1、没有对租用服务器数据的管理权,服务器租用会为用户提供控制权和访问权;2、认为云服务器更加靠谱,服务器租用能提供自行搭建共享环境进行分配,单独的专业售后服务,是云服务器不能实现的;3、认为服务器租用不如自建机房划算...
    99+
    2022-10-05
  • es6中三个点指的是什么意思
    这篇文章给大家分享的是有关es6中三个点指的是什么意思的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。 在es6中,三个点“...”指的是“扩展运算符”...
    99+
    2022-10-19
  • Golang中最常见的错误是什么
    这篇文章主要介绍“Golang中最常见的错误是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Golang中最常见的错误是什么”文章能帮助大家解决问题。一、类型错误类型错误是Golang中最常见的...
    99+
    2023-07-05
  • mysql中报错序号对应的是什么错误
    不知道大家之前对类似mysql中报错序号对应的是什么错误的文章有无了解,今天我在这里给大家再简单的讲讲。感兴趣的话就一起来看看正文部分吧,相信看完mysql中报错序号对应的是什么错误你一定会有所收获的。&n...
    99+
    2022-10-18
  • php错误日志的作用是什么
    这篇文章主要介绍了php错误日志的作用是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在php中,错误日志用于记录程序运行时的出错信息,可以帮助开发人员或者管理人员查看系...
    99+
    2023-06-29
  • Elasticsearch常见的5个错误及解决策略是什么
    这期内容当中小编将会给大家带来有关Elasticsearch常见的5个错误及解决策略是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1、采用动态Mapping如果不定义Mapping,Elastics...
    99+
    2023-06-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作