Promises

Promises are a good way to handle asynchronous functionality in javascript.
That asynchronous behavior makes a single thread of javascript run at a
furious pace with apparent parallelisms without all of the fuss of threaded
code.

In years gone past, asynchronous was handled by callbacks. You’d call an
asynchronous function, such as an ajax or other IO request, with a
callback. The callback would be called when the IO request completed.
That produced good results allowing the javascript thread to continue on
while the IO request was being processed.

Problems with that occur when async functions needs to called and completed
in an serially ordered fashion. The result would be code like this:
var data = ajax1( 'http://...', function(data, err) {
if( !err ) {
return ajax2( 'http://...', function( data, err ) {
if( !err ) {
return ajax3('http://...', function(data, err) {
// etc.
});
}
});
}
});

The nesting of functions within functions can get very deep and confusing.
The use of promises can clean up that code. In this way of programming,
each function called returns a particular instance of a Promise object.
The Promise object is instantiated with two arguments, resolve and reject.
eg:
new Promise( resolve, reject);

This promise object is returned synchronously and it will have one of several states: resolved, rejected or pending. Once a promise is either resolved or rejected is is deemed to be settled. A settled object can not change state back to pending or switch between resolved and rejected.

Another key characteristic of a Promise is that is has a standards compliant then() method. The then method looks like this:
promise.then(
onFullfilled?: Function,
onRejected?: Function
) => Promise

Both onFullfilled and onRejected are optional and will be ignored if they
are not functions. onFulfilled() will be called after the promise is
fulfilled, with the promise’s value as the first argument. onRejected will
be called if the promise is rejected and the first argument will be the
reason for the rejection. the attached then() can be called numerous times
on the same promise and each time then() must return a new promise. These
allow promise agregation and chaining, eg:
bringMe( URL )
.then(striptags)
.then(saveInFile)
.catch(handleErrors);

These chains can get complex.

I have also found the use of Promises.all() to be useful. It takes an array
or other iterable of promise returning functions and it returns a promise
that resolves when ALL of the iterable functions have resolve or upon the
first rejection.
var http = require('http');

function myGet(h, p) {
return new Promise(function(resolve, reject) {
// do a thing, possibly async, then…
http.get({ host: h, path: p }, function(response) {
var body = '';
response.on('data', function(d) {
body += d;
});
response.on('end', function() {
// console.log( "h: " + h + ", p: "+ p +"\n\n"+ body );
resolve(body)
});
});
});
}

var Uspecs = [
{h: "lrw.net", p: "/" },
{h: "lrw.net", p: "/learn-mern-part-1/" },
{h: "blog.triblive.com", p: "/" }
];
// proms is a promise that resolves or rejects after all have done so.
// the error message in catch() is only the first rejection. There could be others
var proms = Promise.all( Uspecs.map( function( el ) {return myGet( el.h, el.p);} ) )
.then(values => {console.log( "values : [" + values + "]/values " );} )
.catch(reason => {console.log("error occured" + reason )} );

console.log( "DONE" ); // prints out before any URLs are finished

There is a lot written about promises and other async handling patterns. It
can be useful to google javascript promises and look at some of that.

This entry was posted in Articles, DDJ, Technology. Bookmark the permalink.