Async JavaScript

Tri Nguyen

single-threaded

synchronous execution

See the Pen synchronous execution by Tri Nguyen (@tnguyen14) on CodePen.

asynchronous execution

See the Pen asynchronous execution by Tri Nguyen (@tnguyen14) on CodePen.

call stack

event loop

concurrency

Callback

				
function bar(callback) {
	console.log('bar');
	callback();
}

function baz(callback1, callback2) {
	console.log('baz');
	callback1(callback2);
}

baz(bar, function foo() {
	console.log('foo');
});
				
				
// baz
// bar
// foo
				
			

event listener

				
function writeChapters(err, chapters) {
	chapters.forEach(function(c) {
		console.log(c);
	});
}

function readSync() {
	var chapter1 = getSync('http://example.com/chapters/1');
	var chapter2 = getSync('http://example.com/chapters/2');
	var chapter3 = getSync('http://example.com/chapters/3');
	return [chapter1, chapter2, chapter3];
}

writeChapters(readSync());
				
			
				
function readAsync(callback) {
	var chapter1, chapter2, chapter3;
	getAsync('http://example.com/chapters/1', function (err, c1) {
		if (err) { callback(err); }
		chapter1 = c1;
		getAsync('http://example.com/chapters/2', function (err, c2) {
			if (err) { callback(err); }
			chapter2 = c2;
			getAsync('http://example.com/chapters/3', function (err, c3) {
				if (err) { callback(err); }
				chapter3 = c3;
				callback(null, [chapter1, chapter2, chapter3]);
			})
		});
	});
}

readAsync(writeChapters);
				
			

github.com/caolan/async

async parallel

				
async.parallel([
	function (callback) {
		getAsync('http://example.com/chapters/1', function (err, c1) {
			if (err) { return callback(err); }
			callback(null, c1);
		});
	},
	function (callback) {
		getAsync('http://example.com/chapters/2', function (err, c2) {
			if (err) { return callback(err); }
			callback(null, c2);
		});
	},
	function (callback) {
		getAsync('http://example.com/chapters/3', function (err, c3) {
			if (err) { return callback(err); }
			callback(null, c3);
		});
	}
], writeChapters);
				
			

async parallel with map

				
var chapters = [
	'http://example.com/chapters/1',
	'http://example.com/chapters/2',
	'http://example.com/chapters/3'
];

var getChapters = chapters.map(function (url) {
	return function (callback) {
		getAsync(url, function (err, chapter) {
			if (err) { return callback(err); }
			callback(null, chapter);
		});
	};
});

async.parallel(getChapters, writeChapters);
				
			

Promises

What it looks like

				
promisifiedFn().then(onFulfilled, onRejected);
				
			
				
getChapter('http://example.com/chapters/1').then(function (chapter) {
	// do something with it
	console.log(chapter);
}, function (err) {
	// handle error
});
				
			

Promise-ifying node-style callbacks

				
function getChapter(url) {
	var promise = new Promise(function (resolve, reject) {
		xhrRequest(url, function (err, res) {
			if (err) { reject(err);}
			resolve(res);
		});
	});
	return promise;
}
				
			
A promise can be:
  • resolved/fulfilled The action relating to the promise succeeded.
  • rejected The action relating to the promise failed.
  • pending Hasn't fulfilled or rejected yet.

chainable

				
var chapter1, chapter2, chapter3;
getChapter('http://example.com/chapters/1').then(function (res) {
	chapter1 = res;
	return getChapter('http://example.com/chapters/2');
}).then(function (res) {
	chapter2 = res;
	return getChapter('http://example.com/chapters/3');
}).then(function (res) {
	chapter3 = res;
}).then(null, function (err) {
	console.log('Error downloading chapters');
});
				
			

sequencing with reduce

				
var chapters = [
'http://example.com/chapters/1',
'http://example.com/chapters/2',
'http://example.com/chapters/3'
];

chapters.reduce(function (sequence, url) {
	return sequence.then(function () {
		return getChapter(url);
	});
}, Promise.resolve());
				
			

do more things

				
var chapters = [
'http://example.com/chapters/1',
'http://example.com/chapters/2',
'http://example.com/chapters/3'
];

chapters.reduce(function (sequence, url) {
	return sequence.then(function () {
		return getChapter(url);
	}).then(function (chapter) {
		addToPage(chapter);
	});
}, Promise.resolve());
				
			

parallel

				
var chapters = [
'http://example.com/chapters/1',
'http://example.com/chapters/2',
'http://example.com/chapters/3'
];

Promise.all(chapters.map(getChapter)).then(function (chapters) {
	chapters.forEach(function (c) {
		addToPage(c);
	});
}).then(function () {
	console.log('All done!');
}, function (err) {
	console.log('Ooops!');
});
				
			

best of both worlds: parallelism & sequencing

				
chapters.map(getChapter).redunce(function(sequence, chapterPromise) {
	return sequence.then(function () {
		 return chapterPromise;
	}).then(function (c) {
		addToPage(c);
	});
}, Promise.resolve());
				
			

Slides

http://decks.tridnguyen.com/js-async

Thank you!

/