Swift之深入解析如何实现Promise

发布时间:2022-07-02 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Swift之深入解析如何实现Promise脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

一、前言

  • 异步编程是开发 App 的一个难点,多线程操作,线程的切换,多层嵌套 callback,使得代码十分的混乱,难以理解。
func load(_ callback: (Value) -> Void) {
     loadService.load { result in
         let saveableITem = result.transFromToSaveableitem
         saveQueue.async {
              saveService.save(saveableItem) { saved in
                  let displayableItem = saved.tranfromToDisplayableItem
                   mainQueue.async {
                       callback(displayableItem)
                   }              
              }
         }
     }
}
  • Github 有很多直接或者间接能解决这个问题的方案,比如 RxSwift 等函数响应式编程框架,通过 observeOn,可以轻松的切换线程,并且使用 map,flatmap 等操作符链式的操作结果,可以让我们轻松的写出结构清晰的代码。具体可以参考我的专栏F1a;RAC+RxSwift。
  • PRomise 是一种链接异步任务的方式,有三大要素
    • 保存当前状态的 state;
    • 保存回调函数的 Callbacks;
    • 控制线程安全的方式。
  • 通常来说,异步任务会在异步操作完成时执行回调闭包(有时候要准备两个闭包,一个代表成功,一个代表失败)。要执行多个异步操作,必须将第二个异步操作放在第一个异步操作的完成闭包中执行:
APIClient.fetchcurrentUser(success: { currentUser in
	APIClient.fetchFollowers(user: currentUser, success: { followers in
		// 得到一个 followers 数组
	}, failure: { error in
		// 错误处理
	})
}, failure: { error in
	// 错误处理
})
  • Promise 的作用是格式化完成闭包,简化链式异步调用的形式。如果系统能够分辨成功和失败,那么组合这些异步操作就变得容易很多。比如,编写具有下列功能的可重用代码:
    • 使用尾闭包执行一系列依赖关系的异步操作;
    • 通过一个完成闭包同时执行多个独立的异步操作;
    • 多个异步操作竞争,返回第一个完成的值;
    • 重试异步操作;
    • 为异步操作设置超时时间。
  • 如上代码转换为 Promise 样式如下:
APIClient.fetchCurrentUser().then({ currentUser in
	return APIClient.fetchFollowers(user: currentUser)
}).then({ followers in
	// you now have an array of followers
)}.onFailure({ error in
	// hooray, a single failure block!
})
  • 可能你也注意到了,Promise 是将嵌套/缩进样式的代码变成一个层级的代码:Promise 是一个 Monad。
  • Promise 在 JavaScript 社区中反响热烈,因为 Node.js 的设计中包含了非常多异步操作,即便是简单的任务也需要用到链式的异步回调,即便只有三四个这样的操作,代码会变得笨重。Promise 终结了提心吊胆写回调的日子,Promise 已经写进了 JavaScript ES6 的规范。JavaScript Promise 的运作机制请参考:JavaScript Promises … in Wicked Detail。
  • JavaScript Promise 实现的一个亮点是它有一个非常明确的规范,称为 A+,具体详情可以在 promisejs.org查看,这意味着依赖 JavaScript 的弱类型系统,多个 Promise 的实现可以融合,彼此之间可以互相操作。只要 Promise 中的 then 函数定义符合规范,它就可以和其他库中的 Promise 连接,这实在是太棒了。
  • A+ 规范有一个非常好的 API,不使用 monad 中那个命名简单且易于理解的 then 方法(在 A+ 规范中被重构为 flatMap 和 map)。不过这个 API 不适合每个人,但我真的很喜欢它,并开始在 Swift 中实现一个类似的库。你可以在 Github 的 Promise 上找个到这个库,编写的过程很具有启发性。

二、枚举

  • 大家都知道,枚举非常棒,因为 Promise 本质上是状态机,所以枚举用在这里非常合适。JavaScript Promise 实现的参考如下所示:
VAR PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {
  // 保存 PENDING, FULFILLED 或者 REJECTED 的状态
  var state = PENDING;

  // 当出现 FULFILLED 或 REJECTED 状态时保存值或者错误
var value = null;

  // 保存被 .then 或者 .done 函数触发的成功 & 失败的处理操作
  var handlers = [];
}
  • 应该是找不到比 Swift 的枚举实现更完美的例子了,如下,是 Swift 中的实现:
