Why are callbacks more "tightly coupled" than promises? - javascript

Can you explain me the following phrase (taken from an answer to Stack Overflow question What are the differences between Deferred, Promise and Future in Javascript?)?
What are the pros of using jQuery promises against using the previous jQuery callbacks?
Rather than directly passing callbacks to functions, something which
can lead to tightly coupled interfaces, using promises allows one to
separate concerns for code that is synchronous or asynchronous.

A promise is an object that represents the result of an asynchronous operation, and because of that you can pass it around, and that gives you more flexibility.
If you use a callback, at the time of the invocation of the asynchronous operation you have to specify how it will be handled, hence the coupling. With promises you can specify how it will be handled later.
Here's an example, imagine you want to load some data via ajax and while doing that you want to display a loading page.
With callbacks:
void loadData = function(){
showLoadingScreen();
$.ajax("http://someurl.com", {
complete: function(data){
hideLoadingScreen();
//do something with the data
}
});
};
The callback that handles the data coming back has to call hideLoadingScreen.
With promises you can rewrite the snippet above so that it becomes more readable and you don't have to put the hideLoadingScreen in the complete callback.
With promises
var getData = function(){
showLoadingScreen();
return $.ajax("http://someurl.com").promise().always(hideLoadingScreen);
};
var loadData = function(){
var gettingData = getData();
gettingData.done(doSomethingWithTheData);
}
var doSomethingWithTheData = function(data){
//do something with data
};
UPDATE: I've written a blog post that provides extra examples and provides a clear description of what is a promise and how its use can be compared to using callbacks.

The coupling is looser with promises because the operation doesn't have to "know" how it continues, it only has to know when it is ready.
When you use callbacks, the asynchronous operation actually has a reference to its continuation, which is not its business.
With promises, you can easily create an expression over an asynchronous operation before you even decide how it's going to resolve.
So promises help separate the concerns of chaining events versus doing the actual work.

I don't think promises are more or less coupled than callbacks, just about the same.
Promises however have other benefits:
If you expose a callback, you have to document whether it will be called once (like in jQuery.ajax) or more than once (like in Array.map). Promises are called always once.
There's no way to call a callback throwing and exception on it, so you have to provide another callback for the error case.
Just one callback can be registered, more than one for promises, and you can register them AFTER the event and you will get called anyway.
In a typed declaration (Typescript), Promise make easier to read the signature.
In the future, you can take advantage of an async / yield syntax.
Because they are standard, you can make reusable components like this one:
disableScreen<T>(promiseGenerator: () => Promise<T>) : Promise<T>
{
//create transparent div
return promiseGenerator.then(val=>
{
//remove transparent div
return val;
}, error=>{
//remove transparent div
throw error;
});
}
disableScreen(()=>$.ajax(....));
More on that: http://www.html5rocks.com/en/tutorials/es6/promises/
EDIT:
Another benefit is writing a sequence of N async calls without N levels of indentation.
Also, while I still don't think it's the main point, now I think they are a little bit more loosely coupled for this reasons:
They are standard (or at least try): code in C# or Java that uses strings are more lousy coupled than similar code in C++, because the different implementations of strings there, making it more reusable. Having an standard promise, the caller and the implementation are less coupled to each other because they don't have to agree on a (pair) of custom callbacks with custom parameters orders, names, etc... The fact that there are many different flavors on promises doesn't help thought.
They promote a more expression-based programming, easier to compose, cache, etc..:
var cache: { [key: string] : Promise<any> };
function getData(key: string): Promise<any> {
return cache[key] || (cache[key] = getFromServer(key));
}
you can argue that expression based programming is more loosely coupled than imperative/callback based programming, or at least they pursue the same goal: composability.

Promises reify the concept of delayed response to something.
They make asynchronous computation a first-class citizen as you can pass it around. They allow you to define structure if you want - monadic structure that is - upon which you can build higher order combinators that greatly simplify the code.
For example you can have a function that takes an array of promises and returns a promise of an array(usually this is called sequence). This is very hard to do or even impossible with callbacks. And such combinators don't just make code easier to write, they make it much easier to read.
Now consider it the other way around to answer your question. Callbacks are an ad-hoc solution where promises allow for clearer structure and re-usability.

They aren't, this is just a rationalization that people who are completely missing the point of promises use to justify writing a lot more code than they would write using callbacks. Given that there is obviously no benefit in doing this, you can at least always tell yourself that the code is less coupled or something.
See what are promises and why should I use them for actual concrete benefits.

