JS isn't even particularly good at evented, non-blocking I/O: chains of asynchronous calls become series of ever-more-indented function(){}s. Languages with coroutines (Lua) or first-class continuations (Scheme) can chain asynchronous calls in a more straightforward style.
There are dozens of very decent ways to handle flow control with JS - any time you see indented function chains it tells you this might be poor quality code. For better or worse you can choose a library or write your own - Async.JS, Promises, etc all deal with this. Some abstractions like Async.Auto handle branching paths (series -> parallel -> series) very elegantly.
function handleRequest(req)
data = db.fetch("user")
return render("template.html", {user=data})
And if db.fetch and render (both made up functions) are written using the coroutine paradigm, your code would automatically be evented and non-blocking, no need to use libraries to handle your callbacks, and your code has the same style it does if it were blocking.
In db.fetch it uses the "yield" keyword that would tell Lua it is about to do an async operation it should wait till it finish before continue running Lua code, meanwhile run something else instead, making it non-blocking and you can run many of these Lua programs at once on a single thread, all of them concurrently.
One nice thing about Lua coroutines is that they are "stackful". You don't need to chain "yields" all the way up the call stack (like Python's "yield from") so its possible to create functions that work with both sync and async callbacks.
function mapList(xs, f)
local ys = {}
for i=1,#xs do
ys[i] = f(xs[i])
end
return ys
end
mapList({10, 20, 30}, function(x)
return db.fetch(x)
end)
In JS you can't use async functions inside of Array.prototype.map. You need to use a separate async-aware method from your favorite async library instead.
I have used this idiom to great results in my project (https://github.com/raksoras/luaw). Basically, request:read() hooks up into libuv (node.js' excellent async IO library) event loop and then yields. Server is now free to run next coroutine. When socket underlying the first request is ready with data to read libuv event loop's callback gets fired and resumes original coroutine.
That's awesome. You've me hooked. For postgres database access, what library do you suggest? Also, I remember lua-nginx can also do non-blocking IO in blocking style code. (http://wiki.nginx.org/HttpLuaModule, http://openresty.org) How does luaw compared to that?
Right now it's just a HTTP server and REST framework. It's a very first release and I don't have any DB drivers for it yet- they would need to be non-blocking as you mentioned.
I have plans to write dbslayer like "access DB over REST" service as a companion to Luaw so that it can use any and all databases that have JDBC drivers available without having to write non-blocking driver specially for each new database. This kind of arrangement where DB connection pooling is abstracted out of application server itself has other advantages related to auto-scaling in cloud and red/black or "flip" code pushes at the cost of slightly more complex deployment.
All depends on how much spare time I actually get :(
With BabelJS, or the co modules (used with generators) you can get a very similar model...
app.use(function *(){
var db = yeild getDbConnection();
var data = db.query("procname", this.request.query.param);
this.body = JSON.stringify(data);
});
This of course assumes you have a db interface that uses Primises and are using koa for your web platform in a version of node that supports Generators, or are using something like BabelJS or traceur.
I prefer Common Lisp, but I can only dream about how wonderful Scheme in the browser would have been. JavaScript is hideous, simply hideous: it's a hack, piled atop a thousand compromises, wrapped up in a million curly brackets.
Every time I use JavaScript I imagine how good life could have been were it Scheme. Every time I have to use JSON I imagine how great life would have been were we using canonical S-expressions[1] instead. There's one good thing—and only one good thing—about JavaScript: it's incredibly well-deployed. As another commenter mentioned, JavaScript is an object lesson in path dependency.
In many ways, it's appropriate that it has 'Java' in the name: it's popular, but it's ugly. There are better languages; indeed, nearly every other non-Turing-tarpit language is better than either Java or JavaScript: Lua, Lisp, TCL, Python, Rebol, Erlang.
Lots of indented function calls is just poor design. You get the same thing in Scala when you start dealing with lots of Futures inappropriately.
Just choose a decent abstraction for callbacks. I prefer promises, but async.js does a good job as well.
The `flatMap` function on a Future in scala might be built into the language, but it is implemented and scala and not significantly different (in my mind), to Bluebird being implemented in javascript.