1

I am rewriting some JavaScript code that uses callbacks to async functions. Basically doing:

function doStuff(callbackFn){
    var result = foo();
    callbackFn(result);
}

//changing in

async function(){
    var result = foo();
    return result; 
}

//So I can change
doStuff(function(x){
     doStuffWith(x)
});

//into

doStuff().then(x => doStuffWith(x));

Now I encounter a function where I have

function doStuff(callbackFn){
    var result = foo();
    var bar = callbackFn(result);
    baz(bar); 
}

And I have no idea how to start on this one... Any suggestions?

heunetik
  • 567
  • 1
  • 8
  • 21
Stijn Van Antwerpen
  • 1,840
  • 17
  • 42
  • 3
    Not all callbacks are there to do asynchronous tasks. Not all use of callbacks can be refactored into promises. This is one such case. – deceze Jul 23 '19 at 06:33
  • @deceze is correct - this doesn't look like async code. It's just a sequence of actions that are supposed to be synchronous - call `foo()`, then pass the result to `callbackFn` and finally call `baz` with the result of that. Three steps that can only be run in sequence. – VLAZ Jul 23 '19 at 06:36
  • The examples you gave are not exactly asynchronous callbacks. Could you show us your real code, please? What does `baz` do, and what is the `bar` value that the callback returns? – Bergi Jul 23 '19 at 07:40

2 Answers2

3

Callback functions are used (mainly) for two different purposes:

  1. Coordinate asynchronous code.
  2. Pass executable code snippets around as opposed to only values.

Your first case looks like #1, doStuff does something, possibly asynchronously, and to enable other code to continue executing if and when doStuff is done, it takes a callback which it will call at the appropriate time.

The other case looks more like #2, where doStuff takes a piece of executable code to get a value that it depends on for its own execution. The classical example of that is Array.prototype.sort:

[5, 1, 7, 3].sort((a, b) => b - a)

This callback fills in a part of the algorithm of sort. It has nothing to do with asynchronous execution and cannot be converted to async/await/.then, and neither does it need to.

deceze
  • 510,633
  • 85
  • 743
  • 889
-2

First, your callbackFn must ALSO be converted to async. I'm assuming you know how to wrap synchronous functions inside a Promise for conversion to async.

Having that done, you would just do this:

async function doStuff(callbackFn) {
  const result = foo();
  const bar = await callbackFn(result); //callbackFn must be async
  await baz(bar); //baz function must be async

  return someResponse;
}
Keith Harris
  • 1,118
  • 3
  • 13
  • 25
  • Why convert it to async when all you do is `await` it? The only difference between this and OP's code is adding superfluous things to add more superfluous syntax on top of it. If `callbackFn` is synchronous *that's fine* - why would it need to be async? – VLAZ Jul 23 '19 at 06:43
  • The question here was "how to convert a function to async" not whether this function warrants async conversion. The "await" keyword tells the program to hand over processing of the function to a thread so that it won't keep the user waiting for fulfillment. "Await" can only be used on async functions, therefore, you must convert to async. – Keith Harris Jul 23 '19 at 06:52
  • 2
    But that's *useless*. If the conversion is *really* needed (and I'm not convinced it is), then the entirety of the work you need to do is make `doStyff` asynchronous. That's it. Having *every* single function in your code base async for the sake of it being async is terrible design for more reasons I can count. Yet it all comes back to - it's useless. It's misguided at best or a cargo cult otherwise. – VLAZ Jul 23 '19 at 06:54
  • The concept of async/await existed in C# since the beginning. Only recently did Javascript implement, and I'm so glad they did! It makes coding awesome, like REALLY AWESOME! But with that comes necessary changes. That's why version 8 of Node.js includes a utility called util.promisify() that enables developers to easily convert legacy SYNCHRONOUS code into ones that return a promise and be used with async and await. Not all functions need it, only the blocking ones do. – Keith Harris Jul 23 '19 at 07:09