ThenAsync 5.0.0

ThenAsync 5.0.0

arden维护。



ThenAsync 5.0.0

Then

then

Language: Swift 2 and 3|4 Platform: iOS 8+/macOS10.11 Carthage compatible Cocoapods compatible Build Status codebeat badge Join the chat at https://gitter.im/s4cha/then License: MIT Release version

原因 - 示例 - 文档 - 安装

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

因为异步代码难以编写,难以阅读,难以推理。 难以维护

尝试

Then 是 freshOS iOS 工具集的一部分。在一个示例 App 中尝试使用它!下载 Starter Project

如何

通过使用一个 then 关键字,使得您可以编写像英语句子一样易于阅读的 aSync 代码
异步代码现在更加 简洁灵活易于维护❤️

是什么

  • 基于流行的 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 Promises略有不同。实际上,它们不是立即启动的,这是故意的。调用thenonErrorfinally将自动启动它们。

调用then开始一个正在进行的promise,如果它尚未开始。在某些情况下,我们只想注册一些后续代码。例如,在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提供回滚值。
您可以

  • 用值来恢复
  • 为特定的错误类型指定恢复值
  • 从块中返回一个值,允许您测试错误类型并返回不同的值。
  • 使用相同类型的另一个Promises来恢复
.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链中插入断言
  • 插入断言并返回您自己的错误

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

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,您可以拦截底层错误并返回自己的高级别错误。经典的用例是当您收到API错误并将它桥接到自己的域名错误。

您可以

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

当所有...

使用.whenAll,您可以组合多个调用,并在所有Promise都解决后获取所有结果

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

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

一个常见的用例是添加如下分析跟踪

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

不论什么

使用 不论什么,您可以在承诺链的中间添加要执行的代码,无论发生什么。

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

展开

使用 展开,您可以将可选类型转换为承诺

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

如果值为 nil,展开将使用 展开失败 错误使承诺链失败 :)

异步任务

AsyncTaskAsync<T> 类型别名供我们使用,我们认为异步标识符比 Promise 更清晰。在需要的地方,您可以自由地将 Promise<Void> 替换为 AsyncTask,将 Promise<T> 替换为 Async<T>
这只是为了视觉效果 :)

异步/等待

await 等待承诺同步完成并返回结果

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
}

等待操作符

Await 操作符带有 .. 简写运算符。当使用 ..? 时,将回退到 nil 值而不是抛出异常。

let userId = try await(fetchUserId())

可以写成这样

let userId = try ..fetchUserId()

安装

CocoaPods

target 'MyApp'
pod 'thenPromise'
use_frameworks!

Carthage

github "freshOS/then"

手动安装

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

作为一个框架

下载此存储库,并在示例项目上构建 Framework 目标。然后,链接到该框架。

贡献者

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.0

支持者

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

赞助商

成为赞助商,可在 Github 的 README 上的我们的标志下面获得链接到您的网站:)