Next time you're about to define a function with a callback argument, don't.
No, do. It's the prevailing style in Node.js and elsewhere, and so there exist tools to transform them (syntactically or otherwise) into more palpable styles:https://github.com/0ctave/node-sync https://github.com/BYVoid/continuation https://github.com/JeffreyZhao/wind https://github.com/Sage/streamlinejs
Also, callbacks ARE sometimes nicer than promises, etc... especially if you have CoffeeScript function syntax.
The fact that the pyramid makes it easy to see the sequence, i.e. follow the chain of causation, and easy to find the callbacks, argues that there is a place for it. Additionally, it makes it easy to transfer state through the chain, since each callback has access to the previous one's variables.
The other patterns, which probably all have appropriate uses, too, would seem to carry a greater risk of spaghetti -- i.e. control that jumps around unexpectedly and is hard to follow.
Put another way, the obviously missing pattern to me is to just move the concurrency up to the level of having multiple threads, and then use synchronous interfaces for synchronous operations. Now that Web Workers are starting to become more widely supported, I don't understand why we aren't heading for synchronous APIs as fast as humanly possible.
My JS programming often looks something like: https://gist.github.com/anonymous/5314313
I don't really care if the APIs I use have callbacks or promises, both fit in just fine.
Is there some community-standard way of naming/declaring a JS function to let the programmer know just by reading the function's name that it will return a promise instead of a final computed value? I'm interested in knowing how people handle this. It's easy to forget that a function doesn't return a promise if the function name makes no mention of it, so I just make it explicit in the function name... but that's just how I handle it.
myAsyncFunc = function (param1, param2, callback) {
var usingPromises = (callback === undefined);
var returnVal = usingPromises ? Q.defer() : this;
someFunction(function (err, res) {
if (usingPromises) {
err ? returnVal.reject(err) : returnVal.resolve(res);
} else {
callback(err, res);
}
});
return returnVal;
};
So if I call myAsyncFunc(foo, bar) it returns a promise and if I call myAsyncFunc(foo, bar, cb) it returns itself for chaining.Otherwise, there's no "naming scheme" for promise-based functions.
Yet, notice how no one shows off how easy it is to write a loop. Oh, and what happens when your code throws an exception? It's as though that path halted forever.
Also, what happens when you have a method defined as
result = foo(args);
that now needs to perform an async operation? Enjoy refactoring every call site.