enum State<Value> {
    case pending
    case fulfilled(value: Value)
    case rejected(error: ErrorType)
}

final class Promise<Value> {    
    private var state: State<Value>
    private var callbacks: [Callback<Value>] = []
}
  • 外部数据依赖于 Promise 的具体状态,所以被封装到对应 case 的关联值中。当 Promise 处于 .pending 状态时,任何外部数据都没有意义,枚举在类型系统中表达出的语义是不可思议的。唯一要批判的是泛型不能被嵌套进其它类型中,并且这个缺陷在 Swift 3 中不会更改,具体请参考:Nested generic type in function is not Allowed

三、类型系统

  • 创建一个新的 JavaScript Promise 时,可以使用便捷构造器:
var promise = new Promise(function(resolve, reject) {
	someAsyncRequest(function(error, result) {
		if (error) {
			reject(error);
		}
		resolve(result);
	});
});
  • 传入了一个包含两个其它函数的函数,主要有两个功能:第一个函数参数对应 Promise 操作成功的情况,第二个对应了失败的情况。这两个函数的顺序很重要,因为 JavaScript 不是类型安全的,如果在上面的第一行代码中写错了顺序,写成了 reject, resolve,很容易就向 resolve 函数中引入了错误。另一方面,Swift 是类型安全的,这意味着 reject 函数的类型是 (ErrorType) -> Void),该函数不会被成功的结果所接受,所以再也不用担心弄乱 reject 和 resolve 函数的顺序。

四、太多的类型可能会令人沮丧

  • Promise 的类型中使用了泛型 Value,这是它的内部值类型,意味着可以通过类型推断而不用指定具体的类型:
let promise = Promise(value: "initialValue") // a fulfilled Promise<String>
  • 因为 Promise 经常被链式调用,依靠类型推断来确定类型将会特别有用,必须向链中的每个步骤添加明确的类型是件令人沮丧的事,最终的样式也不是很有 Swift 的风格:
let promise = Promise<String, APIError>(value: "initialValue")
  • 这使得一行简单的代码增加了很多不必要的包袱,所以我删除了指定错误类型的功能。不幸的是,删除显式的错误类型意味着不得不失去一个小小的类型系统的优势。假设使用了一个叫 NoError 的空枚举,它有效地表达出 Promise 不能失败的语义,因为空的枚举不能被初始化,所以 Promise 不能进入到 rejected 的状态,这是一个令人心痛的损失,但我认为这是值得的,因为这样在其它上下文中使用 Promise 变得更简单,希望能在实践中使用这个类,以便深入体会并思考不设置错误类型否是个明智的决定。

五、函数式编程中的方法难以理解

  • Promise 的类型是一个 monad,也就是说可以对它调用 flatMap,传递给 flatMap 的函数会返回一个新的 Promise,返回的 Promise 的状态将成为该调用链的状态。
  • 不过,flatMap 的函数名是绝对不能忽视的,它无法使用一种易读的方式表达函数中发生的事情,这是 A+ 规范的 Promise API 的优势之一。JavaScript 中的 then 函数被重载为 flatMap 函数(为调用链返回一个新的 Promise)和 map 函数(为调用链中的下一个 Promise 返回一个新值)。then 只意味着“下一步做这件事”,而不知道下一件事情的工作原理。

六、实现 Promise

① 第一个测试

  • 先写第一个测试:
test(named: "0. Executor function is called immediately") { assert, done in
    var string: String = ""
    _ = Promise { string = "foo" }
    assert(string == "foo")
    done()
}
  • 通过此测试,想实现传递一个函数给 Promise 的初始化函数,并立即调用此函数(没有使用任何测试框架,仅仅使用一个自定义的 test 方法,它在 Playground 中模拟断言:PromisePlayground.swift)。
  • 当我们运行 Playground,编译器会报错:
error: Promise.playground:41:9: error: use of unresolved identifier 'Promise'
    _ = Promise { string = "foo" }
        ^~~~~~~
  • 合理,因此需要定义 Promise 类:
class Promise {

}
  • 再运行,错误变为:
error: Promise.playground:44:17: error: argument passed to call that takes no arguments
    _ = Promise { string = "foo" }
                ^~~~~~~~~~~~~~~~~~
  • 必须定义一个初始化函数,它接受一个闭包作为参数,而且这个闭包应该被立即调用:
class Promise {
    init(executor: () -> Void) {
        executor()
    }
}
  • 由此,我们通过第一个测试,目前还没有写出什么值得夸耀的东西,但耐心一点,实现将继续增长:
Test 0. Executor function is called immediately passed 
  • 我们先将此测试注释掉,因为将来的 Promise 实现会变得有些不同。

② 最低限度

  • 第二个测试如下:
test(named: "1.1 Resolution handler is called when promise is resolved sync") { assert, done in
    let string: String = "foo"
    let promise = Promise<String> { resolve in
        resolve(string)
    }
    promise.then { (value: String) in
        assert(string == value)
        done()
    }
}
  • 这个测试挺简单,但添加了一些新内容到 Promise 类,创建的这个 promise 有一个 resolution handler(即闭包的 resolve 参数),之后立即调用它(传递一个 value)。然后使用 promise 的then方法来访问 value 并用断言确保其值。
  • 在开始实现之前,需要引入另外一个不太一样的测试:
test(named: "1.2 Resolution handler is called when promise is resolved async") { assert, done in
    let string: String = "foo"
    let promise = Promise<String> { resolve in
        after(0.1) {
            resolve(string)
        }
    }
    promise.then { (value: String) in
        assert(string == value)
        done()
    }
}
  • 不同于测试 1.1 ,这里的 resove 方法被延迟调用,这意味着,在 then 里,value 不会立马可用(因为 0.1 秒的延迟,调用 then 时,resolve 还未被调用)。
  • 开始理解这里的“问题”,必须处理异步:
    • promise 是一个状态机,当它被创建时,promise 处于pending状态,一旦 resolve 方法被调用(与一个 value),promise 将转到 resolved 状态,并存储这个 value。
    • then 方法可在任意时刻被调用,而不管 promise 的内部状态(即不管 promise 是否已有一个 value),当这个 promise 处于 pending 状态时,调用 then,value 将不可用,因此需要存储此回调,之后一旦 promise 变成 resolved,就能使用 resolved value 来触发同样的回调。
  • 现在对要实现的东西有了更好的理解,那就先以修复编译器的报错开始:
error: Promise.playground:54:19: error: cannot specialize non-generic type 'Promise'
    let promise = Promise<String> { resolve in
                  ^      ~~~~~~~~
  • 必须给 Promise 类型添加泛型,诚然,一个 promise 是这样的东西:它关联着一个预定义的类型,并能在被解决时,将一个此类型的 value 保留住:
class Promise<Value> {

    init(executor: () -> Void) {
        executor()
    }
}
  • 现在错误为:
error: Promise.playground:54:37: error: contextual closure type '() -> Void' expects 0 arguments, but 1 was used in closure body
    let promise = Promise<String> { resolve in
                                    ^
  • 必须提供一个 resolve 函数传递给初始化函数(即 executor):
class Promise<Value> {
    init(executor: (_ resolve: (Value) -> Void) -> Void) {
        executor()
    }
}
  • 注意这个 resolve 参数是一个函数,它消耗一个 value:(Value) -> Void,一旦 value 被确定,这个函数将被外部世界调用。 编译器依然不开心,因为需要提供一个 resolve 函数给 executor,那就创建一个 private:
class Promise<Value> {
    init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) {
        executor(resolve)
    }

    private func resolve(_ value: Value) -> Void {
        // To implement
        // This will be called by the outside world when a value is determined
    }
}
  • 当所有错误都被解决的时候,再来实现 resolve。下一个错误很简单,方法 then 还未定义:
error: Promise.playground:61:5: error: value of type 'Promise<String>' has no member 'then'
    promise.then { (value: String) in
    ^~~~~~~ ~~~~
  • 现在修复它:
class Promise<Value> {

    init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) {
        executor(resolve)
    }

    func then(onResolved: @escaping (Value) -> Void) {
        // To implement
    }

    private func resolve(_ value: Value) -> Void {
        // To implement
    }
}
  • 现在编译通过,我们之前说过一个 Promise 就是一个状态机,它有一个 pending 状态和一个 resolved 状态,可以使用 enum 来定义它们:
enum State<T> {
    case pending
    case resolved(T)
}
  • Swift 可以直接存储 promise 的 value 在 enum 中,现在我要在 Promise 的实现中定义一个状态,其默认值为 .pending,还需要一个私有函数,它能在当前还处于 .pending 状态时更新状态:
class Promise<Value> {

    enum State<T> {
        case pending
        case resolved(T)
    }

    private var state: State<Value> = .pending

    init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) {
        executor(resolve)
    }

    func then(onResolved: @escaping (Value) -> Void) {
        // To implement
    }

    private func resolve(_ value: Value) -> Void {
        // To implement
    }

    private func updateState(to newState: State<Value>) {
        Guard case .pending = state else { return }
        state = newState
    }
}
  • 注意 updateState(to:) 函数先检查了当前处于 .pending 状态,如果 promise 已经处于 .resolved 状态,那它就不能再变成其它状态。 现在是时候在必要时更新 promise 的状态,即当 resolve 函数被外部世界传递 value 调用时:
private func resolve(_ value: Value) -> Void {
    updateState(to: .resolved(value))
}
  • 现在只缺少 then 方法还未实现,必须存储回调,并在 promise 被解决时调用回调,现在来实现:
class Promise<Value> {

    enum State<T> {
        case pending
        case resolved(T)
    }

    private var state: State<Value> = .pending
    // we Store the callback as an instance variable
    private var callback: ((Value) -> Void)?

    init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) {
        executor(resolve)
    }

    func then(onResolved: @escaping (Value) -> Void) {
        // store the callback in all cases
        callback = onResolved
        // and trigger it if needed
        triggerCallbackIfResolved()
    }

    private func resolve(_ value: Value) -> Void {
        updateState(to: .resolved(value))
    }

    private func updateState(to newState: State<Value>) {
        guard case .pending = state else { return }
        state = newState
        triggerCallbackIfResolved()
    }

    private func triggerCallbackIfResolved() {
        // the callback can be triggered only if we have a value,
        // meaning the promise is resolved
        guard case let .resolved(value) = state else { return }
        callback?(value)
        callback = nil
    }
}
  • 这里定义了一个实例变量 callback,以在 promise 处于.pending 状态时保留回调。同时,创建一个方法 triggerCallbackIfResolved,它先检查状态是否为 .resolved,然后传递拆包的 value 给回调,这个方法在两个地方被调用,一个是 then 方法中,如果 promise 已经在调用 then 时被解决;另一个在 updateState 方法中,因为那是 promise 更新其内部状态从 .pending 到 .resolved 的地方。
  • 有了这些修改,测试就成功通过:
Test 1.1 Resolution handler is called when promise is resolved sync passed (1 assertions)
Test 1.2 Resolution handler is called when promise is resolved async passed (1 assertions)
  • 但现在还需要做出一点改变,以得到一个真正的 Promise 实现,先来看看测试:
test(named: "2.1 Promise supports many resolution handlers sync") { assert, done in
    let string: String = "foo"
    let promise = Promise<String> { resolve in
        resolve(string)
    }
    promise.then { value in
        assert(string == value)
    }
    promise.then { value in
        assert(string == value)
        done()
    }
}
test(named: "2.2 Promise supports many resolution handlers async") { assert, done in
    let string: String = "foo"
    let promise = Promise<String> { resolve in
        after(0.1) {
            resolve(string)
        }
    }
    promise.then { value in
        assert(string == value)
    }
    promise.then { value in
        assert(string == value)
        done()
    }
}
  • 这回对每个 promise 都调用了两次 then,看看测试输出:
