Dart async/await internals - dart

I'm searching for the source of async/await implementations.
I would like to know how do they truly works in order to hack into future.then() to detect if there is code awaiting for execution or not.
Edit
This is what I'm willing to accomplish:
TrackingCompleter completer = new TrackingCompleter();
TrackingFuture future = completer.future;
print("isAwaited: ${future.isAwaited} (F)");
new Future.delayed(new Duration(milliseconds: 500), () {
future.then((_) {
print("executing sorping");
print("isThenExecuted: ${future.thenExecuted} (F)");
new Future.delayed(new Duration(milliseconds: 500), () {
print("isThenExecuted: ${future.thenExecuted} (T)");
exit(1);
});
});
print("isAwaited: ${future.isAwaited} (T)");
print("isThenExecuted: ${future.thenExecuted} (F)");
completer.complete();
});
As far, that's working. What I'd like to do now is to detect if future.then is called manually in the code or automatically with an await statement.

The async/await implementation is based on futures.
Basically, await creates a function that contains the rest of the current function (the "continuation" of the await expression), and then calls then on the future you await with that function as argument.
There are more details needed to handle errors, but that's basically it.
In your case, if you want to know if future.then is called, I recommend just wrapping that particular future. Example:
import "package:async/async.dart";
class ThenWrapper<T> extends DelegatingFuture<T> {
void Function(S Function(T), S Function(Object, StackTrace)) _callback;
ThenWrapper(Future<T> future, this._callback): super(future);
Future<S> then<S>(S onValue(T), {S onError(error, StackTrace st)}) {
_callback(onValue, onError);
return super.super(onValue, onError);
}
}
...
TrackingFuture future = new ThenWrapper(completer.future, ...);
You can change the callback to do whatever you want.

Related

Break async / wait declaration chain in Dart

I wonder if you can escape the async / wait chain in Dart. AFAIK every time you want to make a sync call to an async function you must use await but this forces you to make the function which holds the instruction to become async too.
Here is an example:
Future<String> helloAsync() async{
return Future.delayed(const Duration(seconds: 2), ()=>'Hello');
}
void helloSync(){
//call helloAsync synchronously (somehow without making this function async)
//print returned value
}
void main(){
helloSync();
}
In here if I want to make a sync call to helloAsync() inside the HellowSync() I must add await like:
void helloSync(){
String s = await helloAsync();
print(s);
}
but this will not work until I add the async keyword for it - and if I do this means that I have to do it for main() function too.
Is there a way to break this chain of async / await declaration?
(In the initial example this would mean no async declaration for main function)
You could use .then() instead. You can't return the result of a Future from a synchronous function, but since your helloSync() returns void anyway, .then() might be what you are looking for.
void helloSync(){
helloAsync().then((result) => print(result));
}

How do you create a Future in Dart with a lambda/higher-order function and resolve it?

I'm having trouble figuring out a way to do the equivalent of the following Javascript code in Dart:
async function main(){
await new Promise((resolve) => {
setTimeout(resolve, 200);
});
// stuff after 200ms happens here
}
It's nice to be able to create a Promise and resolve it on the fly... can you also do this in dart? I've read about completers, but the examples use "regular" functions, rather than lambda/higher-order ones.
I am not entirely sure what you want but you can write your own example as this in Dart:
import 'dart:async';
Future<void> main() async {
print(DateTime.now().millisecond); // 417
await Future<void>.delayed(const Duration(milliseconds: 200));
print(DateTime.now().millisecond); // 625
}
Maybe a more directly conversion would be:
import 'dart:async';
Future<void> main() async {
print(DateTime.now().millisecond); // 417
await () async {
await Future<void>.delayed(const Duration(milliseconds: 200));
}();
print(DateTime.now().millisecond); // 625
}
The given ECMAScript snippet has an error, setTimeout is supposed to be called on a function, not undefined.
Also, it doesn't really need to be a lambda at all.
function delay_200(resolve) {
setTimeout(resolve, 200);
};
// statically allocated delay function
async function main() {
await new Promise(delay_200);
// stuff after 200ms happens here
}
Now, I haven't used Dart in quite some time, but I think it would be equivalent to the following:
Future<void> main() async {
await Future.delayed(
Duration(milliseconds: 200)
);
// stuff after 200ms happens here
}
Now, I'm honestly not sure if you can construct a Future like you can a Promise, so I didn't really answer the primary question.

Dart / Flutter: async behaviour of an Isolate's top level function

Aye Aye good people,
I'm experiencing a weird behavior
when using the top level function of an isolate asynchronously;
you can find example code HERE, but in short
as top level function of an isolate this works:
String _syncHandle(int data) {
return 'done';
}
and this doesn't:
Future<String> _syncHandle(int data) async {
return 'done';
}
can anybody explain me why?
(or if should work, why isn't doing so in my code?)
thank you in advance
Francesco
...
[edit: just noticed that a similar question has been asked,
nevertheless it is still unanswered
Call async function from Isolate function,
plus issue open on github ]
forgot to update this :/
if you look at the code linked in the question
isolates_logging/lib/provider/test_isolate.dart
Future<void> _handle(int _m) async {
final response = ReceivePort();
isolateTest = await Isolate.spawn(_isolate, response.sendPort);
final sendPort = await response.first as SendPort;
final answer = ReceivePort();
sendPort.send([_m, answer.sendPort]);
await answer.first.then((p) {
_outbound.sink.add(p);});
}
static void _isolate(SendPort _initialReplyTo) {
final port = ReceivePort();
_initialReplyTo.send(port.sendPort);
port.listen((message) {
final data = message[0] as int;
final send = message[1] as SendPort;
send.send(_syncHandle(data));
});
}
}
Future<String> _syncHandle(int data) async {
return 'done';
}
note the send.send(_syncHandle(data)); part
if you do so, you can send only primitives and not futures,
basically that's it

Is there a good way to write "wait for variables to change" in Dart's async method?

