Swift 使用承诺的代码不';根本不执行

Swift 使用承诺的代码不';根本不执行,swift,promise,promisekit,Swift,Promise,Promisekit,我花了一天的大部分时间在这件事上把头撞在墙上,我想我终于明白了。这是一个我希望在今天早上我开始寻找时就存在的问题 背景,我有几年的C++和Python的经验,最近我开始学习Swift来开发非iOS。我将在这里展示的一切在MacBook Pro上的表现似乎与在我的Ubuntu PC上的表现相同。我正在运行Swift 5.4,在命令行中使用Swift软件包管理器进行编译和运行 我已经阅读了几篇关于在Swift中使用承诺的文章,但这些文章都不完整。他们展示的例子让人觉得你可以先调用,,将几个链接在一起

我花了一天的大部分时间在这件事上把头撞在墙上,我想我终于明白了。这是一个我希望在今天早上我开始寻找时就存在的问题

背景,我有几年的C++和Python的经验,最近我开始学习Swift来开发非iOS。我将在这里展示的一切在MacBook Pro上的表现似乎与在我的Ubuntu PC上的表现相同。我正在运行Swift 5.4,在命令行中使用Swift软件包管理器进行编译和运行

我已经阅读了几篇关于在Swift中使用承诺的文章,但这些文章都不完整。他们展示的例子让人觉得你可以先调用
,将几个
链接在一起。然后调用
,然后用
.done
.catch
,一切都会正常工作。当我尝试这个方法时,我通常会遇到一大堆错误,但有时我很幸运地编译了它,结果却发现在运行它时什么都没有发生

下面是一个示例
main.swift
文件,它说明了我的困惑

import PromiseKit

firstly {
    Promise<String> { seal in
        print("Executing closure")
        seal.fulfill("Hello World!")
    }
}.done { str in
    print(str)
}
我希望它打印Stack Overflow主页的HTML内容,但它不打印任何内容


看起来我已经准备好了所有的设置,但是承诺没有兑现。如何让它们真正执行?

这里的问题似乎是所有的在线文章都关注iOS开发,而不是真正解决桌面/服务器可执行文件中的承诺。简单脚本旨在终止,而移动应用程序则设计为无限期运行

如果您深入研究
代码,您会发现
。然后
。完成
。捕获
,等等都有一个
调度队列
的参数,深入研究后,该参数默认为
调度队列.main
。由于这些示例中的顶级代码使用的是主线程,因此主
DispatchQueue
从未获得执行分配给它的工作的机会。通过在最后调用
dispatchMain()
将主线程交给调度系统,这两个示例都可以很容易地执行承诺链

但是,
dispatchMain()
永远不会返回,因此对于打算运行到完成的可执行文件来说,这不是一个好的选择。更好的解决方案是指定一个备用队列来执行这些承诺。对于单个任务,我们可以在
块中使用信号量。最后,
块发出所有工作都已完成的信号。对于多个任务,我怀疑您需要使用
DispatchGroup

以下是第一个示例的更新版本:

import Foundation
import PromiseKit

let queue = DispatchQueue.global()
let semaphore = DispatchSemaphore(value: 0)

firstly {
    Promise<String> { seal in
        print("Executing closure")
        seal.fulfill("Hello World!")
    }
}.done(on: queue) { str in
    print(str)
}.catch(on: queue) { error in
    print("Error: \(error)")
}.finally(on: queue) {
    semaphore.signal()
}

semaphore.wait()
<代码>导入基础 进口承诺书 let queue=DispatchQueue.global() 让信号量=分派信号量(值:0) 首先{ 承诺{盖章 打印(“执行关闭”) seal.fulfill(“你好,世界!”) } }.done(on:queue){str in 打印(str) }.catch(在:队列上){中出错 打印(“错误:\(错误)”) }.最后(关于:队列){ 信号量 } 信号量。等待()
这是第二个的工作版本:

import Foundation
import PromiseKit

let queue = DispatchQueue.global()
let semaphore = DispatchSemaphore(value: 0)

let url = URL(string: "https://stackoverflow.com/")!

enum SampleError: Error {
    case noResponse
    case badCode(Int)
    case couldNotDecode
}

firstly {
    Promise<Data> { seal in
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                return seal.reject(error)
            }

            guard let data = data, let response = response as? HTTPURLResponse else {
                return seal.reject(SampleError.noResponse)
            }

            guard (200..<300).contains(response.statusCode) else {
                return seal.reject(SampleError.badCode(response.statusCode))
            }

            seal.fulfill(data)
        }.resume()
    }
}.then(on: queue) { data -> Promise<String> in
    Promise<String> { seal in
        if let str = String(data: data, encoding: .utf8) {
            seal.fulfill(str)
        } else {
            seal.reject(SampleError.couldNotDecode)
        }
    }
}.done(on: queue) { str in
    print(str)
}.catch(on: queue) { error in
    print("Error: \(error)")
}.finally (on: queue) {
    semaphore.signal()
}

semaphore.wait()
<代码>导入基础 进口承诺书 let queue=DispatchQueue.global() 让信号量=分派信号量(值:0) 让url=url(字符串:https://stackoverflow.com/")! 枚举采样错误:错误{ 案例无应答 案例代码(内部) 案例无法解码 } 首先{ 承诺{盖章 URLSession.shared.dataTask(with:url){data,response,中的错误 如果let error=error{ 退回封条。拒绝(错误) } 保护let data=data,let response=response as?httpurresponse else{ 返回密封。拒绝(样本错误。无响应) } 守卫(200..承诺 承诺{盖章 如果let str=String(数据:数据,编码:.utf8){ 密封件(str) }否则{ 密封。拒绝(样本错误。无法解码) } } }.done(on:queue){str in 打印(str) }.catch(在:队列上){中出错 打印(“错误:\(错误)”) }.最后(关于:队列){ 信号量 } 信号量。等待()

有趣的是,
first
块似乎在主线程上同步执行。我突然想到,如果要运行大量任务,最好在
first
处理程序中尽可能少地执行工作,并释放主线程,以便它可以更快地启动其他线程上的任务。

似乎这里的问题在于,所有在线文章都集中在iOS开发上,并没有真正解决桌面/服务器可执行文件中的承诺。简单的脚本旨在终止,而移动应用程序设计为无限期运行

如果深入研究
代码,您会发现
.then
.done
.catch
,等等都有一个
调度队列
的参数,深入研究后,默认为
调度队列.main
。因为这些示例中的顶级代码使用的是主线程mainode>DispatchQueue
从来没有机会执行分配给它的工作。这两个示例都可以通过在最后调用
dispatchMain()
将主线程交给调度系统来轻松执行承诺链

但是,
dispatchMain()
永远不会返回,因此对于打算运行到完成的可执行文件来说,这不是一个好的选择。更好的解决方案是指定一个备用队列来执行每个承诺。对于单个任务,我们可以在
块中使用一个信号量。最后
块来表示所有工作都已完成。对于多个任务,我怀疑您会这样做需要使用
调度组

以下是第一个示例的更新版本:

import Foundation
import PromiseKit

let queue = DispatchQueue.global()
let semaphore = DispatchSemaphore(value: 0)

firstly {
    Promise<String> { seal in
        print("Executing closure")
        seal.fulfill("Hello World!")
    }
}.done(on: queue) { str in
    print(str)
}.catch(on: queue) { error in
    print("Error: \(error)")
}.finally(on: queue) {
    semaphore.signal()
}

semaphore.wait()
<代码>导入基础 进口承诺书 让