Future/Completer could be called only once? - dart

Please consider the following code:
import 'dart:async';
abstract class ClassAbstract
{
Completer<String> _onEvent1;
Completer<int> _onEvent2;
ClassAbstract()
{
_onEvent1 = new Completer<String>();
_onEvent2 = new Completer<int>();
}
Future get Event1
{
return _onEvent1.future;
}
Future get Event2
{
return _onEvent2.future;
}
}
class NormalClass extends ClassAbstract
{
NormalClass(): super()
{
_onEvent1.complete("Event1 rise");
for (int iCounter = 0; iCounter < 100; iCounter++)
{
_onEvent2.complete(iCounter);
}
}
}
void main() {
NormalClass normalClass = new NormalClass();
normalClass.Event1.then( (val) { print("Event1 rised"); } );
normalClass.Event2.then( (val) { print("Event2 rised: $val"); } );
print("Application close");
}
As you can see it's very simple code that has 1 abstract class with 2 Futures defined, getter for those 2 Futures. Another class that implement this abstract class and call the Features to simulate .NET events system.
The problem is whenever I run this code it fails with error in for(int iCounter....) line with error: Future already complete.
Does it mean that I can complete Future only once ?

That is correct. Futures are designed for one-use asynchronous calls. Basically a future can only provide one value. If you wish to provide multiple values then you will want to make use of a Stream. Using a StreamController you can easily add multiple values which can then be subscribed to.
So your sample would look like this:
import 'dart:async';
abstract class ClassAbstract
{
StreamController<String> _onEvent1;
StreamController<int> _onEvent2;
ClassAbstract()
{
_onEvent1 = new StreamController<String>();
_onEvent2 = new StreamContorller<int>();
}
Future get Event1
{
return _onEvent1.stream;
}
Future get Event2
{
return _onEvent2.stream;
}
}
class NormalClass extends ClassAbstract
{
NormalClass(): super()
{
_onEvent1.add("Event1 rise");
for (int iCounter = 0; iCounter < 100; iCounter++)
{
_onEvent2.add(iCounter);
}
}
}
and could be called something like this:
main() {
var sum = 0;
var thing = new NormalClass();
thing.Event1.listen((myStr) => print(myStr));
thing.Event2.listen((val) {
sum += val;
});
}

That's it. If you want to trigger several values you have to deal with Stream and StreamController. See Introducing new Streams API for more informations.

Yes, a Completer can only complete a Future once, which seems the most obvious to me. A Future is basically a token for an (read 'one') async operation. It will either succeed or fail.
What you are looking for in your case is an observer pattern where there is a source that dispatches events and listeners that will listen for events on the source. In this scenario, the source can dispatch the same event multiple times.
Edit: I was about to add some links to the Streams API, but Alexandre beat me to it. Check the API docs for more info.

Related

What is the difference between StreamSink and Sink?

I was coding a simple dart code and I couldn't see any difference between the implementation of StreamSink and Sink. By the way both have the same behaviour in this case.
int _counter = 0;
final _counterStreamController = StreamController<int>();
final _counterEventController = StreamController<CounterEvent>();
CounterBloc() {
_counterEventController.stream.listen(mapEventToState);
}
StreamSink<int> get _sinkCounter => _counterStreamController.sink;
Stream<int> get counter => _counterStreamController.stream;
Sink<CounterEvent> get counterEventSink => _counterEventController.sink;
void mapEventToState(CounterEvent event) {
if (event is IncrementEvent) {
_counter++;
}
_sinkCounter.add(_counter);
}
The StreamSink class implements a StreamConsumer and EventSink on top of a Sink.
StreamConsumer allows to add multiple Streams to a Sink, so your StreamSink can "output" several streams.
The EventSink provides the method to addErrors besides data to the stream.

How to run multiple async functions in order they were called (FIFO?)