Related

What's wrong with awaiting a promise chain?

I’m working on an Angular 6 application and I’ve been told the following is an anti-pattern:
await someFunction().then(result => {
console.log(result);
});
I realize that it is pointless to await a promise chain. If someFunction() returns a promise, you don’t need a promise chain if you’re awaiting it. You can do this:
const result = await someFunction();
console.log(result);
But I’m being told awaiting a promise chain can cause bugs, or that it will break things in my code. If the first code snippet above does the same thing as the second snippet, what does it matter which one is used. What dangers does the first snippet introduce that the second one doesn’t?
I’m being told awaiting a promise chain will break things in my code.
Not necessarily, your two code snippets do indeed work the same (as long as someFunction() really returns a promise).
What does it matter which one is used. What dangers does the first snippet introduce that the second one doesn’t?
It's harder to understand and maintain, it's confusing to mix different styles. Confusion leads to bugs.
Consider that you would need to add another promise call at the location of the console.log() call, or even a conditional return from the function. Can you use await in the callback like elsewhere in the function, do you need to return the result from the then callback, is it even possible to return from the outer function? All these questions don't even come up in the first snippet. And while they can be easily answered for your toy example, it might not be as easy in real code with more complex and nested control flow.
So you should prefer the more concise and clean one. Stick to await for consistency, avoid then in async functions1.
1: Of course, there's always an exception to the rule. I would say that it's cleaner to use promise chaining for error handling in some cases where you would use catch or the second then callback.
Under the hood, async/await is just promises.
That is, when you have some code that looks like:
const result = await myAsyncFunction();
console.log(result):
That's exactly the same as writing:
myAsyncFunction().then(data => {
const result = data;
console.log(result);
});
The reason then - that you shouldn't mix async/await and .then chains - is because it's confusing.
It's better to just pick one style, and stick to it.
And while you're picking one - you might as well pick async/await - it's more understandable.
If your then code returned a promise instead of calling console.log, your first example would await, but your second example would not.
When you use async/await, you will catch your rejects in try/catch blocks. Your code will be less nested and clearer.
Using then often results in more nesting, and harder to read code.
You can await anything, whether or not it returns a promise. Sometimes this future-proofs calling a method that may one day become async or just return a promise without declaring async.
The downsides are complexity, performance, and compatibility, all of which pale in comparison to the gains.
I find that if you rely on a function's return value after calling it, and it is or may eventually become asynchronous, decorate calling your functions with await to your heart's delight, whether or not it is current async or returns a promise.

What is another way with Javascript promises to set promiseChain = promiseChain.all()?

After reading http://www.promisejs.org/patterns, I saw this Javascript ECMA 6.0 pattern.
function all(promises) {
var accumulator = [];
var ready = Promise.resolve(null);
promises.forEach(function (promise, ndx) {
ready = ready.then(function () {
return promise;
}).then(function (value) {
accumulator[ndx] = value;
});
});
return ready.then(function () { return accumulator; });
}
I am curious whether there is another way with Javascript promises to set promiseChain = promiseChain.all() to meet the objective of
resolving a long chain of promises in their original sequential order.
I found this StackOverflow article. http://stackoverflow.com/questions/28066429/promise-all-order-of-resolved-values
which is relevant to my question.
Also, could I use recursion rather than looping to allow evaluation of promises conditional on the resolution or error handling in the previous promise? Thank you.
At http://www.promisejs.org/patterns I saw this Javascript ECMA 6.0 pattern
No, it's not a pattern at all. It was meant to serve as an explanation of how Promise.all works, suggesting it could be implemented like that function all(promises) { … }. Only that this implementation is absolutely horrible, inelegant, and fails too meet the specification requirements in many ways.
The page puts it as "it should give you an idea of how promises can be combined in interesting ways." Yeah, interesting maybe, but it's really just incorrect code that should not be taken up by anyone as a pattern.
I am curious whether there is another way to meet the objective of resolving a long chain of promises in their original sequential order.
That makes no sense. A promise chain (a promise built from many successive then calls) is already implicitly sequenced, you don't have to do anything special for that.
If you are talking about an array of promises (similar to how Promise.all takes one), multiple arbitrary promises are independent from each other and do not form a sequence - nor can they be forced to do anything in sequence. Remember that a promise is the result of a running asynchronous task, it's not a task that can do anything.
Could I use recursion rather than looping to allow evaluation of promises conditional on the resolution or error handling in the previous promise?
Yes, a recursive approach goes very well with promises and is in fact the only solution to unbounded conditional repetition.

