示例代码
我强烈建议您阅读下面的说明,但这是代码。
struct ExampleData: Codable {
var array : [Int]
var dict : [String : String]
}
// Register a GET /example route
router.get("example") { req -> Future<View> in
// Fetch an HTTP Client instance
let client = try req.make(Client.self)
// Send an HTTP Request to example.vapor.codes/json over plaintext HTTP
// Returns `Future<Response>`
let response = client.get("http://example.vapor.codes/json")
// Transforms the `Future<Response>` to `Future<ExampleData>`
let exampleData = response.flatMap(to: ExampleData.self) { response in
return response.content.decode(ExampleData.self)
}
// Renders the `ExampleData` into a `View`
return try req.view().render("home", exampleData)
}
期货
Future<Expectation> 是 Expectation 的包装器。期望可以成功也可以失败(带有错误)。
Future 类型可以注册成功完成后执行的回调。我们在这里使用的这些回调之一是flatMap。让我们先来看看普通的map。
如果你 map 一个 Future,你将转换未来的成功 Expectation 并透明地通过错误条件。
let promise = Promise<String>()
let stringFuture = promise.future // Future<String>
let intFuture = stringFuture.map(to: Int.self) { string -> Int in
struct InvalidNumericString: Error {}
guard let int = Int(string) else { throw InvalidNumericString() }
return int // Int
}
intFuture.do { int in
print("integer: ", int)
}.catch { error in
print("error: \(error)")
}
如果我们使用有效的十进制整数格式的字符串(如"4")完成承诺,它将打印integer: 4
promise.complete("4")
如果我们在其中放置任何非数字字符,例如 "abc",它会在 InvalidNumericString 错误中抛出一个错误,这将触发 catch 块。
promise.complete("abc")
无论您做什么,map 或 flatMap 函数引发的错误都会通过其他转换透明地级联。转换未来只会转换Expectation,并且只会在成功的情况下触发。错误案例将从“基础未来”复制到新转换的未来。
如果你没有完成承诺而不是承诺失败,则永远不会触发 map 块,而是会在 catch 块中找到 AnyError 条件。
struct AnyError: Error {}
promise.fail(AnyError())
flatMap 的工作方式与上面的示例非常相似。这是一个map,其中尾随闭包返回Future<Expectation>,而不是Expectation。
因此,如果我们将地图块重写为flatMap,虽然不切实际,但我们最终会得到这样的结果:
let intFuture = stringFuture.flatMap(to: Int.self) { string -> Future<Int> in
struct InvalidNumericString: Error {}
guard let int = Int(string) else { throw InvalidNumericString() }
return Future(int) // Int
}
intFuture 仍然是 Future<Int>,因为递归期货将从 Future<Future<Int>> 扁平化为 Future<Int>。
内容
response.content.decode 位读取 Content-Type 并查找此 Content Type 的默认 Decoder。解码后的结构体将返回为Future<DecodedStruct>,在本例中,该结构体为ExampleData。
内容异步返回的原因是内容可能还没有完全到达HTTP响应中。这是一个必要的抽象,因为我们可能会接收超过 100MB 的文件,这可能会导致只有少量可用内存的(云)服务器崩溃。
逻辑
回到原来的路线:
- 先做一个客户端
- 向
http://example.vapor.codes/json发出请求
- 从
Future<Response>异步读取内容
- 将结果异步渲染到视图中
- 返回
Future<View>
框架将理解您正在返回 Future<View>,并将继续处理其他请求,而不是等待结果。
收到 JSON 后,将再次提取此请求并处理为您的网络浏览器将收到的响应。
Leaf 建立在 TemplateKit 之上,它将异步等待未来。就像 Vapor 一样,Leaf 和 TemplateKit 可以很好地理解 Futures,您可以传递 Future 而不是 struct(反之亦然),如果需要,它们会切换到另一个请求,直到 future 完成。