我有一个递归的异步函数,使用REST api和完成处理程序查询Google Drive的文件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
设置为返回nextPageToken
和files(id)
字段,service
是GTLRDriveService
的实例,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
进行另一次异步调用时,我该怎么做?
答案 0 :(得分:1)
如果你想要满足递归的承诺,那么你的“我在这做什么?”在这一行中,您将创建一个新的promise.then {...}.else {...}
模式,在fulfill
子句中调用then
,在reject
子句中调用else
。显然,如果不需要递归调用,你只需直接fulfill
。
我不知道Google API并且您没有共享您的代码以满足对文件列表的承诺,所以我必须保持这个答案有点通用:让我们假设您有一些{{1返回只有在完成所有文件的所有promises时才满足的promise的例程。让我们想象一下顶级电话是这样的:
retrieveTokens
然后你有一个retrieveTokens(for: files).then { tokens in
print(tokens)
}.catch { error in
print(error)
}
,只有当满足各个文件的承诺时,才会返回一个满足的承诺。如果您正在处理一组简单的retrieveTokens
对象,您可能会执行以下操作:
File
(我知道这不是你的样子,但是我需要这个框架来展示我对你的问题的答案。但是在一个函数中封装这个“在给定级别返回所有承诺”是有用的,如它允许你保持递归代码有点优雅,而不重复代码。)
然后,返回单个文件的promise的例程将查看是否需要返回一组递归的promise,并将其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的fulfill
子句中:
then
同样,我知道上述内容并不是您问题的直接答案(因为我不熟悉Google Drive API,也不了解您的顶级承诺逻辑)。因此,在我的示例中,我创建了足以满足the demonstration目的的模型对象。
但希望这足以说明递归承诺背后的想法。