Test 2.1 Promise supports many resolution handlers sync passed (2 assertions)
Test 2.2 Promise supports many resolution handlers async passed (1 assertions)
  • 虽然测试通过了,但你可能也注意问题,测试 2.2 只有一个断言,但应该是两个。如果思考一下,这其实符合逻辑,在异步的测试 2.2 中,当第一个 then 被调用时,promise 还处于 .pending 状态,如之前所见,存储了第一次 then 的回调,但当第二次调用 then 时,promise 还是没有被解决,依然处于 .pending 状态,于是将回调擦除换成了新的。只有第二个回调会在将来被执行,第一个被忘记了,这使得测试虽然通过,但只有一个断言而不是两个。
  • 解决办法也很简单,就是存储一个回调的数组,并在 promise 被解决时触发它们,更新一下:
class Promise<Value> {

    enum State<T> {
        case pending
        case resolved(T)
    }

    private var state: State<Value> = .pending
    // We now store an array instead of a single function
    private var callbacks: [(Value) -> Void] = []

    init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) {
        executor(resolve)
    }

    func then(onResolved: @escaping (Value) -> Void) {
        callbacks.append(onResolved)
        triggerCallbacksIfResolved()
    }

    private func resolve(_ value: Value) -> Void {
        updateState(to: .resolved(value))
    }

    private func updateState(to newState: State<Value>) {
        guard case .pending = state else { return }
        state = newState
        triggerCallbacksIfResolved()
    }

    private func triggerCallbacksIfResolved() {
        guard case let .resolved(value) = state else { return }
        // We trigger all the callbacks
        callbacks.foreach { callback in callback(value) }
        callbacks.removeAll()
    }
}
  • 测试通过,并且都有两个断言:
Test 2.1 Promise supports many resolution handlers sync passed (2 assertions)
Test 2.2 Promise supports many resolution handlers async passed (2 assertions)
  • 现在就已经创建了自己的 Promise 类,已经可以使用它来抽象异步逻辑,但它还有限制。
  • 如果从全局来看,我们知道 then 可以被重命名为 observe,它的目的是消费 promise 被解决后的 value,但它不返回什么。这意味着暂时没法串联多个 promise。

③ 串联多个 Promise

  • 如果不能串联多个 promise,那 Promise 实现就不算完整。先来看看测试,它将帮助我们实现这个特性:
test(named: "3. Resolution handlers can be chained") { assert, done in
    let string: String = "foo"
    let promise = Promise<String> { resolve in
        after(0.1) {
            resolve(string)
        }
    }
    promise
        .then { value in
            return Promise<String> { resolve in
                after(0.1) {
                    resolve(value + value)
                }
            }
        }
        .then { value in // the "observe" previously defined
            assert(string + string == value)
            done()
        }
}
  • 如测试所见,第一个 then 创建了一个有新 value 的新 Promise 并返回了它,第二个 then(前一节定义被称为 observe)被串联在后面,它访问新的 value(其将是 “foofoo” )。但是很快在终端里看到错误:
error: Promise.playground:143:10: error: value of tuple type '()' has no member 'then'
        .then { value in
         ^
  • 我们必须创建一个 then 的重载,它接受一个能返回 promise 的函数,为了能够串联调用 then,这个方法必须也返回一个 promise,这个 then 的原型如下:
func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> {
    // to implement
}
  • 细心的你可能已经发现,在给 Promise 实现 flatMap,就如给 Optional 和 Array 定义 flatMap 一样,也可以给 Promise 定义它。那么这个 “flatMap” 的 then 要怎么实现呢?
    • 需要返回一个Promise?
    • 怎么给一个 promise?onResolved 方法?
    • onResolved 需要一个类型为 Value 的 value 为参数,该怎样得到这个 value 呢?
  • 如果写成代码,大概如下:
func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> {
    then { value in // the "observe" one
        let promise = onResolved(value) // `promise` is a Promise<NewValue>
        // problem: how do we return `promise` to the outside ??
    }
    return // ??!!
}
  • 到这里就快好了,但还有个小问题需要修复:这个 promise 变量被传递给 then 的闭包所限制,我们不能将其作为函数的返回值。我们要使用的技巧是创建一个包装 Promise,它将执行我们目前所写的代码,然后在 promise 变量解决时被同时解决。换句话说,当 onResolved 方法提供的 promise 被解决并从外部得到一个值,那包装的 promise 也就被解决并得到同样的值。
  • 可能文字有些抽象,但如果写成代码,将看得更清楚:
func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> {
    // We have to return a promise, so let's return a new one
    return Promise<NewValue> { resolve in
        // this is called immediately as seen in test 0.
        then { value in // the "observe" one
            let promise = onResolved(value) // `promise` is a Promise<NewValue>
            // `promise` has the same type of the Promise wrapper
            // we can make the wrapper resolves when the `promise` resolves
            // and gets a value
            promise.then { value in resolve(value) }
        }
    }
}
  • 如果整理一下代码,将有这样两个方法:
// observe
func then(onResolved: @escaping (Value) -> Void) {
    callbacks.append(onResolved)
    triggerCallbacksIfResolved()
}

// flatMap
func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> {
    return Promise<NewValue> { resolve in
        then { value in
            onResolved(value).then(onResolved: resolve)
        }
    }
}
  • 最后测试通过:
Test 3. Resolution handlers can be chained passed (1 assertions)

④ 串联多个 value

  • 如果能给某个类型实现 flatMap,那么就能利用 flatMap 为其实现 map,对于 Promise 来说,;map 该是什么样子?使用如下测试:
test(named: "4. Chaining works with non promise return values") { assert, done in
    let string: String = "foo"
    let promise = Promise<String> { resolve in
        after(0.1) {
            resolve(string)
        }
    }
    promise
        .then { value -> String in
            return value + value
        }
        .then { value in // the "observe" then
            assert(string + string == value)
            done()
        }
}
  • 注意第一个 then 没有再返回一个 Promise,而是将其接收的值做了一个变换,这个新的 then 就对应于想添加的 map, 编译器报错说必须实现此方法:
error: Promise.playground:174:26: error: declared closure result 'String' is incompatible with contextual type 'Void'
        .then { value -> String in
                         ^~~~~~
                         Void
  • 这个方法很接近 flatMap,唯一的不同是其参数 onResolved 函数返回一个 NewValue,而不是 Promise。
// map
func then<NewValue>(onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> {
    // to implement
}
  • 之前说可以利用 flatMap 实现 map,在这里的情况,我们看到需要返回一个 Promise,如果使用这个 “flatMap” 的 then,并创建一个 promise,再以映射后的 value 来直接解决,就可以搞定
// map
func then<NewValue>(onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> {
    return then { value in // the "flatMap" defined before
        // must return a Promise<NewValue> here
        // this promise directly resolves with the mapped value
        return Promise<NewValue> { resolve in
            let newValue = onResolved(value)
            resolve(newValue)
        }
    }
}
  • 再一次,测试通过:
Test 4. Chaining works with non promise return values passed (1 assertions)
  • 如果我们移除注释,再看看做出了什么,有三个 then 方法的实现,能被使用或串联:
// observe
func then(onResolved: @escaping (Value) -> Void) {
    callbacks.append(onResolved)
    triggerCallbacksIfResolved()
}

// flatMap
func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> {
    return Promise<NewValue> { resolve in
        then { value in
            onResolved(value).then(onResolved: resolve)
        }
    }
}

// map
func then<NewValue>(onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> {
    return then { value in
        return Promise<NewValue> { resolve in
            resolve(onResolved(value))
        }
    }
}

七、使用示例

  • 实现就完成,Promise 类已足够完整来展示能够用它做什么。假设 App 有一些用户,结构如下:
struct User {
    let id: Int
    let name: String
}
  • 假设还有两个方法,一个获取用户 id 列表,另一个使用 id 获取某个用户,而且假设想显示第一个用户的名字, 通过实现,可以这样做,使用之前定义的这三个 then:
func fetchIds() -> Promise<[Int]> {
    ...
}

func fetchUser(id: Int) -> Promise<User> {
    ...
}

fetchIds()
    .then { ids in // flatMap
        return fetchUser(id: ids[0])
    }
    .then { user in // map
        return user.name
    }
    .then { name in // observe
        print(name)
    }
  • 代码变得十分易读、简洁,而且没有嵌套。

脚本宝典总结

以上是脚本宝典为你收集整理的Swift之深入解析如何实现Promise全部内容,希望文章能够帮你解决Swift之深入解析如何实现Promise所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。