I wrote a program in Dartlang that stops processing until the variable foo becomes false as shown below.
It is executable, but continuing to return Future in a while statement is clumsy.
Is there a way to write it clearly?
Future asyncMethod() async {
while (foo) {
await new Future(() {
return null;
});
}
Unity's coroutine can be written in a single line as below, so I'd like to make this much clearer.
yield return new WaitWhile(() => foo);
You are polling the variable at intervals using a timer. There are lots of ways to do that. I'd just go for the completely straight-forward implementation:
Future waitWhile(bool test(), [Duration pollInterval = Duration.zero]) {
var completer = new Completer();
check() {
if (!test()) {
completer.complete();
} else {
new Timer(pollInterval, check);
}
}
check();
return completer.future;
}
With that function, you can then just write
await waitWhile(() => foo);
to wait for foo to become false.
By using Future.doWhile.
Without a polling interval:
await Future.doWhile(() => isPaused);
With a polling interval:
if (isPaused) {
await Future.doWhile(() => Future.delayed(interval).then((_) => isPaused));
}

What are the pros and cons of async, when to and when not to use it and what other alternatives to callback are there?

callbacks or asynchronous methods or other options
A solution to the callback plague is "await" and "async" or more specifacally 'dart:async' library.
Now, what is the cost of asynchrony?
When should we not use them?
What are the other alternatives?
The below is a badly coded non-polymer custom element that acts like a messageBox in desktop environment. It gives me less braces and parenthesis-es but requires the caller to be also async or use "show().then((v){print(v);});" pattern. Should I avoid the pattern like this?
Is callback better? Or there is an even smarter way?
Polling version
import 'dart:html';
import 'dart:async';
void init(){
document.registerElement('list-modal',ListModal);
}
class ListModal extends HtmlElement{
ListModal.created():super.created();
String _modal_returns="";
void set modal_returns(String v){
///use the modal_returns setter to
///implement a custom behaviour for
///the return value of the show method
///within the callback you can pass on calling append .
_modal_returns=v;
}
factory ListModal(){
var e = new Element.tag('list-modal');
e.style..backgroundColor="olive"
..position="absolute"
..margin="auto"
..top="50%"
..verticalAlign="middle";
var close_b = new DivElement();
close_b.text = "X";
close_b.style..right="0"
..top="0"
..margin="0"
..verticalAlign="none"
..backgroundColor="blue"
..position="absolute";
close_b.onClick.listen((_){
e.hide();
});
e.append(close_b,(_)=>e.hide());
e.hide();
return e;
}
#override
ListModal append(
HtmlElement e,
[Function clickHandler=null]
){
super.append(e);
if(clickHandler!=null) {
e.onClick.listen(clickHandler);
}else{
e.onClick.listen((_){
this.hide();
_modal_returns = e.text;
});
}
return this;
}
Future<String> show() async{
_modal_returns = '';
this.hidden=false;
await wait_for_input();
print(_modal_returns);
return _modal_returns;
}
wait_for_input() async{
while(_modal_returns=="" && !this.hidden){
await delay();
}
}
void hide(){
this.hidden=true;
}
Future delay() async{
return new Future.delayed(
new Duration(milliseconds: 100));
}
}
Non-polling version
In response to Günter Zöchbauer's wisdom(avoid polling), posting a version that uses a completer. Thanks you as always Günter Zöchbauer:
import 'dart:html';
import 'dart:async';
void init(){
document.registerElement('list-modal',ListModal);
}
class ListModal extends HtmlElement{
ListModal.created():super.created();
String _modal_returns="";
Completer _completer;
void set modal_returns(String v){
///use the modal_returns setter to
///implement a custom behaviour for
///the return value of the show method.
///Use this setter within the callback for
///append. Always call hide() after
///setting modal_returns.
_modal_returns=v;
}
factory ListModal(){
var e = new Element.tag('list-modal');
e.style..backgroundColor="olive"
..position="absolute"
..margin="auto"
..top="50%"
..verticalAlign="middle";
var close_b = new DivElement();
close_b.text = "X";
close_b.style..right="0"
..top="0"
..margin="0"
..verticalAlign="none"
..backgroundColor="blue"
..position="absolute";
close_b.onClick.listen((_){
e.hide();
});
e.append(close_b,(_){e.hide();});
e.hide();
return e;
}
#override
ListModal append(
HtmlElement e,
[Function clickHandler=null]
){
super.append(e);
if(clickHandler!=null) {
e.onClick.listen(clickHandler);
}else{
e.onClick.listen((_){
_modal_returns = e.text;
this.hide();
});
}
return this;
}
Future<String> show() async{
_modal_returns = '';
_completer = new Completer();
this.hidden=false;
return _completer.future;
}
void hide(){
hidden=true;
_completer?.complete(_modal_returns);
_completer=null;
}
}
Usually there is no question whether async should be used or not. Usually one would try to avoid it. As soon as you call an async API your code goes async without a possibility to choose if you want that or not.
There are situations where async execution is intentionally made async. For example to split up large computation in smaller chunks to not starve the event queue from being processed.
On the server side there are several API functions that allow to choose between sync and async versions. There was an extensive discussion about when to use which. I'll look it up and add the link.
The disadvantages of using async / await instead of .then() should be minimal.
minimal Dart SDK version with async / await support is 1.9.1
the VM needs to do some additional rewriting before the code is executed the first time, but this is usually neglectable.
Your code seems to do polling.
wait_for_input() async {
while(_modal_returns=="" && !this.hidden){
await delay();
}
}
This should be avoided if possible.
It would be better to let the modal manage its hidden state itself (by adding a hide() method for example), then it doesn't have to poll whether it was hidden from the outside.

Resources