future_goodies 0.6.1

Dart Future Goodies #

Build Status

Future goodies for Dart.

Install #

Just add to your pubspec.yaml:

  future_goodies: any

Usage #

Future goodies provides some helper functions to deal with Future management. Here we going to document each function.

allCompleted #

Given a list of futures, return all that completed successfully after all of then responded

 new Future.value(1),
 new Future.error('err'),
 new Future.value(2)]).then((List results) {
   print(results); // [1, 2]

This function is the inverse of [allRejected].

allRejected #

Given a list of futures, return all that got error

 new Future.value(1),
 new Future.error('err'),
 new Future.value(2)]).then((List results) {
   print(results); // ['err']

This function is the inverse of [allCompleted].

sequence #

This function iteraters over a collection by calling the iterator, this iterator can either return a value, or a Future, if a Future is returned, the iteration will wait until it completes before running the next iteration. This function returns a Future, that will resolve as a List containing the result values (all resolved) of the iteration. If any iteration fails (sync or async) the sequence will stop and the Future returned by it will fail with the error.

import 'package:future_goodies/future_goodies.dart';
import 'dart:async';

Future delayed(value) {
  return new Future.delayed(new Duration(milliseconds: 20), () => value));

void main() {
  Future<List<int>> result = sequence([1, 2, 3, 4], (n) => delayed(n * 2));

  result.then((List<int> values) {
    print(values); // [2, 4, 6, 8]

pipeline #

Reduces a collection to a single value by iteratively combining each element of the collection with an existing value using the provided function. The iterator must return a Future, and the iterator will wait for it before moving on.

If any iteration fails the result Future will fail with same error.

Future simpleDelay(value) => new Future.delayed(new Duration(milliseconds: 10));

pipeline('', ['a', 'b', 'c'], (String acc, String v) => simpleDelay(acc + v)).then((String result) {
  print(result); // 'abc'

FutureWorker #

Managers a Future worker poll

The purpouse of this class is to help when you need to impose some limit for Future calls. You just need to initialize with the limit number of workers, then you call push passing a function that returns a Future and with that the worker will manage to call this function when the poll has space:

class SimpleJob {
  bool started = false;
  Completer completer = new Completer();

  Future run() {
    started = true;

    return completer.future;

FutureWorker worker = new FutureWorker(2);

SimpleJob job1 = new SimpleJob();
SimpleJob job2 = new SimpleJob();
SimpleJob job3 = new SimpleJob();

Future future1 = worker.push(job1.run); // will call right way since the poll is free
Future future2 = worker.push(job2.run); // same as before, still have space
Future future3 = worker.push(job3.run); // will be queued and hold

job1.started; // true
job2.started; // true
job3.started; // false


new Future.microtask(() {
  job3.started; // true

future3.then((value) {
  value; // done, after the job3 completes


You probably going to use it when you wanna limit calls for a server and stuff like that, so since adding a timeout is a common practice (to avoid the poll to never get free slots) you can send a duration to timeout when constructing the worker.

FutureWorker worker = new FutureWorker(2, timeout: new Duration(seconds: 15));

settle #

Makes a list of futures always completes, returning the state of the completion.

settle([new Future.value('hello'), new Future.error('err')]).then((List<SettleResult> results) {
  results[0]; // <SettleResult status:#completed result:hello>
  results[1]; // <SettleResult status:#rejected error:err>

If you wanna do it for a single future, check [SettleResult.settle]

SettleResult.settle #

Wraps a future to always completes with a SettleResult

This function will return a [Future], this future will be an instance of [SettleResult].

Given the original future has completed with success, the [SettleResult] will have the [status] value of [COMPLETED] and the [result] will have the completion value.

Given the original future fails, the [SettleResult] will have the [status] as [REJECTED] and the error will contain the thrown error.

SettleResult.settle(new Future.value('ok')).then((SettleResult res) {
 res.status; // SettleResult.COMPLETED
 res.result; // 'ok'
 res.error; // null

SettleResult.settle(new Future.error('err')).then((SettleResult res) {
  res.status; // SettleResult.REJECTED
  res.result; // null
  res.error; // 'err'

unfold #

The methods [sequence] and [pipeline] are great ways to process asynchronous arrays of futures and tasks. Sometimes, however, you may not know the array in advance, or may not need or want to process all the items in the array.

For example, here are a few situations where you may not know the bounds:

  1. You need to process a queue to which items are still being added as you process it
  2. You need to execute a task repeatedly until a particular condition becomes true
  3. You need to selectively process items in an array, rather than all items

In these cases, you can use when/unfold to iteratively (and asynchronously) process items until a particular condition, which you supply, is true.

Future future = unfold(unspool, stopCondition, handler, seed);


  • [unspool] - function that, given a seed, returns a [valueToSendToHandler, newSeed] pair. May return a list, list of futures, future for an list, or future for an list of futures.
  • [stopCondition] - function that should return truthy when the unfold should stop
  • [handler] - function that receives the valueToSendToHandler of the current iteration. This function can process valueToSendToHandler in whatever way you need. It may return a [Future] to delay the next iteration of the [unfold].

Send values produced by [unspool] iteratively to [handler] until a condition is true. The [unspool] function acts like a generator, taking a [seed] and producing a pair of [value, newSeed] (or a [Future] pair, see above). The value will be passed to [handler], which can do any necessary on or with value, and may return a future. The newSeed will be passed as the [seed] to the next iteration of [unspool].

Examples #

This example generates random numbers at random intervals for 10 seconds.

The condition could easily be modified (to return false;) to generate random numbers forever. Interestingly, this would not overflow the call stack, and would not starve application code since it is asynchronous.

Random random = new Random();

// set end time for 10 seconds from now
DateTime end = new DateTime.now().add(new Duration(seconds: 10));

// Generate random numbers at random intervals!
// Note that we could generate these forever, and never
// blow the call stack, nor would we starve the application
Function unspool = (seed) {
  // seed is passed in, although for this example, we don't need it

  // Return a random number as the value, and the time it was generated
  // as the new seed
  var next = [random.nextInt(100), new DateTime.now()];

  // Introduce a delay, just for fun, to show that we can return a future
  return new Future.delayed(new Duration(milliseconds: random.nextInt(1000)), () => next);

// Stop after 10 seconds
Function condition = (DateTime time) {
  return time.isAfter(end);

Function log = (value) {

DateTime start = new DateTime.now();

unfold(unspool, condition, log, start).then((_) {
  print('Ran for ' + new DateTime.now().difference(start).inMicroseconds.toString() + 'ms');

unfoldList #

Unfold resolving into a list

unfoldList(unspool, stopCondition, seed);


  • [unspool] - function that, given a seed, returns a [valueToAddToList, newSeed] pair. May return an array, array of futures, futures for an array, or future for an array of futures.
  • [stopCondition] - function that should return truthy when the unfold should stop
  • [seed] - intial value provided to the first [unspool] invocation. May be a [Future].

Generate a list of items from a [seed] by executing the [unspool] function while [stopCondition] returns true. The result [Future] will fulfill with a [List] containing all each valueToAddToList that is generated by [unspool].

Function stopCondition = (int i) => i == 3;
Function unspool = (int x) => [x, x + 1];

unfoldList(unspool, stopCondition, 0).then((List<int> values) {
  print(values); // [0, 1, 2]

The methods [unfold] and [unfoldList] ideas and a lot of documentation text was were extracted from the great When library: https://github.com/cujojs/when/blob/master/docs/api.md#unbounded-lists

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  future_goodies: ^0.6.1

2. Install it

You can install packages from the command line:

with pub:

$ pub get

Alternatively, your editor might support pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:future_goodies/future_goodies.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

The package version is not analyzed, because it does not support Dart 2. Until this is resolved, the package will receive a health and maintenance score of 0.

Analysis issues and suggestions

Support Dart 2 in pubspec.yaml.

The SDK constraint in pubspec.yaml doesn't allow the Dart 2.0.0 release. For information about upgrading it to be Dart 2 compatible, please see https://dart.dev/dart-2#migration.

Maintenance issues and suggestions

Make sure dartdoc successfully runs on your package's source files. (-10 points)

Dependencies were not resolved.