使用 Promises 的代码根本不执行
Posted
技术标签:
【中文标题】使用 Promises 的代码根本不执行【英文标题】:Code using Promises doesn't execute at all 【发布时间】:2021-06-11 06:32:20 【问题描述】:我花了一天的大部分时间在墙上撞墙,我想我终于明白了。这是我今天早上开始寻找时希望存在的问题。
作为背景,我有几年使用 C++ 和 Python 的经验,最近我开始学习 Swift 进行非 ios 开发。我将在这里展示的所有内容在 MacBook Pro 上的行为似乎与在我的 Ubuntu PC 上的行为相同。我正在运行 Swift 5.4,在命令行中使用 Swift Package Manager 编译和运行。
我已经阅读了几篇关于在 Swift 中使用 Promises 的文章,但没有加起来。他们展示的示例使您看起来好像只需调用firstly
,将几个.then
调用链接在一起,然后将它们与.done
和.catch
绑定在一起,一切都会正常工作。当我尝试这个时,我大多会得到一堆错误,但有时我很幸运能够编译它,却发现当我运行它时什么都没有发生。
这是一个示例 main.swift
文件,说明了我的困惑。
import PromiseKit
firstly
Promise<String> seal in
print("Executing closure")
seal.fulfill("Hello World!")
.done str in
print(str)
当我运行它时,它只会打印Executing closure
,即使我在它之后添加了一个睡眠,或者我在结果上调用.wait()
。为什么firstly
块执行但done
块不执行?
这是另一个。我花了一段时间才编译它,但它仍然没有达到我的预期:
import Foundation
import PromiseKit
let url = URL(string: "https://***.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 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 str in
print(str)
.catch error in
print("Error: \(error)")
我希望它打印 Stack Overflow 主页的 html 内容,但它什么也不打印。
似乎我已经完成了所有设置,但是 Promise 没有运行。如何让它们真正执行?
【问题讨论】:
【参考方案1】:似乎这里的问题是所有在线文章都专注于 iOS 开发,并没有真正解决桌面/服务器可执行文件中的 Promise。简单脚本旨在终止,而移动应用程序旨在无限期运行。
如果您深入研究Thenable
代码,您会发现.then
、.done
、.catch
等有一个DispatchQueue
的参数,深入挖掘,默认为@987654328 @。因为这些示例中的***代码正在使用主线程,所以主 DispatchQueue
永远没有机会执行分配给它的工作。通过在最后调用 dispatchMain()
将主线程让给调度系统,这两个示例都可以轻松地执行 Promise 链。
但是,dispatchMain()
永远不会返回,因此对于打算运行完成的可执行文件来说,这不是一个好的选择。更好的解决方案是指定一个备用队列来执行这些承诺中的每一个。对于单个任务,我们可以在 .finally
块中使用信号量来表示所有工作都已完成。对于多项任务,我怀疑您需要使用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()
这是第二个的工作版本:
import Foundation
import PromiseKit
let queue = DispatchQueue.global()
let semaphore = DispatchSemaphore(value: 0)
let url = URL(string: "https://***.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()
有趣的是,firstly
块似乎在主线程上同步执行。我突然想到,如果你有很多任务要运行,最好在 firstly
处理程序内做尽可能少的工作,并释放你的主线程,以便它可以启动另一个任务线程更快。
【讨论】:
***.com/questions/63425657/… ***.com/questions/34828991/using-gcd-in-swift-cli以上是关于使用 Promises 的代码根本不执行的主要内容,如果未能解决你的问题,请参考以下文章
我在spring设置了事务管理,但是对于需要使用事务的方法,如果不手动开启事务,这个方法根本不执行