I've spent many hours looking for the solution, but since I am Dart begginer, I couldn't find it out by myself.
What I want to achieve is to create something like queue for some of the async functions that are called randomly (let's say, when user is tapping a button in my app) from different points in code while the app is running. I want them to be executed in the order they were called, so basically I have async methods such as updateDate() and updatePoints() and when the user is tapping button X the updateDate() is going to be called (added to queue), and similar with Y and updatePoints(). When the user taps i. e. X, X, Y I want to run updateDate(), updateDate(), updatePoints() in this exact order. When one task is complete, another one is starting. I guess I can't use await to achieve that. Any hints would be appreciated!
import 'dart:async';
import 'dart:collection';
import 'dart:math';
Future<void> main() async {
_simulateRealWork();
}
Scheduler _scheduler = Scheduler();
class Scheduler {
bool _scheduled = false;
Queue<Future Function()> _queue = Queue<Future Function()>();
void schedule(Future Function() task) {
_queue.add(task);
if (!_scheduled) {
_scheduled = true;
Timer(Duration(seconds: 0), _execute);
}
}
Future _execute() async {
while (true) {
if (_queue.isEmpty) {
_scheduled = false;
return;
}
var first = _queue.removeFirst();
await first();
}
}
}
void _simulateRealWork() {
var maxPeriod = 5;
var count = 5;
for (var i = 0; i < count; i++) {
print('Timer $i');
var random = Random();
Timer(Duration(seconds: random.nextInt(maxPeriod)), () {
print('Scheduled work $i');
Future work() async {
print('Started work $i');
await Future.delayed(Duration(seconds: random.nextInt(maxPeriod)));
print('Ended work $i');
}
_scheduler.schedule(work);
});
}
}
Result:
Timer 0
Timer 1
Timer 2
Timer 3
Timer 4
Scheduled work 2
Started work 2
Scheduled work 0
Scheduled work 3
Ended work 2
Started work 0
Scheduled work 1
Scheduled work 4
Ended work 0
Started work 3
Ended work 3
Started work 1
Ended work 1
Started work 4
Ended work 4
The following code might be a bad practice when used in large queue of tasks, but if you are sure that the array of tasks won't exceed an adequate size - this might work just fine:
Future<List<T>> runOneByOne<T>(List<T Function()> list) {
if (list.isEmpty) {
return Future.value(null);
}
Future task = Future<T>.microtask(list.first);
final List<T> results = [];
for (var i = 1; i < list.length; i++) {
final func = list[i];
task = task.then((res) { results.add(res); return Future<T>.microtask(func); });
}
return task.then((res) { results.add(res); return results; });
}
It executes functions one-by-one in the original order by wrapping one Future into another. results array is used to store returned values, returning all of the values in the end.
Execution stops and throws if stumbled upon an error. Results array is lost in that case. You can add try {...} closure to every microtask wrapper to ignore errors and return null in that one particular task, preserving other values in results array.
Usage example:
runOneByOne<int>([
() { print("First"); return 1; },
() { print("Second"); return 2; },
() { print("Third"); return 3; },
]).then((results) {
print(results); // List<int> [ 1, 2, 3 ]
});

Avoid repetition in BLoCs and RxDart

hopefully I can make myself clear.
After video and tutorials, I found this way to have some widgets to input data to the bloc (valueSetting) and some others to get this data (value).
What I am asking is if there is a better way (there has to be..). I want to avoid the need to have 4 variables for just 1 real value shared between widgets.
import 'dart:async';
import 'package:rxdart/subjects.dart';
class BlocExample {
final _valueSettingController = StreamController<bool>();
// object use by widget to push data
Sink<bool> get valueSetting => _valueSettingController.sink;
final _value = BehaviorSubject<bool>(seedValue: false);
// object used by widget to get data
Stream<bool> get value => _value.stream;
BlocExample() {
_valueSettingController.stream.listen(_value.add);
}
void dispose() {
_value.close();
_valueSettingController.close();
}
}
First of, let me say that you can remove the private variables by using a custom factory constructor. Here's an example:
class MyBloc {
final Sink<bool> input;
final Stream<bool> output;
final VoidCallback _dispose;
MyBloc._({this.input, this.output, VoidCallback dispose}) : _dispose = dispose;
factory MyBloc() {
final mainController = BehaviorSubject(seedValue: false);
return MyBloc._(
input: mainController.sink,
output: mainController.stream,
dispose: () {
mainController.close();
},
);
}
void dispose() {
_dispose();
}
}
Secondly, the problem you're trying to solve is actually not a problem. While it seems at first that there's a lot of duplicates; in reality they serve different purposes.
In many situations, your Stream will be more than just _controller.stream. For example, for whatever reason you may want to transform the value before exposing it:
final mainController = BehaviorSubject(seedValue: false);
final Stream<bool> output = mainController.map((foo) => !foo);
This code makes that the output stream reverses the value of everything passed to mainController.sink
But in my situation this is not the case. So why 3 variables that point to the same thing?
The fact that in your situation, your controller is both the sink and stream without transformation is an implementation detail and may be subject to changes.
By exposing Sink/Stream as done before, you actually abstract this implementation detail. So that in the future if your stream needs custom operations; no change will be required by your UI.
This is not necessary. But recommended.
You can do something like this :)
enum STREAM_GROUP {
TYPE1,TYPE2,TYPE3
}
class BlocExample {
Map<STREAM_GROUP, StreamController<bool>> groups = new Map();
Stream<bool> getValue(STREAM_GROUP type){
return groups[type].stream;
}
Sink<bool> getValueSetting(STREAM_GROUP type){
return groups[type].sink;
}
BlocExample() {
groups[STREAM_GROUP.TYPE1] = StreamController<bool>();
groups[STREAM_GROUP.TYPE2] = StreamController<bool>();
groups[STREAM_GROUP.TYPE3] = StreamController<bool>();
groups.forEach((groupType, streamController){
final currentValue = BehaviorSubject<bool>(seedValue: false);
streamController.stream.listen(currentValue.add);
});
}
void dispose() {
groups.forEach((groupType, streamController){
streamController.close();
});
}
}

Future is completed before function-call is done

