I was mildly surprised to learn that the Promise class has been built-in to JavaScript. I was trying to fully grok the functional library Bacon when I ran into the JavaScript documentation for Promise. A Promise looks like this :

var p = new Promise( /* executor */ function(resolve, reject) { ... } );

A Promise can be in one of three states at all times : Pending, Fulfilled, or Rejected. This is actually not a new idea. Ever play with Java Scanner? Its hasNext() method returns a boolean indicating the presence of another token on the data stream. But one must understand that some streams, such as network packet streams, may postpone answering while waiting for a slow client. Thus, hasNext() returns true if another packet of data has been received, false if the client has disconnected, and simply blocks (does not return) if the network client is being quiet. This corresponds to Fulfilled, Rejected, and Pending. A Promise is much more explicit.

The Promise constructor calls function before anything else. function is expected to spawn asynchronous work but not call resolve or reject immediately. is created only after function has returned. Once the asynchronous work completes, function will call resolve or reject, which notifies the Promise object of the new state.

Here is an example that fetches tweets from twitter using a Promise to handle the asynchronous call.

var http = require('http')

url = 'http://maps.googleapis.com/maps/api/geocode/json?address=New York, NY, U.S.A' 

//url = 'http://maps.googleapis.com/maps/api/geocode/json?address=Mungalatoid'

var p = new Promise((resolve, reject) => {
	console.log("Kicking off an HTTP request")
	// kicks off an asynchronous HTTP request
	http.get(url, (response) => {
		var data = ''
		console.log('HTTP response received')
		response.on('data', (buffer) => {data += buffer})
		response.on('end', () => {
			var twitterObject = JSON.parse(data)
			if (twitterObject.status == 'ZERO_RESULTS') {
				reject(data)
			} else {
				resolve(data) 
			}
		})
		response.on('error', () => {reject('HTTP Error')})
	})
	console.log("HTTP request has been made")
})

console.log("Evaluating Promise")
p.then(
	(resolvedValue) => {console.log("Promise resolved " + resolvedValue)}
).catch(
	(failureReason) => {console.log("Promise rejected " + failureReason)}
)

Try changing between the URLs to see what happens when Google cannot find a match for the place name. Notice that Evaluating Promise is printed before the http.get callback function is called.

Mind you, this whole thing is much simpler just using node’s fetch, which actually returns a promise given a URL.

Leave a Reply