为什么'await'不能用在普通函数中?
Why 'await' cannot be used in ordinary functions?
更正:从两个答案来看,问题看起来是特定于dart的,因为C#实现了Task.Wait
允许以达到预期的效果。我将不胜感激关于为什么这在飞镖中不可能的原因或如何在那里实现它的任何进一步信息。我很乐意以当前形式结束问题。
在某些情况下,让同步函数使用异步调用在内部等待它们完成后再交付结果是有意义的。这在 C# 和 Dart 中都是明确不允许的:任何使用 await
的东西都必须标记为 async
(因此返回一个未来)。
Dart中的一个简单示例,但同样适用于C#:
免责声明:这不是我做事的方式,所以不要建议 "correct" 将所有方法转换为异步的解决方案;这里的代码只是为了说明问题。
我有一个针对特定 REST API 的 HTTP 请求的通用包装器的完全异步实现。它进行一些登录、身份验证等操作:
class RequestProcessor {
Future post(String path, [payload]) async {
return request("POST", path, payload);
}
}
我想实现一个面向高级用户的 API 转换为对 REST-API 的请求。其中一些方法我希望同步。这是我想要但不允许拥有的东西:
class API {
final RequestProcessor processor;
API(this.processor);
// this takes long and should be asynchronous, happy with a future (OK)
Future getQueryResults(query) async {
return await processor.post("/query", query);
}
// here I would prefer to have it synchronous (COMPILE ERROR)
String getVersion() {
return await processor.post("/version");
}
}
问题:为什么不允许这样做?
在 Dart 中标记一个 function/method async
告诉 VM 它需要在执行之前重写代码。
await
不会将异步函数更改为同步函数,该函数仍然是异步的,它只是允许比 then(() { return ...then(() { return...})})
链更好的语法。
如果你进行异步调用,后面的一切都是异步的,你对此无能为力。
await
是异步等待,因此将其放在同步函数中没有意义。要异步,该方法需要 return 当等待的操作启动时,而同步方法需要 运行 完成。
您可以改用同步等待,在这种情况下您的方法不需要是 async
。在 C# 中,您可以通过在 returned 任务上调用 Wait()
方法来完成此操作。
因为等待和返回未来是根本不同的。
返回 future 会释放当前线程,并可选择为以后安排继续,等待会阻塞当前线程。
例如,在 UI 线程中,返回 future 没问题,但等待会导致 UI 挂起,在 Web 服务器线程中,等待会阻塞线程并阻止 Web 服务器从处理更多请求等
甚至有可能等待应该是异步操作的东西会导致死锁。
.net provide Task.Wait 因为当你知道等待很好时,我不知道飞镖 - 但这不是自动的(除了 C# 中异步方法中的 catch 子句内的 await )
这是一种设计选择。
Dart 是单线程的 - 每个同步函数调用将 运行 在允许任何其他代码 运行 之前完成。如果您允许同步函数阻塞直到 future 完成,那么没有其他代码 运行 并且 future 永远不会完成(因为完成它的代码不能 运行)。
可以有一个系统允许其他代码 运行 而一个同步功能被阻止。这需要拥有多个活动堆栈(并行或非并行),或者隐式地将整个程序转换为异步。当你编译成 JavaScript 时,这两种选择都不是很好,所以 Dart 没有尝试这样做。
更正:从两个答案来看,问题看起来是特定于dart的,因为C#实现了Task.Wait
允许以达到预期的效果。我将不胜感激关于为什么这在飞镖中不可能的原因或如何在那里实现它的任何进一步信息。我很乐意以当前形式结束问题。
在某些情况下,让同步函数使用异步调用在内部等待它们完成后再交付结果是有意义的。这在 C# 和 Dart 中都是明确不允许的:任何使用 await
的东西都必须标记为 async
(因此返回一个未来)。
Dart中的一个简单示例,但同样适用于C#:
免责声明:这不是我做事的方式,所以不要建议 "correct" 将所有方法转换为异步的解决方案;这里的代码只是为了说明问题。
我有一个针对特定 REST API 的 HTTP 请求的通用包装器的完全异步实现。它进行一些登录、身份验证等操作:
class RequestProcessor {
Future post(String path, [payload]) async {
return request("POST", path, payload);
}
}
我想实现一个面向高级用户的 API 转换为对 REST-API 的请求。其中一些方法我希望同步。这是我想要但不允许拥有的东西:
class API {
final RequestProcessor processor;
API(this.processor);
// this takes long and should be asynchronous, happy with a future (OK)
Future getQueryResults(query) async {
return await processor.post("/query", query);
}
// here I would prefer to have it synchronous (COMPILE ERROR)
String getVersion() {
return await processor.post("/version");
}
}
问题:为什么不允许这样做?
在 Dart 中标记一个 function/method async
告诉 VM 它需要在执行之前重写代码。
await
不会将异步函数更改为同步函数,该函数仍然是异步的,它只是允许比 then(() { return ...then(() { return...})})
链更好的语法。
如果你进行异步调用,后面的一切都是异步的,你对此无能为力。
await
是异步等待,因此将其放在同步函数中没有意义。要异步,该方法需要 return 当等待的操作启动时,而同步方法需要 运行 完成。
您可以改用同步等待,在这种情况下您的方法不需要是 async
。在 C# 中,您可以通过在 returned 任务上调用 Wait()
方法来完成此操作。
因为等待和返回未来是根本不同的。
返回 future 会释放当前线程,并可选择为以后安排继续,等待会阻塞当前线程。
例如,在 UI 线程中,返回 future 没问题,但等待会导致 UI 挂起,在 Web 服务器线程中,等待会阻塞线程并阻止 Web 服务器从处理更多请求等
甚至有可能等待应该是异步操作的东西会导致死锁。
.net provide Task.Wait 因为当你知道等待很好时,我不知道飞镖 - 但这不是自动的(除了 C# 中异步方法中的 catch 子句内的 await )
这是一种设计选择。 Dart 是单线程的 - 每个同步函数调用将 运行 在允许任何其他代码 运行 之前完成。如果您允许同步函数阻塞直到 future 完成,那么没有其他代码 运行 并且 future 永远不会完成(因为完成它的代码不能 运行)。
可以有一个系统允许其他代码 运行 而一个同步功能被阻止。这需要拥有多个活动堆栈(并行或非并行),或者隐式地将整个程序转换为异步。当你编译成 JavaScript 时,这两种选择都不是很好,所以 Dart 没有尝试这样做。