How to adapt a function that only accepts callback to the promise interface in Javascript?

Asked

Viewed 118 times

7

I’m using an external library function to acquire the token of a user, it is the following:

export default function GetGraphToken(
  email: string,
  password: string,
  callback: (graphClient: Client, token: string) => void,
): void {
  ...

  context.acquireTokenWithUsernamePassword(
    resource,
    email,
    password,
    clientId,
    (tokenError, token) => {
      if (tokenError) {
        throw new Error(tokenError.message);
      }

      const tokenResponse = token as TokenResponse;

      ...

      callback(graphClient, tokenResponse.accessToken);
    },
  );
}

The function callback of acquireTokenWithUsernamePassword is the one I actually get the token from, but after that I want to expose this token to other functions using it. Currently, the way I’m doing this is by passing another callback to deal with it. How to expect from functions callbacks, this will lead me to use chained function within function and I think it is possible to avoid this using Promise.

If I could change the function acquireTokenWithUsernamePassword I would make her return a Promise instead of receiving a callback. However, as it belongs to an external library, I cannot. Behold, my doubt arises, I am stuck to the use of callback or is there some way to get rid of it using Promise?

1 answer

6


You were right: you can use promises to avoid the callback Hell (and avoid callbacks in general).

Generally, Promise is the ideal way to deal with asymchronism in modern Javascript, since they allow composition and chaining. In addition, they marry extremely well with asynchronous functions.

If you are using a legacy library that still makes use of callbacks, nay make your code work based on callbacks. You’ll only be turning back your codebase to the detriment of a backward library. Instead, create a type of wrapper Function which involves the original function, operating in promise interface.

I’m not sure what the signature of acquireTokenWithUsernamePassword, but I will give an example of how to convert the function fs.readFile of Node.js, which normally operates with callbacks:

const fs = require('fs');

function readFilePromise(fileName) {
  // Note que retornamos uma promessa explicitamente:
  return new Promise((resolve, reject) => {
    fs.readFile(fileName, 'utf8', (err, data) => {
      if (err) {
        // Em caso de erro, rejeitamos a promessa:
        reject(data);
      } else {
        // Em caso de sucesso, resolvemos a promessa com o conteúdo desejável:
        resolve(data);
      }
    });
  });
}

Now you can use readFilePromise, that operates through an interface that makes use of promises. But note that the above example is certainly "lay", since it ignores the argument options of readFile. It was just to give a real idea. Besides, Node.js also already offers a API of file system promise-based.

Another very common example of promissification is to convert the setTimeout so you can use it with the await. Behold:

// Promissificamos o `setTimeout`, chamando-o de `delay`:
function delay(timeout) {
  // Como `setTimeout` não lança erros, não usaremos o parâmetro `reject`:
  return new Promise((resolve) => {
    setTimeout(resolve, timeout);
  });
}

async function main() {
  console.log('A');
  await delay(500);
  console.log('B');
  await delay(250);
  console.log('C');
  await delat(250);
  console.log('End.');
}

main();

Whenever using an old library that operates via callbacks, shall make such manual involvement for each legacy function. But given that the ecosystem has already established itself relatively well with the use of promises, I believe that it will not be such a large number of Wrappers.

Just be careful not to convert all in promise. Some Apis (such as Observable and Stream) utilize callbacks that can be called multiple times and, as promises are solved only once, are not ideal in this type of scenario.

To learn more about how promises work, I suggest this article. To documentation also brings good information.

  • 2

    +1 Wrappers So they are wonderful things, even facilitate the creation of tests. Another option is, if it is an open source lib, try to collaborate with the project (creating a Issue on and, if well accepted, a PR) or threaten the repository owner (do not recommend, be a nice person)

  • 2

    It fell like a glove! Until now I had only found examples, which converted callback to Promise, in codes that the developer could modify and I did not realize that it would also use this technique in third-party libraries.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.