if you have an idea about basic principles. • Threading is one of them. We are humans and multi-threading is how our brain works. We can drive a car, while answering a phone call and we are also able to digest our food and smell the farts of our fellow passengers. • But we can‘t do any tasks arbitrarely in parallel. There are limits. We can‘t talk about sex, think about quantum physics and try to remember when our next meeting is scheduled. Tasks start blocking each other. Some are non-blocking and others block our ability to do multi-tasking. • Sneezing for example is blocking. Every action stops, while we are sneezing. Thus making sneezing a synchronous action. Except for our heart beat, which is never blocked by other processes • Ok, so it looks like we always want to have non-blocking processes, but it is not that easy!
even worse: it’s single-threaded. To be correct, JS is interpreted synchronous and the interpreters run single-threaded. • Single-threaded means only one command at a times is processed. So you might ask, why the hell does anyone want to code asynchronous in Javascript? • The answer is very simple: Because we want to. • This is because we want to click a button on our page and have it load some other stuff, while the rest of the page is still accessible. We want to show already loaded parts of the gallery and don’t want to wait until everything is downloaded and then start showing off all content.
is synchronous single-threaded, we can start asynchronous tasks with one command at a time. Imagine a king, who sends out his knights and servants to do certain things. • The king has no idea what one knight is doing at the moment. But he has given instructions. And the knight has to come back and give a report to the king. This makes it possible for him to do many things parallel through his servants. • While a servant is on his way doing something, the king cannot contact him. He cannot stop him from accomplishing his orders. And furthermore he doesn’t know if his knights get killed on the mission or desert. Remember: Back in these days mobile phones did not exist!
the age of mobile communication and the knights should have mobile phones with them. The answer is yes, there are some parallel programming paradigms which can do that, for example Open MPI. In this country the king has a leash and can always control his servants. • In computers this is called threads with process IDs. You can send messages to threads and control them, kill them, spawn more and have them waiting for work and so on. But this is the country of Java and C++. In the mighty realm of Javascript we don’t want to control our Knights tightly, because everything should run smooth and fast.
middle ages, let’s have an example: var fs = require('fs'); var content = fs.readFileSync('index.html'); console.log(contents); Well, the content is loaded and then displayed in the console. But while it is being loaded, nothing else will happen. If our hard disk is much slower than our CPU, we could do other things in between. And no surprise, this is near to always the case.
var fs = require('fs'); fs.readFile('index.html', function(err, contents){ console.log(contents); }); var fs = require('fs'); fs.readFile('index.html', function(err, contents){ console.log(contents); }); Remember anonymous functions? Here is one, let‘s name it a callback.
console.log(contents); } fs.readFile('index.html', callback); • We could have done it this way as well. The function acts the same but it is no longer anonymous. • So what are callbacks? Well, this is the order the knights get from the king, what they have to do after finishing or how to report back at a certain stage.
require('fs'); http.createServer(function(request, response) { response.writeHead(200); fs.readFile('index.html', function(err, contents) { response.write(contents); response.end(); }); }).listen(8080); Callback #1 Callback #2 This might look magical at first glance. Keep in mind that functions are objects as well. Here an object is created which handles a request and a response. The first callback is called when createServer is finished and the second after the readFile is finished.
knight, go forth and create server!” http.createServer(…) • He continues: “Afterwards, write head and read the file index.html!” function(request, response) { response.writeHead(200); fs.readFile('index.html',…) • The knight accepts this order, but he thinks “file read is no fun, let my page do that for me!” function(err, contents) { response.write(contents); response.end(); }); • Furthermore he says his page: “After you have done that, put the content into this response letter and I will bring it to the king!”
{ console.log('squad '+num+' reporting in!'); return Callback(null); }; async.each([1, 2, 3, 4], gather_troops, function (err) { console.log("Army ready!"); }); The package async is required The king wants to gather troops! The king gives out orders through async.each
(err) { console.log("Army ready!"); }); • The function async.each will run the function gather_troops with each entry in the given array [1,2,3,4] and afterwards write a report to the console. squad 1 reporting in! squad 2 reporting in! squad 3 reporting in! squad 4 reporting in! Army ready!
num+'. course'); }; async.map([1, 2, 3, 4], make_delicious_course, function (err, results) { console.log(results); console.log("Lordes, disheth ready!"); }); map instead of each! The callback carries a string now! The results are printed here and not in the called function!
that in the last example map is used instead of each? • Because each does not return an array. When the army is gathered, he only wants to hear from them, that they are ready. But when food is cooked, returning the courses is very important. • Map does return an array. Therefore the king can eat the food, because he has the food at hand. • So if just want to execute some things parallel, just use each. But if you need something back, map will be the better option. Speaking in websites, in one case you want to display some <divs> in another case you need reference to some spawned buttons, too.
of time for preparing the courses. var make_delicious_course = function (num, Callback) { setTimeout(function() { console.log("dish #"+num+" is being prepared!"); return Callback(null, num+'. course'); }, 100 * Math.random()); }; • What does that mean? Well we have just added a timeout that waits until some time is over and then proceeds. Thus simulating different amounts of time the cooks will need. setTimeout takes an anonymous callback function as argument!
4], make_delicious_course, function (err, results) { console.log(results); console.log("Lordes, disheth ready!"); }); dish #2 is being prepared! dish #1 is being prepared! dish #3 is being prepared! dish #4 is being prepared! [ '1. course', '2. course', '3. course', '4. course' ] Lordes, disheth ready! This may be surprising. We see that our asynchronous tasks run in an arbitrary order. That is not too surprising, since we understand what asynchrony means. But still the array is in the right order. This is because the async.js library takes care of the order in this case. If we had build a function “map” by ourselves, we would have to remember the running order and sort the array in the end.
code is designed carefully they are never a problem at all. • The whole design how asynchronous programming is done in Javascript prevents critical implications of races very well. This is because you don’t know what your knights are doing. And they don’t know what other knights are doing. Therefore critical data races occur especially when handling global variables. • But we all know global variables are bad style. In parallel programming this is even more the case. • Debugging races can be painful – even for kings.
function (err, results) { console.log(results); console.log("Lordes, disheth ready!"); } • Maybe you have noticed that all take arguments in the order “error” and then “something” to proceed with. In this case these arguments were “err” and “results”. There is a convention in the community of JS to put error handling first and the rest afterwards. Most libraries stick to this behavior and it is advisable to stick to it as well. If you don’t want to handle errors, because you are the king or so, then you can still pass “null”: return Callback(null, num+'. course');
a lot of surprises below. In Javascript it is the same, that is why Josh Wright has coined this name in his tutorial. How does a Christmas tree look like? asyncFunc1(function(err, result) { asyncFunc2(function(err, result) { asyncFunc3(function(err, result) { asyncFunc4(function(err, result) { asyncFunc5(function(err, result) { // It's Christmas! Praise the lord etc. } } } } }
async call leads to the source code being indented and you lose overview really fast. • Others name this effect “callback hell” • Furthermore we haven’t seen error handling yet. This adds in to the topic “our code gets swollen up” • In the final part of this introduction to asynchronous programming in Javascript, we will see at least one way to trim code and make it look more like synchronous code. • So let’s have a look at promises!
which allows us to register, send and save users. All functions are just dummies to show how error handling works. We use it with the following code: var registry = new Registration(); registry.register("[email protected]", function (err) { console.log("done", err); }); • The output tells us that the built-in error occurred and was printed successfully. Now let’s do the same with promises… done [Error: Failed to send]
the common name. • A promise can have different states: • fulfilled • rejected • pending • (settled) • If your function is used as a promise, you can say what happens when the promise has fulfilled or rejected. Or more precise, what happens “then”.
{ var _save = deferred.promisify(function (email, callback) { callback(null); }); var _send = deferred.promisify(function (email, callback) { callback(new Error("Failed to send")); }); this.register = function (email, callback) { //chain two promises together and return a promise return _save(email).then(_send); }; }; The function is promisified Therefore it becomes „thenable“
No Christmas tree effect, no callback hell. • Furthermore you can collect all errors in nested functions, which call each other with then. Then you can throw all errors at once. • Promises standardize the way asynchronous code is managed. Functions you run have a precise state of either pending or settled. When settled you know if they fulfilled or failed (rejected). • Promises are not a must have, but they give the feeling of returning code back.