Last active
August 4, 2016 22:04
-
-
Save mikermcneil/755a2ae7cc62d9a59656ab3ba9076cc1 to your computer and use it in GitHub Desktop.
I've answered a lot of questions lately about asynchronous (non-blocking) vs. synchronous (blocking) function declarations (implementation) and asynchronous (non-blocking) vs. synchronous (blocking) invocations (userland). This is a set of crude representative examples that aims to shed some light on the underlying concepts at work.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ╔═╗╔═╗╦ ╦╔╗╔╔═╗ ┌─┌┐┌┌─┐┌┐┌ ┌┐ ┬ ┌─┐┌─┐┬┌─┬┌┐┌┌─┐─┐ | |
// ╠═╣╚═╗╚╦╝║║║║ │ ││││ ││││───├┴┐│ │ ││ ├┴┐│││││ ┬ │ | |
// ╩ ╩╚═╝ ╩ ╝╚╝╚═╝ └─┘└┘└─┘┘└┘ └─┘┴─┘└─┘└─┘┴ ┴┴┘└┘└─┘─┘ | |
// ┬ ┬┌─┐ | |
// ───└┐┌┘└─┐─── | |
// └┘ └─┘o | |
// ╔═╗╦ ╦╔╗╔╔═╗╦ ╦╦═╗╔═╗╔╗╔╔═╗╦ ╦╔═╗ ┌─┌┐ ┬ ┌─┐┌─┐┬┌─┬┌┐┌┌─┐─┐ | |
// ╚═╗╚╦╝║║║║ ╠═╣╠╦╝║ ║║║║║ ║║ ║╚═╗ │ ├┴┐│ │ ││ ├┴┐│││││ ┬ │ | |
// ╚═╝ ╩ ╝╚╝╚═╝╩ ╩╩╚═╚═╝╝╚╝╚═╝╚═╝╚═╝ └─└─┘┴─┘└─┘└─┘┴ ┴┴┘└┘└─┘─┘ | |
// ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ | |
// ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ ┌┼─ | |
// └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ | |
// ╔═╗╔╗╔ ╔╦╗╔═╗╔═╗╦ ╔═╗╦═╗╔═╗╔╦╗╦╔═╗╔╗╔ ┌─┬┌┬┐┌─┐┬ ┌─┐┌┬┐┌─┐┌┐┌┌┬┐┌─┐┌┬┐┬┌─┐┌┐┌─┐ | |
// ╠╣ ║║║ ║║║╣ ║ ║ ╠═╣╠╦╝╠═╣ ║ ║║ ║║║║ │ ││││├─┘│ ├┤ │││├┤ │││ │ ├─┤ │ ││ ││││ │ | |
// ╚ ╝╚╝ ═╩╝╚═╝╚═╝╩═╝╩ ╩╩╚═╩ ╩ ╩ ╩╚═╝╝╚╝ └─┴┴ ┴┴ ┴─┘└─┘┴ ┴└─┘┘└┘ ┴ ┴ ┴ ┴ ┴└─┘┘└┘─┘ | |
// ┬ ┬┌─┐ | |
// ───└┐┌┘└─┐─── | |
// └┘ └─┘o | |
// ╔═╗╔╗╔ ╦╔╗╔╦ ╦╔═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔ ┌─┬ ┬┌─┐┌─┐┬─┐┬ ┌─┐┌┐┌┌┬┐─┐ | |
// ╠╣ ║║║ ║║║║╚╗╔╝║ ║║ ╠═╣ ║ ║║ ║║║║ │ │ │└─┐├┤ ├┬┘│ ├─┤│││ ││ │ | |
// ╚ ╝╚╝ ╩╝╚╝ ╚╝ ╚═╝╚═╝╩ ╩ ╩ ╩╚═╝╝╚╝ └─└─┘└─┘└─┘┴└─┴─┘┴ ┴┘└┘─┴┘─┘ | |
// | |
// I've answered a lot of questions lately about asynchronous (non-blocking) | |
// vs. synchronous (blocking) function declarations (implementation) and | |
// asynchronous (non-blocking) vs. synchronous (blocking) invocations (userland). | |
// | |
// This is a set of crude representative examples that aims to shed some light | |
// on the underlying concepts at work. | |
// ------------------------------------------------------- | |
// api/services/SomeService.js | |
module.exports = { | |
/** | |
* A synchronous function declaration; in this case, this is a helper within a service. | |
* | |
* @required {Dictionary} newUserProps | |
* @return {String} [a short message] | |
* @throws {Error?} [if something goes wrong] | |
*/ | |
signUpSync: function (opts){ | |
var newUserId = createUserSync(opts.newUserProps); | |
sendWelcomeEmailSync({ userId: newUserId }); | |
return 'hello'; | |
} | |
} | |
// (note that no explicit try/catch is necessarily required above since | |
// the default behavior of throwing any error up to the caller just works | |
// automatically.. unless you need to negotiate errors programatically. | |
// To put it another way, the code above is not going to crash your process.) | |
// ------------------------------------------------------- | |
// Userland of synchronous function | |
function (req, res) { | |
var msg = SomeService.signUpSync({ | |
newUserProps: {} | |
}); | |
return res.json({ | |
message: msg | |
}); | |
} | |
// ------------------------------------------------------- | |
// ------------------------------------------------------- | |
// api/services/SomeService.js | |
module.exports = { | |
/** | |
* An asynchronous function declaration; e.g. a helper in a service. | |
* | |
* @required {Dictionary} newUserProps | |
* @async | |
* @callback [done] | |
* @param {Error?} [if something goes wrong] | |
* @param {String} [a short message] | |
*/ | |
signup: function (opts, done){ | |
createUser({}, function (err) { | |
if (err) { return done(err); } | |
sendWelcomeEmail({ userId: newUserId }, function (err) { | |
if (err) { return done(err); } | |
return done(undefined, 'hello'); | |
}); | |
}); | |
} | |
} | |
// ------------------------------------------------------- | |
// Userland of asynchronous function | |
function (req, res) { | |
var msg = SomeService.signUp({ | |
newUserProps: {} | |
}, function (err, result) { | |
if (err) { return res.serverError(err); } | |
return res.json({ | |
message: msg | |
}); | |
}); | |
} | |
// ------------------------------------------------------- | |
// ------------------------------------------------------- | |
// re try/catch: This is the implicit structure of | |
// synchronous code which is hidden from us automatically | |
// via the automatic upwards propagation of "throw". | |
// | |
// The thing is, if you don't do the following, you'd | |
// never know (programatically-speaking) WHY an error | |
// occurred in the top-level catch statement | |
function (req, res) { | |
try { | |
var msg = SomeService.signUpSync({ | |
newUserProps: {} | |
}); | |
try { | |
var whatever = SomeService.somethingElseSync({}); | |
try { | |
return res.json({ | |
message: msg | |
}); | |
}//</try to build up some output, encode it to JSON, then respond> | |
catch (e) { | |
return res.serverError(e); | |
} | |
}//</try to do somethingElseSync> | |
catch (e){ | |
return res.serverError(e); | |
} | |
}//</try to signupSync> | |
catch (e) { | |
return res.serverError(e); | |
} | |
} | |
// ------------------------------------------------------- | |
// versus the following code whose statements are calls to asynchronous helpers: | |
// (notice how the structure is the same as above) | |
function (req, res) { | |
SomeService.signUp({ | |
newUserProps: {} | |
}, function (err, msg) { | |
if (err) { return res.serverError(err); } | |
SomeService.somethingElse({}, function (err) { | |
if (err) { return res.serverError(err); } | |
// To be completely precise, we still use a try/catch | |
// for this one since building the dictionary and calling | |
// res.json is synchronous. Usually, you'd leave this | |
// try/catch out. | |
try { | |
return res.json({ | |
message: msg | |
}); | |
}//</try to build up some output, encode it to JSON, then respond> | |
catch (e) { | |
return res.serverError(e); | |
} | |
});//</try to doSomethingElse (async)> | |
});//</try to signup (async)> | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment