1

scenario 1

function a(callback){
 console.log("not calling callback");
}

a(function(callback_res){
  console.log("callback_res", callback_res);
});

scenario 2

function a(callback){
console.log("calling callback");
   callback(true);
}

a(function(callback_res){
  console.log("callback_res", callback_res);
});

will function a be waiting for callback and will not terminate in scenario 1? However program gets terminated in both scenario.

gourav kumar
  • 141
  • 1
  • 11

2 Answers2

1

The problem is not safety but intention. If a function accepts a callback, it's expected that it will be called at some point. If it ignores the argument it accepts, the signature is misleading.

This is a bad practice because function signature gives false impression about how a function works.

It also may cause parameter is unused warning in linters.

will function a be waiting for callback and will not terminate in scenario 1?

The function doesn't contain asynchronous code and won't wait for anything. The fact that callbacks are commonly used in asynchronous control flow doesn't mean that they are asynchronous per se.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • This is not necessarily the case. Look at `Array.prototype.forEach()`. It won't call it's callback if you call `array.forEach(fn)` on an empty array and that's perfectly fine and expected. So, it really depends upon the contract of the function, what it does and how it communicates that the callback will be called. – jfriend00 Oct 04 '18 at 08:06
  • @jfriend00 That's a good point. However, `forEach` doesn't accept a callback it *never* uses. – Estus Flask Oct 04 '18 at 08:07
1

will function a be waiting for callback and will not terminate in scenario 1?

No. There is nothing in the code you show that waits for a callback to be called.

Passing a callback to a function is just like passing an integer to a function. The function is free to use it or not and it doesn't mean anything more than that to the interpreter. the JS interpreter has no special logic to "wait for a passed callback to get called". That has no effect one way or the other on when the program terminates. It's just a function argument that the called function can decide whether to use or ignore.


As another example, it used to be common to pass two callbacks to a function, one was called upon success and one was called upon error:

function someFunc(successFn, errorFn) {
    // do some operation and then call either successFn or errorFn
}

In this case, it was pretty clear that one of these was going to get called and the other was not. There's no need (from the JS interpreter's point of view) to call a passed callback. That's purely the prerogative of the logic of your code.


Now, it would not be a good practice to design a function that shows a callback in the calling signature and then never, ever call that callback. That's just plain wasteful and a misleading design. There are many cases of callbacks that are sometimes called and sometimes not depending upon circumstances. Array.prototype.forEach is one such example. If you call array.forEach(fn) on an empty array, the callback is never called. But, of course, if you call it on a non-empty array, it is called.


If your function carries out asynchronous operations and the point of the callback is to communicate when the asynchronous operation is done and whether it concluded with an error or a value, then it would generally be bad form to have code paths that would never call the callback because it would be natural for a caller to assume the callback is doing to get called eventually. I can imagine there might be some exceptions to this, but they better be documented really well with the doc/comments for the function.

For asynchronous operations, your question reminds me somewhat of this: Do never resolved promises cause memory leak? which might be useful to read.

jfriend00
  • 683,504
  • 96
  • 985
  • 979