I'm working with two functions, both of them should return a future. A third function gets called when both of them are done. Right now the future is returned too early, so that my third function is called before my second function is completed.
Function1:
static var getObjectDataCompleter = new Completer();
static var fillObjectCompleter = new Completer();
static Future getObjectData(List jsonMap) {
for (int i = 0; i < jsonMap.length; i++) {
fillObjectCompleter = new Completer();
var request = buildRequest("GET", resourceUrl);
request.send();
request.onLoadEnd.listen((event) => fillObject(request));
}
if(fillObjectCompleter.isCompleted) {
getObjectDataCompleter.complete(null);
}
return getObjectDataCompleter.future;
}
Function2:
static Future fillObject(HttpRequest request) {
String responseText = request.response;
List stringJson = JSON.decode(responseText);
fillObjectCompleter.complete(null);
return fillObjectCompleter.future;
}
Function1 is returning the future before the call "fillObject()" is completed.
What am I doing wrong?
The function1-future should be returned when the "for-loop" is done and all "fillObject-calls" are completed.
Async code is just scheduled for later execution and the sync code continues executing without waiting for the async code. The method you pass ot Future.then(...) is executed when the scheduled async code is finished. You find a lot of such questions and examples tagged [:dart-async:] here on StackOverflow.
I have a hard time figuring out what you actually try to accomplish. Can you please explain in prosa what you actually try to accomplish, then I can try to fix your code example to do what you want it to do.
Usually there is no need to use a Completer in custom async functions. You just have to ensure that nested async calls are properly chained by always returning the future of the call.
See these two lines of the following code as example. The returns are important for the example to work.
return async.Future.forEach(jsonMap, (item) {
return request.onLoadEnd.first.then((event) => fillObject(event.target));
The Future returned from getObjectData completes after the response of all requests are processed.
import 'dart:html' as dom;
import 'dart:async' as async;
import 'dart:convert' show JSON;
class Xxx {
static async.Future getObjectData(List jsonMap) {
return async.Future.forEach(jsonMap, (item) {
//var request = new dom.HttpRequest();
//request.open("GET", "https://www.googleapis.com/discovery/v1/apis?fields=");
var request = buildRequest("GET", resourceUrl);
request.send();
return request.onLoadEnd.first.then((event) => fillObject(event.target));
});
}
static fillObject(dom.HttpRequest request) {
print('fillObject');
String responseText = request.response;
List stringJson = JSON.decode(responseText);
}
}
void main() {
var json = ['a', 'b', 'c'];
Xxx.getObjectData(json).then((_) => print('done'));
}
See https://www.dartlang.org/articles/event-loop for more details about async execution.

Streams equivalent to Observable.Throttle?

Is there a Streams equivalent to Observable.Throttle? If not -- is there any reasonably elegant way to achieve a similar effect?
There's no such method on streams for now. A enhancement request has been filed, you can star issue 8492.
However, you can do that with the where method. In the following exemple, I have defined a ThrottleFilter class to ignore events during a given duration :
import 'dart:async';
class ThrottleFilter<T> {
DateTime lastEventDateTime = null;
final Duration duration;
ThrottleFilter(this.duration);
bool call(T e) {
final now = new DateTime.now();
if (lastEventDateTime == null ||
now.difference(lastEventDateTime) > duration) {
lastEventDateTime = now;
return true;
}
return false;
}
}
main() {
final sc = new StreamController<int>();
final stream = sc.stream;
// filter stream with ThrottleFilter
stream.where(new ThrottleFilter<int>(const Duration(seconds: 10)).call)
.listen(print);
// send ints to stream every second, but ThrottleFilter will give only one int
// every 10 sec.
int i = 0;
new Timer.repeating(const Duration(seconds:1), (t) { sc.add(i++); });
}
The rate_limit package provides throttling and debouncing of Streams.
#Victor Savkin's answer is nice, but I always try to avoid reinventing the wheel. So unless you really only need that throttle I'd suggest using the RxDart package. Since you are dealing with Streams and other reactive objects RxDart has a lot of nice goodies to offer besides throttling.
We can achieve a 500 millisecond throttle several ways:
throttleTime from ThrottleExtensions<T> Stream<T> extensions: stream.throttleTime(Duration(milliseconds: 500)).listen(print);
Combining ThrottleStreamTransformer with TimerStream: stream.transform(ThrottleStreamTransformer((_) => TimerStream(true, const Duration(milliseconds: 500)))).listen(print);
Using Debounce Extensions / DebounceStreamTransformer: stream.debounceTime(Duration(milliseconds: 500)).listen(print);
There are some subtle differences regarding delays, but all of them throttles. As an example about throttleTime vs. debounceTime see What is the difference between throttleTime vs debounceTime in RxJS and when to choose which?
The following version is closer to what Observable.Throttle does:
class Throttle extends StreamEventTransformer {
final duration;
Timer lastTimer;
Throttle(millis) :
duration = new Duration(milliseconds : millis);
void handleData(event, EventSink<int> sink) {
if(lastTimer != null){
lastTimer.cancel();
}
lastTimer = new Timer(duration, () => sink.add(event));
}
}
main(){
//...
stream.transform(new Throttle(500)).listen((_) => print(_));
//..
}

Resources