×

Dart Future and Stream

Before understanding Future and Stream in Dart, we need first to get familiar with two terms : Synchronous and Asynchronous Programming. 

In synchronous programming, a single operation is handled at a time, and the processing proceeds to the next operation only when the first one is completed. While in asynchronous programming, we can take up another task even if the previous one is not finished. 

Dart supports Asynchronous programming with the help of ‘Future’ and ‘Stream’ classes. 

Future refers to the processing that is left incomplete in-between. An asynchronous function returns Future that tells when the result will be ready. 

Stream refers to the sequence of asynchronous events which keep you informed of the next events in line. 

Future

Future represents the value or error that is supposed to be available in the Future. Handling such errors or values at the time they would be available, is mandatory and should be taken care of. 

Implementation = Future <data_type> class_name

They can basically exist in three states: 

  1. Uncompleted 
  2. Completed with a value
  3. Completed with an error 
Dart Future And Stream

Every Dart code that we write, a single thread is dedicated to picking events from the event queue and processing them for the program's execution.

Future Constructors

A Future constructor is a constructor that takes a function as the parameter and returns some value which can be Future or non - Future. In simple words, it creates a Future that contains the result of the process that calls that Future. 

The result can be one of the following options : 

  1. Throws = The Future returned is completed with an error. 
  2. Future itself = The Future returned is completed first, and then the completion of the created Future takes place. 
  3. Non – Future = The returned Future is completed with the value returned. 

Implementation =  factory Future( FutureOr <T> computation( ) ) ;

Properties 

  1. HashCode = 

Returns the hash code for a numerical value, and it returns the same value for int and doubles when the value provided is the same. 

Implementation = int get hashchode ;

  • Runtime Type =

Represents the type of runtime an object has. 

Implementation = Type get runtimeType ;

Methods

  • asStream( ) =

This method creates a stream that contains the result of the completion of the specified Future. If a Future remains incomplete, the stream would never be able to produce any events. While, if the Future is complete, the stream executes the event and eventually closes down. 

Implementation = Stream<T> asStream( ) ;

  • catchError( ) =

This method is used to handle all the errors that the Future emits. It returns a new completed Future with some result which could be of the Future or the call back ' onError '. The Future can complete with the following cases :

  • With a value = The Future returned is completed with this same value.
  • With an error = Test is called with the error value. In this case, the completion of Future depends on the Boolean value of the test :
  • True = The error calls the ' onError ', and with the result of this call, Future is executed. 
  • False = The exception is now not handled by ' catchError ' and the Future is made to complete with the same error. 
  • Omitted = The default value is true, and the function is supposed to always return true if the test is omitted. 

Implementation = 

Future<T> catchError (

          Function onError ,

                 { bool test (

                       Object error

                          ) ? }

               )
  • then< R > =

This method registers all the callbacks that have to be made as soon as the Future is completed. As we know by now, a future can complete with a value or an error; let us then understand how the method works in each case : 

  1. Completes with a value = The ' onValue ' callback will be called with the value with which the Future is completed. Depending upon the time of Future's completion, the callback is scheduled. If it is already completed, a callback won't be made immediately but would schedule for later. 
  2. Completes with an error = The ' onError ' callback will be called with the error with which the Future is completed. Remember that the ' onError ' callback must return a value or Future to complete the returned Future with either of these two.

Finally, it returns a Future that is completed with the results of the call to

‘ onValue ' or ' onError '. If the callback returns a Future, completion of Future returned by ' then ' would be completed with the same result as of the returned Future. Else if the callback throws, the returned Future is completed with the thrown error. 

If ' onError ' is not given, and this Future completes with an error, the error is forwarded directly to the returned Future.

Implementation = 

Future<R> then<R> (

             FutureOr<R> onValue (

                                 T value

                         ) ,

           { Function? onError }

) ;
  • toString( ) =

Converts a given number into an equivalent shortest string and returns the same. 

Implementation = external String toString( ) ;

  • whenComplete( ) =

This method registers a function to be called when this Future completes. Irrespective of whether a Future completes with a value or an error, the action function is called. Asynchronously, this is equivalent to the " finally " block. 

When this call is invoked, it returns a Future that would be completed in the same way as it was completed, unless an error occurs. If in case, the call does not return a Future, the value returned is ignored. And if it throws, the Future completes with that thrown error.

Let us say if the call returns another Future, then the Future returned previously is left in between until the completion of this another future. If this Future completes with an error, then the previous Future also completes with the same error. Remember that the value, as a result, is ignored. 

Implementation = 

Future<T> whenComplete (

      FutureOr<void> action (

) ;

Stream

Stream is a way by which we receive a sequence of events. These events can correspond to :

  1. Data event which is also known as the element of the stream.
  2. Error event which intimates if the event has failed. 

When the stream is done with emitting all the events, it notifies a single

' done ' event which signifies the end. We can use the listen( ) method with the function as a parameter to subscribe to the stream. 

We receive these events by an active object of the stream called as StreamSubscription object. Using this object, we can either entirely terminate the notification update of the event or temporarily pause it. 

Types of Streams 

  1. Single – subscription stream
  2. Broadcast stream

Single-subscription Stream

This stream enables only a single listener to receive the event. It starts emitting events only when the listener is active and stops generating them as soon as the listener unsubscribes. 

Remember that two listeners aren't allowed on a single-subscription stream even though the first one is cancelled. 

Broadcast Stream

This stream enables any number of listeners and notifies the events as soon as they are ready, irrespective of whether the listeners are available or not. They are mainly used for independent events. 

asBroadcastStream is used to enable several listeners to listen to a single subscription stream. 

By default, the streams are single-subscription streams. In the case of listening to a stream twice, the compiler throws an exception.

Stream Constructors 

  • Stream<T> constructor  =

This constructor is used to create a stream. 

Implementation = Stream( ) ; 

  • Stream.empty( ) =

This constructor is used to create an empty broadcast stream, and it performs a single task of sending ‘ done ’ events when the stream is listened to. 

Implementation = const factory Stream.empty( ) = _EmptyStream<T> ;

  • Stream.error( ) =

This constructor is used to create a stream that emits a single error before completing. Then it stackTrace and completes with a ‘ done ’ event. 

Implementation = 

Stream< T >.error (

Object error,

[ StackTrace? stackTrace ]

)

Stream Properties

  • First =

This property returns the first element of the given stream. As soon as the first element is retrieved, listening to this stream is stopped, by implicitly unsubscribing the method. 

There can be two cases of its working : 

  • The stream is empty = In this case, the Future returned by the stream completes with an error. 
  • Occurrence of some error event = In this case, the Future returned by the stream completes with that error. 

 Implementation = Future<T> get first { } 

  • hashCode =

Returns the hash code for a numerical value, and it returns the same value for int and doubles when the value provided is the same. 

Implementation = int get hashchode ;

  • isEmpty =

This property checks whether the given stream contains any elements or not and accordingly returns true or false. 

  • True = When the stream ends without emitting any elements, indicating that the stream is empty. 
  • False = When the stream emits an element. 

If the event causes an error, the future returned is completed with that error. 

Implementation = Future<bool> get isEmpty { }

  • Last =

This property returns the last element of the stream. In case of any error caused by the stream, the future returned is completed with that error. And if the stream is empty, the future returned completes with an error. 

Implementation = Future<T> get last { }

  • Length =

This property calculates the number of elements in the stream and returns the same. At the end of this stream, the future returned is completed with the number of elements calculated by this property. 

If, in any case, the stream causes an error, the future returned is completed with that error, terminating the processing. 

Implementation = Future<int> get length { }

  • runtimeType =

Represents the type of runtime an object has. 

Implementation = Type get runtimeType ;

  • single =

This property returns the single element of the given stream. If, in any case, the stream causes an error, the future returned is completed with that error, terminating the processing. 

If the stream is empty or has more than a single element, the future returned is completed with an error. 

Implementation = Future<T> get single { }

  • isBroadcast =

This property checks whether this stream is a broadcast stream or not and accordingly returns true or false. 

Implementation = bool get isBroadcast ;

Methods

  • any( ) =

This method checks whether ' test ' accepts any element provided by the stream. Here, we call ' test ' on each and every element of the stream to check the same. If it returns true, the future returned is completed with true. Else if the stream returns false, the future returned is completed with false. 

If, in any case, the stream causes an error or the call to test throws, the future returned is completed with that error. 

Implementation = 

Future<bool> any (

bool test (

             T element

)

           )
  • asBroadcastStream( ) =

This method returns a multi-subscription stream that produces the event as same as this. The stream returned will subscribe to this given stream.

Implementation = 

Stream<T> asBroadcastStream (

                { void onListen (

                    StreamSubscription<T> subscription

                              ) ? ,

                      void onCancel (

                   StreamSubscription<T> subscription

         ) ? }

)             
  • elementAt =

This method returns the value at the given index in the given stream. Listening to the stream is terminated as soon as the value at that index is retrieved. 

If, in any case, the stream causes an error before the value is retrieved, the Future returned is completed with the error. 

Implementation = 

Future<T> elementAt (

      int index

)
  • handleError( )

This method creates a wrapper Stream that determines some errors from this given stream. This generated wrapper stream sends the error to the ' test ' to match whether the errors are the same, and then the ' onError ' function determines this error. 

Implementation = 

Stream<T> handleError (

Function onError ,

{ bool test (

dynamic error

) ? }

)
  • listen( )

This method is used to subscribe the elements to the stream and then returns the StreamSubscription that handles the events emitted by the stream using the following handlers :

  • onData
  • onError
  • onDone

Implementation = 

StreamSubscription<T> listen (

          void onData (

                 T event

                    ) ? ,

             { Function? onError ,

                        void onDone (

                ) ? ,

             bool? cancelOnError }

)
  • toString( )

This method converts a given number into an equivalent shortest string and returns the same. 

Implementation = external String toString( ) ;

  • toList( )

This method collects all the elements of the given stream in the ' List '. It creates the List< T > and adds all the elements of the given stream to the list. At the end of the stream, the future returned is completed with the list. 

Implementation = Future< List<T> > toList( )


Related Topics

Dart Generators

Synchronous Generator Dart Generator is a unique function that allows us to generate price sequences. Generators return values when needed; means that the value is generated if we try to duplicate...

5 minutes read.

Callable Classes in Dart

Just like the functions, we can also call the instances of classes in Dart. Such classes are also known as “callable ” classes. We need to use the “call( )”...

3 minutes read.

Dart lists data type

The most important data type in any programming language is an ordered list of elements, an array. Dart lists resemble JavaScript array lists. Example,               var...

7 minutes read.

Dart Types of Functions

Functions are the set of statements intended to perform a specific task. They accept some input from the user, perform the specified computation and generate the output. They are very...

4 minutes read.

Dart super keyword

The ' super ' keyword is used to refer to the immediate parent class object of the currently in-use child class. Using this keyword, we can invoke the superclass (...

6 minutes read.

Dart Constants

Dart Constants are the objects or variables whose values can’t change or modify during the execution of the program. Their use case is when we want a particular value to...

2 minutes read.

Dart Standard Input & Output

Standard Input in Dart (stdin): The standard input stream reads data both synchronously and asynchronously from the keyboard.  In Dart programming language, .readLineSync( ) function is used to accept input from the...

3 minutes read.

Dart Symbols

Symbols data type in Dart A symbol is an object that is the representation of an operator or identifier in Dart. These are compile-time constants.  They are used in APIs that refer...

1 minute read.

Dart Features

Dart is a fully-featured, object-oriented modern language with its roots in the programming language ‘Smalltalk’. It has some of its eminent features similar to the languages such as Java, C#...

4 minutes read.

Dart - extends, with and implements Keywords

The application development in Dart programming language using the Flutter framework, regularly experience different usage of the implements, extends and with keywords. Dart has full support for inheritance that is...

5 minutes read.

Dart URIs

The Uri class supports encoding and decoding of strings with the help of functions to be used in URIs ( which may also be known as URLs ). These functions...

6 minutes read.

Dart Static Members

Static Members in Dart Static members are the members of the class declared using the 'static' keyword. the static members have the following characteristics :  All the objects of the class having...

3 minutes read.

Dart Switch Case Statement

In the case of if-else statements, we prefer not to use the if-else ladder when there are many test conditions to be evaluated. In such a situation, it is preferable...

4 minutes read.

Type System in Dart

Dart language is a type safety enabled language that uses static and dynamic type checking to match the value of the variable with its data type at the compile-time. This...

4 minutes read.

Dart Packages

Every programming language has some in-built functions stored inside the header files that makes the task much easier for the programmer. The Dart Packages refer to the compilation of a...

4 minutes read.

Assert in DART

In any programming language, resolving error is the most unwanted and tedious task. At times it becomes very difficult to find the error in the large code. Dart offers an...

3 minutes read.

Dart Concurrency

Dart concurrency allows us to run multiple or multiple components of a system at once. It issues several commands at once. Dart provides Isolates as a tool for performing compliance...

2 minutes read.

Dart Classes

Dart is an object – oriented programming language that supports all the object-oriented programming concepts such as classes, objects, inheritance, data abstraction and data encapsulation. A class can be defined as...

8 minutes read.

Dart Equality and Relational Operators

Dart provides the functionality of checking the relationship between the values or values within the variables. These operators return the resultant value as Boolean, i.e., either ‘true’ or ‘false’. Some important points...

3 minutes read.

Dart Installation Guide

There are various ways of compiling and running an application created in Dart, either by compiling the Dart code to JavaScript using the Dart2js tool or by running on the...

3 minutes read.