首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

所谓的“承诺”

可能反正我写的东西有些枯燥,但是久而久之,功力一定深厚,所以会比较小众,坚持写,写到天荒地老。坚持翻译好文。

让我们回到介绍一章中提到的问题:回调:我们有一个异步任务序列一个接一个地执行——例如,加载脚本。我们怎样才能把它写好呢?

Promise 提供了一些方法来做到这一点。

在本章中,我们将讨论 Promise chaining。

它是这样的:

其思想是通过.then处理程序链传递结果。

这里的流程是:

初始 Promise 在1秒内解决(*),

然后 then 处理程序被调用(**)。

它返回的值被传递给下一个 .then 处理程序(***)

当结果沿着处理程序链传递时,我们可以看到警报调用的序列:124。

整件事都成功了,因为一个 Promise 回调。然后返回一个 Promise,这样我们就可以在它上调用下一个.then。

当处理程序返回一个值时,它将成为该 Promise 的结果,因此下一个.then将随之调用。

一个典型的新手错误:技术上,我们也可以在一个 promise 中添加多个 .then。这不是连锁反应。

例如:

我们在这里所做的只是一个 Promise 的几个处理程序。它们不会相互传递结果;相反,他们会独立处理。

所有。然后在相同的 Promise 上得到相同的结果-那个 Promise 的结果。因此,在上述代码中,所有警报显示相同的:

在实践中,我们很少需要对一个 Promise 使用多个处理程序。链接更常用。

Returning promises

在.then(handler)中使用的处理程序可以创建并返回 promise。

在这种情况下,进一步的处理程序会等待,直到它安定下来,然后得到它的结果。

例如:

在这里,第一个 .then 显示了1,并在(*)行中返回新的 Promise(…)。一秒钟后,它进行解析,结果 (resolve的参数,这里是result * 2) 被传递给第二个 .then 的处理器。该处理程序在(**)行中,它显示2并执行相同的操作。

因此输出与前面的示例相同:124,但现在警报调用之间有1秒的延迟。

返回 Promise 允许我们构建异步操作链。

Example: loadScript

让我们在上一章定义的promisified loadScript中使用这个特性,按顺序逐个加载脚本:

这段代码可以用箭头函数简化:

在这里,每个loadScript调用返回一个承诺,下一个.then在解析时运行。然后,它开始加载下一个脚本。脚本一个接一个地加载。

我们可以向链中添加更多的异步操作。请注意,代码仍然是“平的”-它向下增长,而不是向右。没有“末日金字塔”的迹象。

技术上,我们可以直接在每个loadScript中添加.then,就像这样:

这段代码做了同样的事情:依次加载3个脚本。但它“向右生长”。我们有和回调一样的问题。

开始使用 Promise 的人有时不知道链接,所以他们这样写。一般来说,链接是首选。

有时直接编写 .then 是可以的,因为嵌套函数可以访问外部作用域。在上面的例子中,嵌套最多的回调函数可以访问所有变量script1、script2、script3。但这是一个例外,而不是规律。

Thenables

确切地说,处理程序可能返回的不是一个promise,而是一个所谓的“thenable”对象——一个具有方法的任意对象。它会像承诺一样被对待。

其思想是,第三方库可以实现它们自己的“承诺兼容”对象。它们可以拥有一组扩展的方法,但也与本机承诺兼容,因为它们实现了.then。

下面是一个可执行对象的例子:

JavaScript 检查行(*)中.then处理程序返回的对象:如果它有一个名为then的可调用方法,那么它调用该方法,提供本地函数resolve,拒绝作为参数(类似于executor),并等待直到其中一个被调用。在上面的例子中,resolve(2)在1秒(**)之后被调用。然后,结果将沿着链向下传递。

这个特性允许我们将自定义对象与promise链集成在一起,而不必从promise继承。

Bigger example: fetch

在前端编程中,承诺通常用于网络请求。我们来看一个扩展的例子。

我们将使用fetch方法从远程服务器加载关于用户的信息。它有很多可选的参数,在单独的章节中介绍过,但是基本的语法非常简单:

468/5000这将向url发出一个网络请求并返回一个承诺。当远程服务器以头响应时,但在下载完整响应之前,promise将使用响应对象进行解析。

要读取完整的响应,我们应该调用response.text()方法:它返回一个承诺,当从远程服务器下载全文时解析该文本,结果是该文本。

下面的代码向用户发出请求。json并从服务器加载它的文本:

从fetch返回的响应对象还包括response. JSON()方法,该方法读取远程数据并将其解析为JSON。在我们的例子中,这更方便,所以我们切换到它。

为了简洁起见,我们还将使用箭头函数:

现在让我们对加载的用户做一些事情。

例如,我们可以再向GitHub发出一个请求,加载用户配置文件并显示头像:

代码的作品;请参阅有关细节的评论。然而,这里面有一个潜在的问题,对于那些开始使用 Promise 的人来说,这是一个典型的错误。

看看这一行(*):在角色完成展示并被移除后,我们该如何做些事情?例如,我们想要显示一个用于编辑该用户或其他东西的表单。就目前而言,不可能。

为了使链可扩展,我们需要返回一个 Promise ,它可以解决化身何时结束显示的问题。

是这样的:

也就是说,行(*)中的.then处理程序现在返回新的承诺,只有在setTimeout(**)中调用resolve(githubUser)之后才会得到解决。下一个 .then 在链中等待它。

作为一种良好的实践,异步操作应该总是返回promise。这使得我们有可能在事件发生后制定行动计划;即使我们现在不打算扩展这条链,我们以后可能会需要它。

Summary

如果.then(或catch/finally,没关系)处理程序返回promise,则链上的其余部分将等待直到它解决。当它这样做时,它的结果(或错误)将进一步传递。

以下是全貌:

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20210217A02R7T00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券