Async patterns
For JavaScript and Ruby
Michiel Kalkman
(use Chrome or Safari and the arrow keys)
Closures
In computer science, a closure is a first-class function with free variables that are bound in the lexical environment. Such a function is said to be "closed over" its free variables.
The Standard Repository of All Knowlegde and Wisdom (AKA Wikipedia)
Lexical environment is SCOPE
(Stuff you can shoot at!)
Closures example
Scoping rules for closures in JavaScript and Ruby are almost identical
(Aside from the JS mess with 'this')
The Good Old Days
function setupView() {
var obj = getDBObject();
var form = getForm();
renderView(obj, form);
}
Ye Olde Invocation Chain
Optimistic nesting
function setupView() {
getDBObject(function(obj) {
handle(obj);
getForm(function(form) {
handle(form);
renderForm();
console.info("All done");
});
});
}
.. the end result
asyncCall(function() {
asyncCall(function() {
asyncCall(function() {
asyncCall(function() {
asyncCall(function() {
asyncCall(function() {
asyncCall(function() {
console.info("Mommy, what's my scope?");
});
});
});
});
});
});
});
[..] if your indentation goes too far to the right, then it means your function is designed badly and you should split it to make it more modular or re-think it.
Linus Torvalds, Linux Kernel Style Guide
Being 'smart'
function setupView() {
getDBObject(handleDBObject);
}
function getDBObject(callback) {
asyncCall(callback);
}
function handleDBObject(dbobj) {
handle(dbobj);
asyncCall(handleForm);
}
function handleForm(form) {
handle(form);
renderTheForm();
console.info("All done");
}
The Newfangled Async Hell Pattern
What is a sequencer pattern?
- Execute serially, tasks that are interdependant.
- Keep control flow out of the tasks
Sequencer pattern
function getDBObject(callback) {
asyncCall(function(dbobj) {
handle(dbobj);
callback();
});
}
function getForm(callback) {
asyncCall(function(form) {
handle(form);
callback();
});
}
function renderForm(callback) {
renderTheForm();
callback();
}
sequence(
getDBObject,
getForm,
renderForm
);
The Sequencer Pattern
What is a sequencer?
| JavaScript | Ruby |
|---|---|
|
|
What is a sequencer?
| JavaScript | Example use |
|---|---|
|
|
What is a sequencer?
| Ruby | Example use |
|---|---|
|
|
What is a sequencer?
| Ruby | Example use |
|---|---|
|
|
Sequencer pattern
sequence(
getDBObject, // 350ms
getForm, // 200ms
renderForm
);
//
// Total request time : 550ms
//
Collector pattern
- Execute in parallel tasks that are not interdependant.
- Keep control flow out of the tasks
Collector pattern
| Sequencer | Collector |
|---|---|
|
|
And now ...
.. Errors!
Ye Olde Invocation Chain
Error handling?
That doesn't work with async
Errors have to
- preferably not occur at all or
- be handled locally and always continue or
- be handled locally and invoke an error callback
Summary
- Understand scoping
- Establish a code convention for async code
- Write error-free code :)
Q?
- Code at github.com/michiel
- Random junk at twitter.com/michielkalkman