KEMBAR78
Asynchronous Programming with JavaScript | PDF
<web/F><web/F>
Taming the Async Beast
By Niloy Mondal
@niloy_mondal84
<web/F><web/F>
Background
As a JS developer, async programming is a part of life.
Examples of Async APIs:
setTimeout, setInterval, addEventListener
XMLHttpRequest
CSS Animations
Database transactions in NodeJS
But no good tools to do async programming… till now
<web/F><web/F>
Callback Hell
Lets say we want to create a new user, upload photo and finally fetch all details of the user.
createUser(userDetails, function(response) {
if (response.success) {
var user = response.user;
uploadPhoto(user.id, photo, function(response) {
if (response.success) {
getUser(user.id, function(response) {...});
} else {
alert("Error: cannot upload photo");
}
});
} else {
alert("Error: cannot create user");
}
});
<web/F><web/F>
Problems
<web/F><web/F>
Promise
Rules are meant to broken, Promises are meant to be resolved.
Welcome `Promises` aka `Futures` aka `Continuation Monad` from functional programming.
Many initial implementations but now standardized. Now part of JS.
function setTimeoutP(delay) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, delay);
});
}
setTimeoutP(2000).then(function() {
console.log("After 2 seconds");
});
<web/F><web/F>
Taming the Async Beast (Attempt 1)
var userId;
createUser(userDetails)
.then(function(user) {
userId = user.id;
return uploadPhoto(userId);
}).then(function() {
return getUser(userId);
}).then(function(userDetails) {
// user details fetched
}).catch(function() {
alert("Oops! Error occoured");
});
<web/F><web/F>
Benefits of using Promise
No pyramid of doom anymore, code is indented only to 1 level.
Code is somewhat sequential.
Execution flows from one `then` to another, top to bottom.
Clean error handling using `catch` similar to `try...catch` block.
<web/F><web/F>
Parallel execution using Promises
Usecase: Edit User Information page
var userDetailsPromise = getUser(userId);
var occupationValuesPromise = getOccupationValues();
Promise.all([userDetailsPromise, occupationValuesPromise])
.then(function(args) {
var userDetail = args[0];
var occupationValues = args[1];
// fill the UI elements here
});
<web/F><web/F>
Problems with Promise
Does solve the async problem to some extent but it still feels like a workaround/hack.
We have keep writing these `then` over and over for each async call.
If..else type conditional flow is hard.
For some complicated use cases, even Promises become an unreadable mess.
<web/F><web/F>
Can we do better?
.
<web/F><web/F>
Small introduction to Generators
What will be the output of the following code?
function* squares() {
var i = 1;
while(true) {
yield i * i;
i++;
}
}
var n = squares();
console.log(n.next().value);
console.log(n.next().value);
console.log(n.next().value);
<web/F><web/F>
Taming the Async Beast (Attempt 2)
Lets create a user, upload photo and fetch all details.
spawn(function*() {
try {
var user = yield createUser(userDetails);
yield uploadPhoto(user.id);
var userDetails = yield getUser(user.id);
// user details fetched
} catch(ex) {
alert("Oops! Error occoured");
}
});
<web/F><web/F>
Things to remember
• `spawn` function is a library code (http://taskjs.org/)
• Code is sequential even though we are doing async operations
• `try… catch` just works
• Requires `Promise` to work.The functions `createUser` must return a _Promise_ for this pattern to work.
The general rule of thumb is that `yield` can be used infront of functions that return Promise.
<web/F><web/F>
Parallel execution
spawn(function*() {
var values = yield [getUser(userId), getOccupationValues()];
var userDetailsPromise = values[0];
var occupationValuesPromise = values[1];
});
The way to think about this is, whatever you can pass to `Promise.all` can be passed to `yield`.
<web/F><web/F>
Serial Execution of Async Task (Unknown length)
Say you have a CSV file that you read line by line, extract values from each line and upload information by firing an API. The
execution of each API needs to be serial (one after another) because the data below depends on the data above it.
spawn(function*() {
var lines = fs.readFileSync("foo.csv", "utf-8").split("n");
for (var line of lines) {
yield pushRow(line);
}
});
<web/F><web/F>
Using Generators today
Generators are natively implemented in
• Chrome/Opera
• Firefox
• NodeJS(with harmony flag)
For other browsers, various transpilers can be used like Traceur or Babel. I personally use Tracuer.
<web/F><web/F>
Thank you
<web/F><web/F>
Twitter: niloy_mondal84
Github: https://github.com/niloy
Blog: https://github.com/niloy/blog/issues

Asynchronous Programming with JavaScript

  • 1.
    <web/F><web/F> Taming the AsyncBeast By Niloy Mondal @niloy_mondal84
  • 2.
    <web/F><web/F> Background As a JSdeveloper, async programming is a part of life. Examples of Async APIs: setTimeout, setInterval, addEventListener XMLHttpRequest CSS Animations Database transactions in NodeJS But no good tools to do async programming… till now
  • 3.
    <web/F><web/F> Callback Hell Lets saywe want to create a new user, upload photo and finally fetch all details of the user. createUser(userDetails, function(response) { if (response.success) { var user = response.user; uploadPhoto(user.id, photo, function(response) { if (response.success) { getUser(user.id, function(response) {...}); } else { alert("Error: cannot upload photo"); } }); } else { alert("Error: cannot create user"); } });
  • 4.
  • 5.
    <web/F><web/F> Promise Rules are meantto broken, Promises are meant to be resolved. Welcome `Promises` aka `Futures` aka `Continuation Monad` from functional programming. Many initial implementations but now standardized. Now part of JS. function setTimeoutP(delay) { return new Promise(function(resolve, reject) { setTimeout(resolve, delay); }); } setTimeoutP(2000).then(function() { console.log("After 2 seconds"); });
  • 6.
    <web/F><web/F> Taming the AsyncBeast (Attempt 1) var userId; createUser(userDetails) .then(function(user) { userId = user.id; return uploadPhoto(userId); }).then(function() { return getUser(userId); }).then(function(userDetails) { // user details fetched }).catch(function() { alert("Oops! Error occoured"); });
  • 7.
    <web/F><web/F> Benefits of usingPromise No pyramid of doom anymore, code is indented only to 1 level. Code is somewhat sequential. Execution flows from one `then` to another, top to bottom. Clean error handling using `catch` similar to `try...catch` block.
  • 8.
    <web/F><web/F> Parallel execution usingPromises Usecase: Edit User Information page var userDetailsPromise = getUser(userId); var occupationValuesPromise = getOccupationValues(); Promise.all([userDetailsPromise, occupationValuesPromise]) .then(function(args) { var userDetail = args[0]; var occupationValues = args[1]; // fill the UI elements here });
  • 9.
    <web/F><web/F> Problems with Promise Doessolve the async problem to some extent but it still feels like a workaround/hack. We have keep writing these `then` over and over for each async call. If..else type conditional flow is hard. For some complicated use cases, even Promises become an unreadable mess.
  • 10.
  • 11.
    <web/F><web/F> Small introduction toGenerators What will be the output of the following code? function* squares() { var i = 1; while(true) { yield i * i; i++; } } var n = squares(); console.log(n.next().value); console.log(n.next().value); console.log(n.next().value);
  • 12.
    <web/F><web/F> Taming the AsyncBeast (Attempt 2) Lets create a user, upload photo and fetch all details. spawn(function*() { try { var user = yield createUser(userDetails); yield uploadPhoto(user.id); var userDetails = yield getUser(user.id); // user details fetched } catch(ex) { alert("Oops! Error occoured"); } });
  • 13.
    <web/F><web/F> Things to remember •`spawn` function is a library code (http://taskjs.org/) • Code is sequential even though we are doing async operations • `try… catch` just works • Requires `Promise` to work.The functions `createUser` must return a _Promise_ for this pattern to work. The general rule of thumb is that `yield` can be used infront of functions that return Promise.
  • 14.
    <web/F><web/F> Parallel execution spawn(function*() { varvalues = yield [getUser(userId), getOccupationValues()]; var userDetailsPromise = values[0]; var occupationValuesPromise = values[1]; }); The way to think about this is, whatever you can pass to `Promise.all` can be passed to `yield`.
  • 15.
    <web/F><web/F> Serial Execution ofAsync Task (Unknown length) Say you have a CSV file that you read line by line, extract values from each line and upload information by firing an API. The execution of each API needs to be serial (one after another) because the data below depends on the data above it. spawn(function*() { var lines = fs.readFileSync("foo.csv", "utf-8").split("n"); for (var line of lines) { yield pushRow(line); } });
  • 16.
    <web/F><web/F> Using Generators today Generatorsare natively implemented in • Chrome/Opera • Firefox • NodeJS(with harmony flag) For other browsers, various transpilers can be used like Traceur or Babel. I personally use Tracuer.
  • 17.
  • 18.