Stop Worrying and Learn to Love the Async   (@rvagg)

Stop Worrying and Learn to Love the Async

This work is © 2014 Rod Vagg and is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Australia License

@rvagg
Rod Vagg


Erik

NodeSource

http://r.va.gg
http://nodesource.com

A Quick History of Computing

In the beginning

Programming was about computing

Computers were self-contained number-crunchers

Cruncher

Interactive I/O was late to the game

I/O is not computing


Tape Robot

I/O is what computers wait for

I/O is the bottleneck in the majority of programs

But, I/O is usually hidden

System.out.println("Reading file...");
BufferedReader br = new BufferedReader(new FileReader("in.txt"));

try {
  StringBuilder sb = new StringBuilder();
  String line;

  while ((line = br.readLine()) != null)
    sb.append(line + "\n");
  System.out.print(sb.toString());
} finally {
  br.close();
}

System.out.println("Finished reading file!");

The programmer isn't prompted to consider the costs

I/O is expensive

ClassOperationTime cost
Memory L1 cache reference: 1 ns
L2 cache reference: 4 ns
Main memory reference: 100 ns
I/O SSD random-read: 16,000 ns
Round-trip in same datacenter: 500,000 ns
Physical disk seek: 4,000,000 ns
Round-trip from AU to US: 150,000,000 ns

Then ...
User Interfaces

The UI introduced new challenges


Fran

I/O in the form of a human

Unpredictable

Very high latency

Sequential programming has limits

Good UI's don't constrain the user

Networked UI's: a perfect storm


User variability delivered over unreliable, high-latency networks


Browsers...

IE

On the web, nothing is synchronous


Always in reactive mode, responding to external events

  • React to user events
  • React to network events
  • React to browser events

Enter JavaScript

JavaScript:
The King of event-driven programming

Born in the browser

Designed to respond to user-events

Timers!   BREAKING NEWS: Scrolling text with DHTML!

var p = document.getElementById('scroll');
function scroll () {
  var ptxt = p.innerHTML.replace(/ /g, ' ').split('');
  ptxt.push(ptxt.shift());
  p.innerHTML = ptxt.join('').replace(/ /g, ' ');
}
setInterval(scroll, 100)

Warning: content may trigger intense feelings of nostalgia

JavaScript:
The King of event-driven programming


  • First-class functions

  • Closures and scope capturing

  • Single-threaded

Asynchronicity at the extreme:
Node.js


Async works well for performing many complex, parallel tasks in the browser ...

Why not on the server too?

Synchronous I/O with Node.js


Node.js can be classic

Synchronous file system I/O, on the JavaScript thread

console.log('Reading data...');
var data = fs.readFileSync('in.dat');
console.log('Finished reading data!');

Don't do this

Asynchronous I/O with Node.js


File system I/O is performed on a thread-pool when asynchronous

console.log('Reading data...');
fs.readFile('in.dat', function (err, data) {
  // asynchronous
  console.log('Finished reading data!');
})
console.log('Not finished reading data...');

Asynchronous I/O with Node.js


Network I/O performed with non-blocking system calls

epoll or select depending on platform

Asynchronous I/O with Node.js

Network I/O, always asynchronous, generally event-based

var server = http.createServer()

server.on('request', function (request, response) {
  // handle HTTP request
});
server.on('clientError', function () { /* ... */ }});
server.on('error', function () { /* ... */ }});
server.on('close', function () {
  console.log('Server shut down');
})
server.on('listening', function () {
  console.log('Listening on port 8080');
});

server.listen(8080);

The Callback

The callback

JavaScript embraces the continuation passing style

console.log('Ping!');
function pong () { console.log('Pong!'); }
setTimeout(pong, 100);
console.log('Reading file...');
fs.readFile('in.dat', 'utf8', function (err, data) {
  console.log('in.dat contains %d lines', data.split('\n').length);
});
function clickHandler () { alert('Yo!'); }
el.addEventListener('click', clickHandler, false);

The callback

The callback function is the fundamental unit of asynchronous programming in JavaScript

  • DOM events
  • Browser-based networking
  • Basic Node.js I/O operations
  • Node.js EventEmitter
  • Streams

Even Promises and async utilities for generators are built on callbacks

Embrace the Async

Embrace the Async

Node.js-style callbacks are a great way to represent an asynchronous platform

fs.stat('fooballs.txt', function (err, stat) {
  if (err)
    // deal with it
  else
    // get on with it
})
  • I/O is in your face, you have to deal with as a special case
  • Error-handling is first-class
  • The pattern is simple and allows highly compatible modularity

Embrace the Async


Hide asynchronous behaviour at your peril

Use abstractions wisely: for productivity, not to change the fundamental nature of the platform

The world is asynchronous, programming should be asynchronous, learn to think in async

Asynchronous programming



Accept it; it's the new norm