dart event loop, futures and streams

A Future represents a single value that might end up as data, error, or incomplete. For each of these states we wire up different handlers. For data we use the then method on the Future, which takes a function (data) {}, where data is the input that enters the event loop asynchronously.

Future.value(5).then((data) { 
    print(data); 
})

Pay special attention here.

Incase it wasn't a regular data like 5, but an error, we could setup the handler like this:

Future.value(5).then((data) { 
    print(data); 
}).catchError(error) {
    print("Error: $error");
}

Here, even though .catchError was invoked on the .then of the Future, both are meant to handle the same Future. But if instead of .catchError we used a .then we are working on a different Future: the one returned by the handler of the previous Future. For example:

Future.value(5).then((data) { 
    return 10;
}).then(value) {
    print("$value + 5 = 15")
}

The second then is a handler for a new Future (value 10) while the first catchError worked on the First future had the value been an error.

The event loop really runs the show. All streams let the data in into the event loop, where handlers are set to work with it synchronously (unless Isolates are explictly used). Note: What's asynchronous here is just delivery of events originating from other threads into the event loop thread/the main thread. So its asynchronous delivery and synchronous handling.

Let's start with the basic stdin. stdin (like stdout and stderr) is managed by the kernel. You don't get the typical .close() method for this stream. The closing of this stream is done by the kernel when the process finishes.

import 'dart:convert';
import 'dart:io';

void main() {
  List<int> input = [];
  stdin.lineMode = false;
  stdin.echoMode = false;
  var subscription;

  subscription = stdin.listen((List<int> data) {
    if (data[0] == 4) {
      // Reset terminal modes before exiting
      stdin.lineMode = true;
      stdin.echoMode = true;
      subscription.cancel();

      print("Input:");
      print(utf8.decode(input));
    }

    // if (!ListEquality().equals(data, [127])) {
    if (data[0] != 127) {
      // Add the character to our input buffer
      input.addAll(data);
      // Display the character
      stdout.write(utf8.decode(data));
    } else {
      // Handle backspace
      if (input.isNotEmpty) {
        // Remove last character from buffer
        input.removeLast();
        // Move cursor back, print space to overwrite, move cursor back again
        stdout.write('\b \b');
      }
    }
  });
}

Comments