thenPromise 5.1.2

thenPromise 5.1.2

测试已测试
语言语言 SwiftSwift
许可 MIT
发布最新发布2019年12月
SPM支持SPM

s4cha 维护。



Then

then

Language: Swift 5 Platform: iOS 8+/macOS10.11 SPM compatible Carthage compatible Cocoapods compatible Build Status codebeat badge License: MIT Release version

原因 - 示例 - 文档 - 安装

fetchUserId().then { id in
    print("UserID : \(id)")
}.onError { e in
    print("An error occured : \(e)")
}.finally {M
    print("Everything is Done :)")
}
  let userId = try! await(fetchUserId())

因为异步代码难以编写,难以阅读,难以理解。 维护起来很痛苦

试试看

then是freshOS iOS工具集的一部分。在一个示例应用中试试! 下载起始项目

如何

使用一个then关键字,您可以通过它编写出类似英语句子的异步代码
异步代码现在更简洁灵活易于维护❤️

什么是

  • 基于流行的Promise/Future概念
  • Async/Await
  • progress race recover validate retry bridgeError chain noMatterWhat ...
  • 强类型
  • 纯Swift & 轻量级

示例

之前

fetchUserId({ id in
    fetchUserNameFromId(id, success: { name in
        fetchUserFollowStatusFromName(name, success: { isFollowed in
            // The three calls in a row succeeded YAY!
            reloadList()
        }, failure: { error in
            // Fetching user ID failed
            reloadList()
        })
    }, failure: { error in
        // Fetching user name failed
        reloadList()
    })
}) {  error in
    // Fetching user follow status failed
    reloadList()
}
🙉🙈🙊#callbackHell

之后

fetchUserId()
    .then(fetchUserNameFromId)
    .then(fetchUserFollowStatusFromName)
    .then(updateFollowStatus)
    .onError(showErrorPopup)
    .finally(reloadList)

🎉🎉🎉

更进一步🤓

fetchUserId().then { id in
    print("UserID : \(id)")
}.onError { e in
    print("An error occured : \(e)")
}.finally {
    print("Everything is Done :)")
}

如果我们要让它可维护,它应读起来像一句英语句子
我们可以通过将我们的块抽取为单独的函数来做此事

fetchUserId()
    .then(printUserID)
    .onError(showErrorPopup)
    .finally(reloadList)

现在它变得更简洁、更灵活、更可维护,并且读起来像一句英文句子 <3
精神健康保存 // #goodbyeCallbackHell

文档

  1. 编写自己的Promise
  2. 进度
  3. 注册块以供稍后使用
  4. 返回拒绝的Promise
  5. 常用辅助工具
  6. race
  7. recover
  8. validate
  9. retry
  10. bridgeError
  11. whenAll
  12. chain
  13. noMatterWhat
  14. unwrap
  15. AsyncTask
  16. Async/Await

编写自己的Promise💪

想知道fetchUserId()是什么吗?
它是一个简单的函数,返回一个强类型的Promise

func fetchUserId() -> Promise<Int> {
    return Promise { resolve, reject in
        print("fetching user Id ...")
        wait { resolve(1234) }
    }
}

在这里,您通常会替换示例等待函数为您的网络请求 <3

进度

至于 thenonError,也可以为上传头像等行为调用 progress 块。

uploadAvatar().progress { p in
  // Here update progressView for example
}
.then(doSomething)
.onError(showErrorPopup)
.finally(doSomething)

后续注册块

我们的实现与原始 JavaScript Promise 略有不同。确实,它们不会立即启动,这是故意的。调用 thenonErrorfinally 将自动启动它们。

调用 then 将启动承诺(如果尚未启动)。在某些情况下,我们只想为以后注册一些代码。例如,在 JSON 到 Swift 模型解析的情况下,我们通常想将解析块附加到 JSON 承诺,但又不启动它们。

为了做到这一点,我们需要使用 registerThen。它与 then 完全相同,只是不会立即启动承诺。

let fetchUsers:Promise<[User]> = fetchUsersJSON().registerThen(parseUsersJSON)

// Here promise is not launched yet \o/

// later...
fetchUsers.then { users in
    // YAY
}

请注意,onErrorfinally 也分别有它们的不启动对应者:registerOnErrorregisterFinally

返回拒绝承诺

有时我们需要返回一个拒绝承诺,例如:

return Promise { _, reject in
  reject(anError)
}

这可以用以下快捷方式来表示:

return Promise.reject(error:anError)

公用助手

赛跑

使用 race,你可以发送多个任务,并得到第一个返回的任务的结果。

race(task1, task2, task3).then { work in
  // The first result !
}

恢复

使用 .recover,您可以为失败的Promise提供一个回退值。
您可以

  • 用值恢复
  • 为特定的错误类型恢复值
  • 从块中返回一个值,使您能够测试错误的类型并返回不同的值。
  • 用同一类型的另一个Promise恢复
