Skip to content
This repository was archived by the owner on Feb 13, 2018. It is now read-only.

BASE.async.Future

Jared Barnes edited this page Sep 9, 2015 · 11 revisions

Futures handle asynchrony beautifully. Promises have become part of the Ecmascript spec, but Futures offer a little more.

Here is how you create a future.

var future = new Future(function(setValue, setError){
    setTimeout(function(){
        setValue("Boo");
    }, 1000);
});

// Wait one second and print the returned value.
future.then(function(value){
    console.log(value);
});

Usually you are handed a future and this is how you can handle the asynchrony.

//...
 
getMarkets().then(function(marketsArray){
    console.log(marketsArray);
}).ifError(function(networkError){
   throw new Error(networkError);
}).ifCanceled(function(){
   // Do something if the ajax call was aborted.
});    

//...

The above example is simple but shows some of the options in handling asynchrony. Below we will show a bit more. Chaining, and Error recovery is important and Futures handle that too.

//...

var marketsFuture = getMarkets();

marketsFuture.catch(function(networkError){
   
   // If you return a successful future here it will
   // recover from the error and hand the future to the 
   // next chain.
   return Future.fromResult([]);

}).chain(function(marketsArray){
   // Now we know that we will always have a result, 
   // regardless if the network went done or not.
}).try(); 

//...
//...

var marketsFuture = getMarkets();

marketsFuture.catch(function(networkError){
   
   // If you return a successful future here it will
   // recover from the error and hand the future to the 
   // next chain.
   
   // Otherwise you can modify the Error, and make a custom message.
   if (network.statusCode === 500){
       return Future.fromResult([]);
   } else {
       return Future.fromError(new Error("Custom Error Message."));
   }  

}).chain(function(marketsArray){

   // This method returns another future.
   return doAnotherQueryAccrossTheNetwork(marketsArray);

}).chain(function(results){
   // Do something substantial with the results.
}).try(); 

//...

If you return a Future on a chain callback then it will send the value of that future to the next interest callback.

If you return a value on a chain callback then it will wrap your value into a Future, and send it to the next interested callback.

Here is an example.

future.chain(function(){
     return 4;
}).chain(function(number){
    console.log(number); // --> 4
}).try();

// Or

future.chain(function(){
    return Future.fromResult(4);
}).chain(function(number){
    console.log(number); // --> 4
}).try();

Also the "chain" method doesn't execute the future. Only "then", and "try" methods actually get the future started.

#Instance Methods

future.then

Instance Method

Allows you to react when the value is ready.

future.then(callback: function) --> Future

var f = future.then(function(value){
    // Do something 
});

console.log(f === future); // true

future.ifError

Instance Method

Allows you to react to an error.

future.ifError(callback: function) --> Future

var f = future.ifError(function(error){
    // Do something 
});

console.log(f === future); // true

future.ifCanceled

Instance Method

Allows you to react when something cancels the Future. This is different than an error. An example of this is a user may have navigated to another interest which would negate the need for the value we wanted. Good example of this is on an HttpRequest, we may want a report, but the report query takes a few seconds. In that time the user may decided to run another report. The future can abort the xhr because we treat errors differently than cancels.

future.ifCanceled(callback: function) --> Future

var f = future.ifCanceled(function(reason){
   // Do something 
});

console.log(f === future); // true

future.cancel

Instance Method

future.cancel(reason: string) --> Future

var f = future.cancel("User Canceled");

console.log(f === future); // true

future.try

Instance Method

This methods starts the retrieval process of the future value. future.try() --> Future

var f = future.try();

console.log(f === future); // true

future.finally

Instance Method

This method is called on completion. Whether or not it failed or was canceled or completed successfully. Use this method if you just need to know if its done.

future.finally(callback: function) --> Future

var f = future.finally();

console.log(f === future); // true

#Chaining, catching Errors and catching Cancellations.

The following functions are more advanced uses of Futures. And in all honesty, these methods should be what we use more often.

future.chain

Instance Method

On a chain we use an intermediate future to allow us to chain futures together.

future.chain(callback: callback) --> Future

var f = future.chain(function(){
   return BASE.async.delayAsync(1000);
}).chain(function(){
    return getReportAsync();
}).chain(function(report){
    // Do something here.
});

console.log(f === future); // false

This helps us avoid "Callback Hell". Which would look like this.

var f = future.then(function(value){
   setTimeout(function(){
       getReportAsync().then(function(report){
           // Do something useful.
       });
   }, 1000);
});

If there is any error handling, it becomes even more exacerbated.

future.catch

Instance Method

future.catch(callback: function) --> Future

Error handling with "catch" is magical. It allows you to react to any error up the chain. You may even want to recover from a certain error, and "catch" is how you do that.

future.chain(function(value){
	var futureAuthentication = authenticateAsync();
	return futureAuthentication;
}).chain(function(authentication){
	var profilePictureFuture = getProfilePictureAsync(authentication.userId);
	return getProfilePictureFuture;
}).chain(function(profileImage){
	displayImage(profileImage);
}).catch(function(error){
	displayDefaultImage();
});

// If you want it to execute you need to call "try" because
// "chain" allows you to compose chains without executing them.
future.try();  

future.catchCanceled

Instance Method

This works just like catch but on cancelations.

future.chain(function(value){
	var futureAuthentication = authenticateAsync();
	return futureAuthentication;
}).chain(function(authentication){
	var profilePictureFuture = getProfilePictureAsync(authentication.userId);
	return getProfilePictureFuture;
}).chain(function(profileImage){
	displayImage(profileImage);
}).catchCanceled(function(error){
	displayDefaultImage();
});

// If you want it to execute you need to call "try" because
// "chain" allows you to compose chains without executing them.
future.try();  

Class Methods

Future.fromResult

Class Method

There are times where you need to have a future, but you already have the value. In these circumstances you would use this method to create a Future and set its value to what you inject into it.

Future.fromResult(value: any) --> Future

var f = Future.fromResult("John");

console.log(f.isComplete === true); // true

Future.fromError

Class Method

As stated above, there are times where you need to make an Future from an Error.

Future.fromError(error: Error) --> Future

var f = Future.fromError(new Error("Custom Error"));

console.log(f.isComplete === true); // true

Future.fromCanceled

Class Method

There are also times where you may need to make a canceled future.

Future.fromCanceled(reason: string) --> Future

var f = Future.fromCanceled("User Canceled");

console.log(f.isComplete === true); // true

Future.all

Class Method

Many times you want to run multiple futures at once and be notified that they are all done. If any of the futures error out or are canceled, the future that is returned from Future.all will follow suit.

The returned value sent to the callback is an array of values.

Future.all(futures: Future[]) --> Future

var f = Future.all([futureInt, futureString, FutureObject]);

f.then(function(values){
    console.log(values[0]); // 1
    console.log(values[1]); // "string"
    console.log(values[2]); // {}
});

Clone this wiki locally