Actually in Dart, in order to use await in function body, one need to declare whole function as async:
import "dart:async";
void main() async {
var x = await funcTwo();
print(x);
}
funcTwo() async {
return 42;
}
This code wouldn't work without marking main() as async
Error: Unexpected token 'await'.
But, doc says "The await expressions evaluates e, and then suspends the currently running function until the result is ready–that is, until the Future has completed" (Dart Language Asynchrony Support)
So, maybe I miss something, but there is no need to force function to be asynchronous? What is a rationale for making async declaration obligatory ?
In async functions await is rewritten to code where .then(...) is used instead of await.
The async modifier marks such a function as one that has to be rewritten and with that await is supported.
Without async you would have to write
void main() {
return funcTwo().then((x) {
print(x);
});
}
This is a very simple example but the rewriting can be rather complex when more of the async features are uses, like try/catch, await for(...), ...
One issue is that await was not originally part of the Dart language. To maintain backward compatibility with existing programs that could potentially use await as an identifier, the language designers added a mechanism to explicitly opt-in to using the new await keyword: by adding a (previously invalid) construct to declare a function async.
Related
I have a d3.js org chart tree that works just fine if the JSON data is completely embedded in the source code. However, if I remove the JSON data to an external file and use the below code it fails:
<script>
"use strict";
var path;
var treeData;
async function getjson() {
treeData = await d3.json("orgchart_ext.json");
console.log('getjson being called');
}
getjson();
console.log('after json');
The JS console shows that the after json appears before the getjson being called. As you can see, I am using an async function but inside using the await option.
How can I redo this code such that code after the getjson function does not run until that function is complete?
A very simple working (json data embedded) can be see here: https://codepen.io/tbellmer/pen/RwaGXgq
I have been struggling with this for months so any help will be very much appreciated.
Indeed, I guess that's the expected behavior in an async workflow.
If you want your console.log('after json') statement to be executed after the getjson returns, you need to explicitely await it.
It can be done by wrapping your code in an async function like so:
var path;
var treeData;
async function getjson() {
treeData = await d3.json("orgchart_ext.json");
console.log('getjson being called');
}
async function main() {
await getjson();
console.log('after json');
}
main();
Now your code is waiting for the getjson function to be completed before executing the next statement.
You could put all your code that draws the chart inside a function. i.e. draw(). Then inside your getjson() function, call draw() after the await.
async function getjson() {
treeData = await d3.json("orgchart_ext.json");
draw();
}
I have this function, want to call it synchronously, because if I call it async then I should use FutureBuilder, which I don't prefer because it has extra flicker if user scrolls too fast:
Future<String> getRealHTML(int chapter) async {
var key = _Html.keys.toList()[chapter];
var val = _Html.values.toList()[chapter];
if (val.Content.startsWith("filename:")) {
EpubContentFileRef value = contentRefHtml[key];
return await value.readContentAsText();
}
return null;
}
readContentAsText() returns a Future, you cannot call it synchronously since it is an I/O request which means it will take time to finish the request, that is why it is called asychronously.
Dart newbie here, I'm currently learning about asynchronous execution in Dart. I'm a bit irritated about how concurrency works in Dart, take the following scenario from their codelab:
void printOrderMessage () async {
try {
var order = await fetchUserOrder();
print('Awaiting user order...');
print(order);
} catch (err) {
print('Caught error: $err');
}
}
Future<String> fetchUserOrder() {
// Imagine that this function is more complex.
var str = Future.delayed(Duration(seconds: 4), () => throw 'Cannot locate user order');
return str;
}
Future<void> main() async {
await printOrderMessage();
}
In this case, the asynchronous operation is fetching the the user order from say a DB. Now because of Dart's await / async mechanism, every function that is related to the async operation is required to have a Future<> return type and must be tagged with async.
This feels clunky ... Imagine if some value deep in my function chain is being calculated asynchronously, would I really need to always return a future? Is there some other construct to synchronize code in Dart than await? Or have I misunderstood the concept?
If callers need to be able to wait for your asynchronous operation to finish, then your asynchronous function must return a Future that can be awaited. This is contagious; if callers of those callers need to be able to wait, then they too need to have Futures to wait upon.
If callers should not wait, then you can have a "fire-and-forget" function that does not need to return a Future:
Future<void> foo() {
// ...
}
// Does not need to return a Future. Consequently, callers cannot
// directly determine when `foo` completes.
void bar() {
foo();
}
All my repository methods are async for my CRUD operations using EF.Core async methods and use AutoMapper to map my EF entity model (Customer) to Domain Model (CustomerModel) and pass it back to my service layer.
public async Task<CustomerModel> GetCustomerByIdAsync(int id)
{
Customer customer = await _context.Customers.FindAsync(id);
var mappedResult = _mapper.Map<CustomerModel>(customer);
return await Task.FromResult(mappedResult);
}
Since "_mapper.Map" is not async but GetCustomerByIdAsync is, I return await Task.FromResult(mappedResult) instead of return mappedResult;
My caller method in service layer is also async. Have I got this right? I am also wondering about deadlock implications, although I am not calling any of my async methods from sync methods using .Result.
Thanks for your time.
Since "_mapper.Map" is not async but GetCustomerByIdAsync is, I return await Task.FromResult(mappedResult) instead of return mappedResult;
No, await Task.FromResult(x) doesn't ever make any sense. I've seen this code a lot, and I'm not sure where it comes from.
await Task.FromResult(x) is literally a less-efficient way of writing x. It's less efficient and less maintainable, so I have no idea where this idea came from.
Your code should look like:
public async Task<CustomerModel> GetCustomerByIdAsync(int id)
{
Customer customer = await _context.Customers.FindAsync(id);
var mappedResult = _mapper.Map<CustomerModel>(customer);
return mappedResult;
}
I am building a screen in an app using an existing model class which I can't modify. The model has a method called refreshList() which fetches some data from an API, processes it, and finally it updates a List member in a model with the fetched data.
I want to know the state of the list - i.e. is it uninitialized, being fetched or already fetched - so that I can update the UI accordingly.
The problem is that refreshList() is not async, but uses an async method internally. Additionally, the internal method doesn't return a Future.
void refreshList(){
if( someCondition ){
_doRefreshList();
}
}
void _doRefreshList() async{
// ... do stuff
http.Response response = await http.get(url);
// ... do some more stuff
}
I would like to do something like
setState((){ _isLoading = true; });
await model.refreshList();
setState((){ _isLoading = false; });
but unfortunately I can't modify the methods in the model to return a Future.
Is there any way to achieve this without modifying refreshList() to be async and return a Future, and modifying _doRefreshList() to return a Future?
No, there is no way to wait for an asynchronous operation to complete unless it provides some way to get a callback when it's done.
The usual way to do that is to return a future. Having a callback function parameter is another approach, but it's rarely better than just returning a future.
In your example, refreshVerList has no way to report when it is done, and neither does _doRefreshList. You will have to add that somehow, and returning a future is the simplest and most consistent way to solve the problem for both functions.
(Technically, the _doRefreshList function does return a future, it's just typed as void. You can cast that future to Future, but I strongly discourage that kinds of shenanigans. If the function author decides to return something else, say null, at a later point, they are perfectly within their right to do since the return type is void.)
You can use Completer.
Completer<Null> onFetchCompleter;
Future<Null> _doRefreshList() async{
onFetchCompleter = Completer();
// ... do stuff
http.Response response = await http.get(url);
// ... do some more stuff
onFetchCompleter.complete();
return onFetchCompleter.future;
}
In the same way you can user a completer in your refreshVerList method.
Create a Future with the function reference as argument:
Future(model.refreshList);
Now you can use await since the above gives you a Future<void>:
setState(() { _isLoading = true; });
await Future(model.refreshList);
setState(() { _isLoading = false; });