.recover(with: 12)
.recover(MyError.defaultError, with: 12)
.recover { e in
  if e == x { return 32 }
  if e == y { return 143 }
  throw MyError.defaultError
}
.recover { e -> Promise<Int> in
  // Deal with the error then
  return Promise<Int>.resolve(56)
  // Or
  return Promise<Int>.reject(e)
  }
}
.recover(with: Promise<Int>.resolve(56))

注意,在块版本中,您还可以抛出自己的错误 \o/

验证

使用 .validate,您可以通过断言块断开Promise链。

您可以

  • 将断言插入Promise链
  • 插入断言并返回自己的Error

例如,检查用户是否有权饮酒

fetchUserAge()
.validate { $0 > 18 }
.then { age in
  // Offer a drink
}

.validate(withError: MyError.defaultError, { $0 > 18 })`

默认情况下,失败的验证将返回 PromiseError.validationFailed

重试

使用 retry,您可以将失败的Promise重试X次。

doSomething()
  .retry(10)
  .then { v in
   // YAY!
  }.onError { e in
    // Failed 10 times in a row
  }

BridgeError

使用 .bridgeError,您可以拦截低级别的错误并返回自己的高级错误。经典用例是您收到一个API错误并将其桥接到自己的域错误。

您可以

  • 捕获所有错误并使用自己的Error类型
  • 只捕获特定错误
.bridgeError(to: MyError.defaultError)
.bridgeError(SomeError, to: MyError.defaultError)

WhenAll

使用 .whenAll,您可以组合多个调用,并在所有Promise完成时获取所有结果。

whenAll(fetchUsersA(),fetchUsersB(), fetchUsersC()).then { allUsers in
  // All the promises came back
}

使用 chain,可以在不改变 Promise 链的情况下添加行为。

一个常见的用例是添加Analytics跟踪,如下所示

extension Photo {
    public func post() -> Async<Photo> {
        return api.post(self).chain { _ in
            Tracker.trackEvent(.postPicture)
        }
    }
}

无所不为

使用 noMatterWhat,你可以在 Promise 链的中间添加无论发生什么都会被执行的代码。

func fetchNext() -> Promise<[T]> {
    isLoading = true
    call.params["page"] = page + 1
    return call.fetch()
        .registerThen(parseResponse)
        .resolveOnMainThread()
        .noMatterWhat {
            self.isLoading = false
    }
}

展开

使用 unwrap,可以将可选项转换为 Promise

func fetch(userId: String?) -> Promise<Void> {
   return unwrap(userId).then {
        network.get("/user/\($0)")
    }
}

如果遇到 nil 值,展开会使用 unwrappingFailed 错误失败 Promise 链 :)

异步任务

AsyncTaskAsync<T> 类型别名适用于那些认为 Async 比Promise 更清晰的人。请在实际需要的地方将 Promise<Void> 替换为 AsyncTask,将 Promise<T> 替换为 Async<T>
这是纯粹为了视觉效果 :)

Async/Await

await 同步等待一个 Promise 完成,并返回结果

let photos = try! await(getPhotos())

async 取一个块,并将其包装在一个后台 Promise 中。

async {
  let photos = try await(getPhotos())
}

注意我们不再需要 !,因为 async 会捕获错误。

一起,async/await 使我们能够以同步的方式编写异步代码

async {
  let userId = try await(fetchUserId())
  let userName = try await(fetchUserNameFromId(userId))
  let isFollowed = try await(fetchUserFollowStatusFromName(userName))
  return isFollowed
}.then { isFollowed in
  print(isFollowed)
}.onError { e in
  // handle errors
}

等待操作符

等待可以使用 .. 简写运算符。而 ..? 将回退到空值,而不是抛出错误。

let userId = try await(fetchUserId())

可以写成这样

let userId = try ..fetchUserId()

安装

Swift 包管理器

要在 Xcode 11 项目中通过 SPM 指定,请访问项目 > Swift 包。

https://github.com/freshOS/then

CocoaPods

target 'MyApp'
pod 'thenPromise'
use_frameworks!

Carthage

github "freshOS/then"

手动操作

简单地将 .swift 文件复制粘贴到您的 Xcode 项目中 :)

作为框架

获取此存储库并在示例项目中构建框架目标。然后链接到此框架。

贡献者

S4chaMax KonovalovYannickDotDamienpiterlouis

Swift 版本

  • Swift 2 -> 版本 1.4.2
  • Swift 3 -> 版本 2.2.5
  • Swift 4 -> 版本 3.1.0
  • Swift 4.1 -> 版本 4.1.1
  • Swift 4.2 -> 版本 4.2.0
  • Swift 4.2.1 -> 版本 4.2.1
  • Swift 5.0 -> 版本 5.0.0
  • Swift 5.1 -> 版本 5.1.0
  • Swift 5.1.3 -> 版本 5.1.2

赞助商

喜欢这个项目?请提供咖啡或通过每月捐赠来支持我们,帮助我们继续活动 :)

赞助商

成为赞助商,让你的标志出现在我们的 Github README 上,并提供你的网站的链接 :)