Why 'await' requires 'async' in function definition

∥☆過路亽.° 提交于 2021-02-19 05:56:08

问题


I'm currently learning Dart, but this is also applicable to what's going on in the JavaScript world right now, and it seems like C# also uses the same pattern.

In Dart, any function that uses await must itself be labeled asynchronous through async as follows:

import "dart:html";

main() async {
  var context = querySelector("canvas").context2D;
  var running = true;

  while (running) {
    var time = await window.animationFrame;
    ...
  }
}

This does not make sense to me. If a function is waiting on an asynchronous function to complete, is it not then considered blocking? Why do JS and Dart require it to be labeled asynchronous? Would it not be the opposite?

To me it would make far more sense if the calling function must use the async keyword if it calls any function that also includes it in its definition. In this pattern, await would be used to convert asynchronous functions to synchronous ones.

This way would also avoid duplicate functions, since right now, libraries seem to always have func() and funcSync() or funcAsync().


回答1:


The basic semantics of async/await are the same across F#, VB, C#, Python, Dart, Hack, and JavaScript. So I think this question has sufficient answers from other languages. But since it has been reopened...

If a function is waiting on an asynchronous function to complete, is it not then considered blocking?

No. Think about it this way:

  • "asynchronous" means "does not block the calling thread".
  • "synchronous" means "blocks the calling thread".

In an asynchronous method/function, the method/function can be paused at the await points, but it does not block the calling thread while it is paused. The function runs serially (one statement at a time), but asynchronously (without blocking the calling thread).

To me it would make far more sense if the calling function must use the async keyword if it calls any function that also includes it in its definition.

That's how it already works... await consumes promise/future/task-returning methods/functions, and async marks a method/function as capable of using await.

This way would also avoid duplicate functions

This is not possible with historically-blocking imperative languages. A method/function either blocks the calling thread until it is complete, or it does not. It is either synchronous or asynchronous.

There are some interesting alternative approaches to async methods/functions, though:

Go is not historically blocking; you can think of it as a language where every method/function is potentially asynchronous; doing this in any other runtime would be disastrous, but Go avoids those problems by implementing a strict goroutine system with message passing - no shared memory or threads allowed.

Another example are pure functional languages, where Future is just another monad and requires no special compiler support for async/await keywords.




回答2:


In Dart async indicates that the code containing await needs to be rewritten. async/await is just syntactic sugar for the Future.then() base API, and the code is rewritten to this canonical Future based form, before it is compiled and executed.

Therefore await doesn't make code blocking.

There are also other supported markers like *sync and *async for generators.

See also - Dart async/await internals - https://www.dartlang.org/articles/language/await-async




回答3:


I'm not sure what your question has to do with C# but await is a most unfortunate keyword choice in C#. await is more understandable if you read it as resume after or even yield then resume after. When execution encounters await, it suspends the current function, returning to its caller. Once the Task being waited on is done, execution resumes after the await when the caller needs the result (from an await expression of its own).




回答4:


This is a fundamental misunderstanding of what's going on "under-the-hood", I'm assuming the javascript async/await implementation mirrors (at least conceptually) that of the .NET world (which originated in F#).

Essentially:

  1. A "unit of work" "token" of sorts (in C# a Task in JS a Promise) represents a completion of a task with an option of returning a value.
  2. An "asynchronous" method is marked with async, to indicate to the compiler/interpreter/runtime whatever, that this method will return said token, and will likely consume some as well.
  3. The thingamajig running it all, will (in C#'s case), rewrite the code on the sly to essentially do the following:

  1. Start async method
  2. Do standard normal code
  3. Encounter "token" providing method
  4. Call it, grab token
  5. Setup a place the code can jump back to later
  6. Is the token complete? If so, carry on, If not, set a callback to have the runtime come back to this place when it does

In this expanded context, the keywords make sense:

  1. async(hronous) - A method that does some task that can take an indeterminate amount of time, that can be waited upon.
  2. await - Indicates that instead of just grabbing the token from the async method and doing nothing with it, that you actually want to set up all this ceremony around listening out for when the work is done, and carrying on afterwards.

tl;dr

Just think of async and await as invisible callbacks, async indicates when something can be listened out for, and await is what actually does the listening.



来源:https://stackoverflow.com/questions/44894691/why-await-requires-async-in-function-definition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!