余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

在 Promise 方面的一些探索(谈谈对promise的理解)

xiyangw 2022-12-03 13:21 12 浏览 0 评论

英文原文发布时间较早,故原文代码中的 Swift 版本较旧,但是作者已将 GitHub 上的 Promise 示例代码 更新到了最新 Swift 版本,所以译者在翻译本文时,将文章里的代码按照 GitHub 上的示例代码进行了替换,更新成了最新版本的 Swift 代码。

上周,我写了一篇介绍 Promise 的文章,Promise 是处理异步操作的高阶模块。只需要使用 fulfill() 、 reject() 和 then() 等函数,就可以简单自由地构建大量的功能。本文会展示我在 Promise 方面的一些探索。

在 Promise 方面的一些探索(谈谈对promise的理解)

Promise.all

Promise.all 是其中的典型,它保存所有异步回调的值。这个静态函数的作用是等待所有的 Promise 执行 fulfill(履行) ,一旦全部执行完毕, Promise.all 会使用所有履行后的值组成的数组对自己执行 fulfill。例如,你可能想在代码中对数组中的每个元素打点以捕获某个 API 的完成状态。使用 map 和 Promise.all 很容易实现:

let userPromises = users.map({ user in

要使用 Promise.all ,需要首先创建一个新的 Promise,它代表所有 Promise 的组合状态,如果参数中的数组为空,可以立即执行 fulfill。

public static func all<T>(_ promises: [Promise<T>]) -> Promise<[T]> { return Promise<[T]>(work: { fulfill, reject in

在这个 Promise 内部,遍历每个子 Promise,并分别为它们添加成功和失败的处理流程。一旦有子 Promise 执行失败了,就可以拒绝高阶的 Promise。

for promise in promises {

只有当所有的 Promise 都执行成功,才可以 fulfill 高阶的 Promise。检查一下以确保没有一个 Promise 被拒绝或者挂起,使用一点点 flatMap 的魔法,就可以对 Promise 的组合执行 fulfill 操作了。完整的方法如下:

public static func all<T>(_ promises: [Promise<T>]) -> Promise<[T]> { return Promise<[T]>(work: { fulfill, reject in

请注意,Promise 只能履行或者拒绝一次。如果第二次调用 fulfill 或者 reject ,不会对 Promise 的状态造成任何影响。

因为 Promise 是状态机,它保存了与完成度有关的重要状态。它是一种不同于 NSOperation 的方法。虽然 NSOperation 拥有一个完成回调以及操作的状态,但它不能保存得到的值,你需要自己去管理。

NSOperation 还持有线程模型以及优先级顺序相关的数据,而 Promise 对代码 如何 完成不做任何保证,只设置 完成后 需要执行的代码。Promise 类的定义足以证明。它唯一的实例变量是 state ,状态包括挂起、履行或者拒绝(以及对应的数据),此外还有一个回调数组。(它还包含了一个隔离队列,但那不是真正的状态。)

delay

有一种很有用的 Promise 可以延迟执行自己的操作。

public static func delay(_ delay: TimeInterval) -> Promise<()> { return Promise<()>(work: { fulfill, reject in

在方法内部,可以使用 usleep 或者其他方法来实现延迟,不过 asyncAfter 方法足够简单。当构建其他有趣的 Promise 时,这个延迟 Promise 会很有用。

timeout

接下来,使用 delay 来构建 timeout 。该 Promise 如果超过一定时间就会被拒绝。

public static func timeout<T>(_ timeout: TimeInterval) -> Promise<T> { return Promise<T>(work: { fulfill, reject in

这个 Promise 自身没有太多用处,但它可以帮助我们构建一些其他功能的 Promise。

race

Promise.race 是 Promise.all 的小伙伴,它不需要等待所有的子 Promise 完成,它只履行或者拒绝第一个完成的 Promise。

public static func race<T>(_ promises: [Promise<T>]) -> Promise<T> { return Promise<T>(work: { fulfill, reject in

因为 Promise 只能被执行或拒绝一次,所以当移除了 .pending 的状态后,在外部对 Promise 调用 fulfill 或者 reject 不会产生任何影响。

有了这个函数,使用 timeout 和 Promise.race 可以创建一个新的 Promise,针对成功、失败或者超过了规定时间三种情况。把它定义在 Promise 的扩展中。

public func addTimeout(_ timeout: TimeInterval) -> Promise<Value> { return Promise.race(Array([self, Promise<Value>.timeout(timeout)]))

可以在正常的 Promise 链中使用它,像下面这样:

APIClient

这是我喜欢 Promise 的原因之一,它们的可组合性使得我们可以轻松地创建各种行为。通常需要保证 Promise 在 某个时刻 被履行或者拒绝,但是 timeout 函数允许我们用常规的方式来修正这种行为。

recover

recover 是另一个有用的函数。它可以捕获一个错误,然后轻松地恢复状态,同时不会弄乱其余的 Promise 链。

我们很清楚这个函数的形式:它应该接受一个函数,该函数中接受错误并返回新的 Promise。recover 方法也应该返回一个 Promise 以便继续链接 Promise 链。

extension Promise {

在方法体中,需要返回一个新的 Promise,如果当前的 Promise( self )执行成功,需要把成功状态转移给新的 Promise。

public func recover(_ recovery: @escaping (Error) throws -> Promise<Value>) -> Promise<Value> { return Promise(work: { fulfill, reject in

然而, catch 是另一回事了。如果 Promise 执行失败,应该调用提供的 recovery 函数。该函数会返回一个新的 Promise。无论 recovery 中的 Promise 执行成功与否,都要把结果返回给新的 Promise。

//...do {

完整的方法如下:

public func recover(_ recovery: @escaping (Error) throws -> Promise<Value>) -> Promise<Value> { return Promise(work: { fulfill, reject in

有了这个新的函数就可以从错误中恢复。例如,如果网络没有加载我们期望的数据,可以从缓存中加载数据:

APIClient.getUsers()

retry

重试是我们可以添加的另一个功能。若要重试,需要指定重试的次数以及一个能够创建 Promise 的函数,该 Promise 包含了重试要执行的操作(所以这个 Promise 会被重复创建很多次)。

public static func retry<T>(count: Int, delay: TimeInterval, generate: @escaping () -> Promise<T>) -> Promise<T> { if count <= 0 { return generate()
  • 如果数量不足 1,直接生成 Promise 并返回。

  • 否则,创建一个包含了需要重试的 Promise 的新的 Promise,如果失败了,在 delay 时间之后恢复到之前的状态并重试,不过此时的重试次数减为 count - 1 。

基于之前编写的 delay 和 recover 函数构建了重试的函数。

在上面的这些例子中,轻量且可组合的部分组合在一起,就得到了简单优雅的解决方案。所有的这些行为都是建立在 Promise 核心代码所提供的简单的 .then 和 catch 函数上的。通过格式化完成闭包的样式,可以解决诸如超时、恢复、重试以及其他可以通过简单可重用的方式解决的问题。这些例子仍然需要一些测试和验证

相关推荐

JavaScript ES2019 中的 8 个新功能(javascript 菜鸟教程)
JavaScript ES2019 中的 8 个新功能(javascript 菜鸟教程)

JavaScript一直在不断改进和添加更多新功能。TC39已经完成,并批准了ES2019的8项新功能。这个过程包含了5个阶段:第0阶段:稻...

2023-03-21 19:30 xiyangw

JavaScript 对象可以做到的三件事(在浏览器上运行javascript程序,可以)

除了普通的对象属性赋值和遍历之外,我们还可以使用JavaScript对象执行许多其他操作。在本文中,我们将了解如何使用它们,包括访问内部属性、操作属性描述符和继承只读属性。1.访问内部属性Jav...

冰与火之歌:JavaScript 的困境与挑战(冰与火之舞url)
冰与火之歌:JavaScript 的困境与挑战(冰与火之舞url)

最近几年以来,伴随着各个端平台的迅猛发展,以TypeScript、Swift、Kotlin和Dart为代表的新一代应用编程语言纷纷浮现。群雄环伺之下,J...

2023-03-21 19:30 xiyangw

JavaScript每年更新一个版本,功能越来越强大,能用JS的终将用JS
JavaScript每年更新一个版本,功能越来越强大,能用JS的终将用JS

不做详细功能介绍ES2015(ES6)带来的重大特性Arrowfunctions(箭头函数)PromisesGeneratorslet和const...

2023-03-21 19:30 xiyangw

IT技术分享:浅谈JavaScript作用域(js有哪些作用域,分别是什么意思)
IT技术分享:浅谈JavaScript作用域(js有哪些作用域,分别是什么意思)

javascript是目前web领域中使用非常广泛的语言,不管是在前端还是在后端都能看到它的影子,可以说web从业者不论怎样都绕不开它。在前端领域,各种框架层出...

2023-03-21 19:29 xiyangw

软件测试 | JavaScript如何使用(javascript自动测试框架)

简介JavaScript是脚本语言,是一种轻量级的编程语言,可以插入HTML页面的编程代码。插入HTML页面后,可由所有的现代浏览器执行。作用JavaScript可以直接写入HTML输...

高性能的JavaScript,这是一个高级程序员必备的技能
高性能的JavaScript,这是一个高级程序员必备的技能

不知道大家有没有看过高性能JavaScript,这个书是一本好书,推荐有JavaScript的基础的同学可以看一看这本书.下面是我根据这本书整理出来的知识:1、...

2023-03-21 19:28 xiyangw

javascript:5分钟了解javascript,就能上手(javascript环境配置)
javascript:5分钟了解javascript,就能上手(javascript环境配置)

javascript一.js组成部分ECMA:文档对象类型:(DOM)documentobjectmodule浏览器对象类型:(BOM)broswe...

2023-03-21 19:28 xiyangw

JavaScript 使用(javascript 原型)
JavaScript 使用(javascript 原型)

JavaScript使用<script>标签在HTML中,JavaScript代码必须位于<script>与</s...

2023-03-21 19:28 xiyangw

JavaScript的前景一片光明(js在前端设计中的作用)
JavaScript的前景一片光明(js在前端设计中的作用)

JavaScript的未来很光明,该语言确实正在打破浏览器的壁垒,许多开发人员看到JavaScript的服务器端实现,入node.js,从而可以使用一种语言编...

2023-03-21 19:27 xiyangw

第4节 使用Javascript(javascript基本语法学习四)
第4节 使用Javascript(javascript基本语法学习四)

如果使用JavaScript,在哪里使用JavaScript?这节课我们来研究这些知识点。在哪里使用:在<script>中嵌入,向HTML页面中插入...

2023-03-21 19:27 xiyangw

我的 JavaScript,比你的 Rust 更快(rust vs javascript)
我的 JavaScript,比你的 Rust 更快(rust vs javascript)

JoshUrbane是一位从业多年的软件架构师,很喜欢在社交媒体分享技术观点。近日,他写了一篇文章,记录了自己凭借经验赢了与新人开发者打赌的故事,而“我的...

2023-03-21 19:27 xiyangw

javascript简介(javascript简介ppt)
javascript简介(javascript简介ppt)

javascript诞生于1995年。当时,它的主要目的是处理以前由服务器端语言(如php)负责的一些输入验证操作。在javascript问世之前,必须把表单...

2023-03-21 19:25 xiyangw

JavaScript介绍(javascript简介)

JavaScript是运行在浏览器端的脚步语言,JavaScript主要解决的是前端与用户交互的问题,包括使用交互与数据交互。JavaScript是浏览器解释执行的,前端脚本语言还有JScript(...

为什么我喜欢JavaScript?(为什么我喜欢闻姨妈血的味道)
为什么我喜欢JavaScript?(为什么我喜欢闻姨妈血的味道)

每个开发人员都有自己喜欢的语言。继续读下去,看看为什么这个开发人员喜欢JavaScript,尽管有些奇怪的部分已经让其他人放弃了它。学习如何使用Crafter...

2023-03-21 19:24 xiyangw

取消回复欢迎 发表评论: