-
Notifications
You must be signed in to change notification settings - Fork 1
BASE.async.Future
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
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
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
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
Instance Method
future.cancel(reason: string) --> Future
var f = future.cancel("User Canceled");
console.log(f === future); // true
Instance Method
This methods starts the retrieval process of the future value. future.try() --> Future
var f = future.try(); console.log(f === future); // true
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.
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.
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();
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 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
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
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
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]); // {}
});