Automatic callback ladder creator

Suppose we have these two async functions:
function myfu(f) {
setTimeout(function(){ f(true) }, 200)
}
function myfu2(x, f) {
setTimeout(function(){ f(500 + x) }, 200)
}
I was thinking about this syntax:
if (myfu.()) {
var d = myfu2.(55)
console.log(d) // outputs 555
}
which is amazingly simpler to type and read that this:
myfu(function (DOTCALL1) {
if (DOTCALL1) {
myfu2(55, function (DOTCALL2) {
d = DOTCALL2
console.log(d) // outputs 555
})
}
})
The conversion from .( syntax could be easily implemented by means of search/replace/regex.
I noticed that most of the time the result of my asynchronous functions is not used, and after it was called, the upper functions also exits immediately.
Although sometimes the upper function can do something after it called the first async(callback), usually it does nothing. Sometimes the asynchronous function could return something useful, but most of the time it just returns undefined and real stuff is returned with callback(result).
So I thought that maybe I could modify the code some how to make it easier to type and read. Which is illustrated by the example above.
My question is sipmle: is there already similar solution? I do not want to reinvent the wheel (if it is already invented). Or, if there is no such project, why not, why this approach, which seems so easy to implement and supposed to simplify development significantly is not used?
Please do not respond with the suggestion to "take a look at async.js". I am not asking about asynchronous programming patterns, asynchronous programming in general, not about arrow function notation =>, not about coffeScript. I am asking about a code conversion on the text level from proposed original syntax form to well known async ladder, aka "callback hell" notation.
What you are describing is very similar to streamline.js: https://github.com/Sage/streamlinejs.
I wrote it but I got the idea from narrative.js: See http://www.neilmix.com/narrativejs/doc/
So your intuition is right. This can be done. It is nevertheless a little more complicated than a few search/replace/regex operations, at least if you want to go beyond the obvious and support async calls in all JavaScript constructs. For example, try to rewrite:
while (asyncF1.() && asyncF2.()) asyncF3.();
I described the streamline transformation algorithm in a blog post: https://bjouhier.wordpress.com/2011/05/24/yield-resume-vs-asynchronous-callbacks/
I have this site bookmarked since last year where the author blogs about EcmaScript6 which allegedly allows you to obtain something similar to .NET's async / await pattern (so allowing code to invoke asynchronous methods like a "normal" one). Here is the link
ES6 introduces two small extensions to the language syntax:
function*: the functions that you declare with a little twinkling star are generator functions. They execute in an unusual way and return generators.
yield: this keyword lets you transfer control from a generator to the function that controls it.
And, even though these two language constructs were not orginally designed to have the async/await semantics found in other languages, it is possible to give them these semantics:
The * in function* is your async keyword.
yield is your await keyword.
Knowing this, you can write asynchronous code as if JavaScript had async/await keywords.
I never had the chance to try it out though, so YMMV. It sounds useful.

javascript node.js in a stand-alone script, block/wait on a promise

I have a simple program in node.js, such as:
// CODE1
step1();
step2();
var o = step3();
step4(o);
step5();
step6();
this program is meant to be run in a stand-alone script (not in a web browser),
and it is a sequential program where order of execution is important (eg, step6 needs to be executed after step5).
the problem is that step3() is an async function, and the value 'o' is actually passed to a given callback,
so I would need to modify the program as follows:
// CODE2
step1();
step2();
step3( function (o) {
step4(o);
step5();
step6();
})
it could make sense to call step4 from the callback function, because it depends on the 'o' value computed by step3.
But step5 and step6 functions do not depend on 'o', and I have to include them in that callback function only to preserve the order of execution: step3, then step4, then step5 then step6.
this sounds really bad to me.
this is a sequential program, and so I would like to convert step3 to a sync function.
how to do this?
I am looking for something like this (eg using Q):
// CODE3
step1();
step2();
var deferred = Q.defer();
step3(deferred.resolve);
deferred.blockUntilFulfilled() // this function does not exist; this is what i am looking for
var o = deferred.inspect().value
step4(o);
step5();
step6();
How to do this?
ps: there are advantages and disadvantages of using sync or async, and this is a very interesting discussion. however, it is not the purpose of this question. in this question, i am asking how can i block/wait until a promise (or equivalent) gets fulfilled. Please, please, please, do not start a discussion on whether sync/blocking is good or not.
It's impossible to turn an async operation into a sync operation in vanilla JavaScript. There are things like node-fibers (a C++ add-on) that will allow this, or various compile-to-JS languages that will make the async operations look sync (essentially by rewriting your first code block to the second), but it is not possible to block until an async operation completes.
One way to see this is to note that the JavaScript event loop is always "run to completion," meaning that if you have a series of statements, they will always be guaranteed to execute one after the other, with nothing in between. Thus there is no way for an outside piece of information to come in and tell the code to stop blocking. Say you tried to make it work like so:
stepA();
stepB();
while (global.operationIsStillGoing) {
// do nothing
}
stepC();
This will never work, because due to the run-to-completion nature of JavaScript, it is not possible for anything to update global.operationIsStillGoing during the while loop, since that series of statements has not yet run to completion.
Of course, if someone writes a C++ addon that modifies the language, they can get around this. But that's not really JavaScript any more, at least in the commonly understood sense of ECMAScript + the event loop architecture.

Synchronous vs Asynchronous code with Node.js

We are working with node, mainly for an internal project and to understand the best way to use the technology.
Not coming from a specific asynchronous background the learning curve can be a challenge but we are getting used to the framework and learning the process.
One thing that has polarised us is when the best time to use synchronous code vs asynchronous code is. We are currently using the rule that if anything interacts with IO then it has to be asynchronous via call backs or the event emitter (thats a given), but other items which are not in any way using IO can be constructed as synchronous functions (this will depends as well on the heaviness of the function itself and how blocking it actually is) but is this the best approach to take when working with Node.js?
For instance, we are creating a Hal+JSON builder, which currently exists within our code base. It is synchronous simply because all it is doing is creating some rather smallish object literals and nothing more, there are no external dependencies and certainly no IO interactions.
Is our approach a good one to take or not?
Let's say you have two functions, foo and bar, which are executing synchronously:
function foo() {
var returnValue = bar();
console.log(returnValue);
}
function bar() {
return "bar";
}
In order to make the API "asynchronous" is to change it to use callbacks:
function foo() {
bar(function(returnValue) {
console.log(returnValue);
});
}
function bar(callback) {
callback("bar");
}
But the fact of the matter is, this code is still entirely synchronous. The callback is being executed on the same call stack, and no threading optimizations are being made, no scalability benefits are to be had.
It then becomes a question of code readablity and coding style. I personally find the typical var val = func(); type code more readable and readily understandable. The only drawback is, that if you one day would need to change the functionality of bar so, that it would need to perform some I/O activity or call some other function which is asynchronous, you need to change the API of baras well.
My personal preference: use traditional, synchnous patterns when applicable. Always use asynchronous style when I/O is involved or when in doubt.
Turning a synchronous function into an asynchronous one using process.nextTick() is an option, but one you should only use if your software is blocking for too long. Every time your synchronous function is running node can't do anything else as it's single threaded. This means that if your application is a server, it becomes unresponsive.
Before you split up any synchronous function, I would advise to first do some benchmarking and profiling so you can make an informed decision. Otherwise you run the risk of dong a premature optimisation
See here for a good discussion https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil
Here's how you can make your function asyncronous, in the sense that you will allow node to do other things http://howtonode.org/understanding-process-next-tick
I don't what's "Hal+Json builder", but here's what I think about NodeJS. You should write your code as asynchronous as possible, pushing it to it's limits. The simple reason is that asynchronous code trades performance for responsiveness, which is in most cases more important.
Of course if certain operations are really quick, then there is no need for asynchronous code. For example consider this code:
var arr = []; // assume array is nonempty
for (var i = 0, l = arr.length; i < l; i++) {
arr[ i ].doStuff( );
}
If arr is small and doStuff is a quick operation, then you should not bother in writing this code in asynchronous way. However if it takes some time, then you should consider writing it like that:
var arr = []; // assume array is nonempty
var process_array_element = function( ) {
if (arr.length) {
arr.pop().doStuff( );
process.nextTick( process_array_element );
}
};
process_array_element( );
Now this code is truely asynchronous. It will take even more time for it to complete the job, but in the meantime it won't block entire server. We've traded performance for responsiveness.
Conclusion: It depends on your situation! :)

Categories

Resources