gpt4 book ai didi

swift - 将递归异步函数转换为 promise

转载 作者:行者123 更新时间:2023-11-28 06:17:10 24 4
gpt4 key购买 nike

我有一个递归的异步函数,它使用 REST api 和完成处理程序在 Google 云端硬盘中查询文件 ID:

func queryForFileId(query: GTLRDriveQuery_FilesList,
handler: @escaping FileIdCompletionHandler) {
service.executeQuery(query) { ticket, data, error in
if let error = error {
handler(nil, error)
} else {
let list = data as! GTLRDrive_FileList
if let pageToken = list.nextPageToken {
query.pageToken = pageToken
self.queryForFileId(query: query, handler: handler)
} else if let id = list.files?.first?.identifier {
handler(id, nil)
} else {
handler(nil, nil) // no file found
}
}
}
}

这里,query设置为返回nextPageTokenfiles(id)字段,serviceGTLRDriveService 的一个实例,而 FileIdCompletionHandler 只是一个 typealias:

typealias FileIdCompletionHandler = (String?, Error?) -> Void

我已经阅读了如何将异步函数转换为 promises(如 this thread 中所示),但我不知道如何将其应用于递归异步函数。我想我可以将整个方法包装为 Promise:

private func fileIdPromise(query: GTLRDriveQuery_FilesList) -> Promise<String?> {
return Promise { fulfill, reject in
queryForFileId(query: query) { id, error in
if let error = error {
reject(error)
} else {
fulfill(id)
}
}
}
}

但是,我希望更直接一些:

private func queryForFileId2(query: GTLRDriveQuery_FilesList) -> Promise<String?> {
return Promise { fulfill, reject in
service.executeQuery(query) { ticket, data, error in
if let error = error {
reject(error)
} else {
let list = data as! GTLRDrive_FileList
if let pageToken = list.nextPageToken {
query.pageToken = pageToken
// WHAT DO I DO HERE?
} else if let id = list.files?.first?.identifier {
fulfill(id)
} else {
fulfill(nil) // no file found
}
}
}
}
}

那么:当我需要对 executeQuery 进行另一个异步调用时,我该怎么办?

最佳答案

如果你想满足一组递归的 promise ,在你的“我在这里做什么?”行,您将创建一个新的 promise.then {...}.else {...} 模式,在 then 中调用 fulfill > 子句和 else 子句中的 reject。显然,如果不需要递归调用,您只需直接fulfill即可。

我不了解 Google API,而且您没有分享您的代码来满足对文件列表的 promise ,所以我不得不让这个答案有点笼统:假设您有一些 retrieveTokens 例程返回一个 promise ,只有当所有文件的所有 promise 都完成时才会满足。让我们想象一下顶级调用是这样的:

retrieveTokens(for: files).then { tokens in
print(tokens)
}.catch { error in
print(error)
}

然后您将拥有一个 retrieveTokens,它返回一个 promise ,只有当对单个文件的 promise 得到满足时,该 promise 才会被满足。如果你正在处理一个简单的 File 对象数组,你可能会这样做:

func retrieveTokens(for files: [File]) -> Promise<[Any]> {
var fileGenerator = files.makeIterator()
let generator = AnyIterator<Promise<Any>> {
guard let file = fileGenerator.next() else { return nil }
return self.retrieveToken(for: file)
}

return when(fulfilled: generator, concurrently: 1)
}

(我知道这不是你的样子,但我需要这个框架来显示我对你下面问题的回答。但是将这个“在给定级别返回所有 promise ”封装在一个函数中是有用的,因为它允许您使递归代码保持优雅,而无需重复代码。)

然后为单个文件返回 promise 的例程将查看是否需要返回一组递归 promise ,并将其 fulfill 放在 then 子句中那个新的递归创建的 promise :

func retrieveToken(for file: File) -> Promise<Any> {
return Promise<Any> { fulfill, reject in
service.determineToken(for: file) { token, error in
// if any error, reject

guard let token = token, error == nil else {
reject(error ?? FileError.someError)
return
}

// if I don't have to make recursive call, `fulfill` immediately.
// in my example, I'm going to see if there are subfiles, and if not, `fulfill` immediately.

guard let subfiles = file.subfiles else {
fulfill(token)
return
}

// if I got here, there are subfiles and I'm going to start recursive set of promises

self.retrieveTokens(for: subfiles).then { tokens in
fulfill(tokens)
}.catch { error in
reject(error)
}
}
}
}

同样,我知道以上内容并不是您问题的直接答案(因为我不熟悉 Google Drive API 也不熟悉您如何执行顶级 promise 逻辑)。因此,在我的示例中,我创建了足以满足 the demonstration 目的的模型对象。 .

但希望这足以说明递归 promise 集背后的想法。

关于swift - 将递归异步函数转换为 promise,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44787956/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com