Converting a callback to a promise

To make synchronous an asynchronous function with await, the callback executed at it ends must be changed to a promise...

To illustrate how this can be done, we will start with a simple example ...

The formula function is executed on a server, so it takes a delay before the result arrives, so we add a callback for operations that depend on this result.

function formula(a, b, callback) {
  var x = a * b
  callback(x)
}

It is not known when the formula function has completed its treatment (in practice, the treatment is a little more complicated). If, for example, we want to display the result, we call the function as that:

formula(10, 5, function(x) {
  console.log(x)
})

This method, however, has some limitations. The first one is that if the processing that uses formula is also asynchronous, it will also must have a callback, and we often come with a sequence of functions interleaved one in the other, hence the name: callbacks hell!

Another problem also occurs when the asynchronous functions are those of a database (see MySQL or SQLite on Node.js). The write operations are asynchronous, the read operations are asynchronous. Of course, reading depends on what was previously stored in the database. But reading does not come in sequence after storage, users write and read in the database independently of each other. Callbacks are not usable.

Callback is a limited and inefficient solution, which is why it should be replaced by a more modern method: the Promise object.

Using it with then

The formula function will be rewritten as follows:

function formula(a, b) {
  return new Promise(function(resolve, reject) {
    var x = a * b
    if(x == 0) reject("Error")
    else resolve(x)
  })
}

Promise's argument is a function with two parameters, the first, resolve, is executed when the processing is successfully completed, the second, reject, when an error occurs. Resolve returns the result of the processing, the keyword return is superfluous here.

The call will now have this form:

formula(10,5).then(function(x) { console.log(x) })  

Using it with async/await

The previous function is used again, only the call changes:

async function test() {
   var x = await formula(10,5)
   console.log(x)
}

test()

The call must be within a function declared async, you can not use await without it. Await waits for the completion of the formula function and then returns the result available to assign it to x.

It is now possible to use an asynchronous function without worrying about the other functions invoked in the processing. One can dream of seeing the library libuv of Node.js rewritten entirely without callback!

Make synchronous a function with callback

In the case where functions of a library uses callbacks, as is the case with libuv, SQLite etc... we do not have the choice of the method, but it is still possible to make these functions synchronous, by interfacing a promise between these functions and the call.

Example of an interface to the initial formula function with callback:

function formula(a, b, callback) {
  var x = a * b
  callback(x)
}

function formulaSync(a, b) {
    return new Promise(function(resolve, reject) {
        formula(a, b, function(x) {
            if(x==0) reject(false)
            else  resolve(x)
        })
    })
}

async function test() {
    var x = await formulaSync(10, 5)
    console.log(x)
}

test()

See also:

© September 8, 2017 Xul.fr