async – Como converter uma função baseada em promise para callback em JavaScript?

Podemos converter funções assíncronas que trabalham com callback para trabalharem com promises, como demonstrado nos exemplos abaixo:

callback:

const timeInMs = 1_000;

function asyncCallback(timeMs, callback) {
  setTimeout(() => callback(null, timeMs), timeMs);
}

console.log('first');

asyncCallback(timeInMs, (err, result) => {
  if (err) return console.log('Error: ', err);

  console.log('last');

  console.log('Time passed: ', result);
});

console.log('second');

Mudando para promise:

const timeInMs = 1_000;

function asyncCallback(timeMs, callback) {
  setTimeout(() => callback(null, timeMs), timeMs);
}

// função simples para converter callback em promise
function promisify(callback) {
  return function promisified(...args) {
    return new Promise((resolve, reject) => {
      const argsArray = (
        ...args,
        function (err, result) {
          if (err) return reject(err);

          resolve(result);
        },
      );

      callback(...argsArray);
    });
  };
}

// promisificando e convertendo a função asyncCallback
const asyncPromise = promisify(asyncCallback);

console.log('first');

asyncPromise(timeInMs).then((result) => {
  console.log('last');

  console.log('Time passed: ', result);
});

console.log('second');

// usando async/await
(async () => {
  const result = await asyncPromise(timeInMs);

  console.log('(async/await) Time passed: ', result);
})();

Repare que foi possível mudar de callback para promise graças a função customizada promisify().

A pergunta é:

  • Como converter uma função baseada em promise para callback, ou seja, fazer o oposto de promisify()? Algo como callbackify().

Tem uma função no Node.js chamada callbackify do core module util que faz já faz o caminho inverso:

import { callbackify } from 'util'

const timeInMs = 1_000

function asyncCallback (timeMs, callback) {
  setTimeout(() => callback(null, timeMs), timeMs)
}

function promisify (callback) {
  return function promisified (...args) {
    return new Promise((resolve, reject) => {
      const argsArray = (
        ...args,
        function (err, result) {
          if (err) return reject(err)

          resolve(result)
        },
      )

      callback(...argsArray)
    })
  }
}

const asyncPromise = promisify(asyncCallback)

const callbackFunction = callbackify(asyncPromise)

callbackFunction(timeInMs, (err, result) => {
  console.log('Time passed: ', result) // Time passed:  1000
})

Mas eu quero saber como seria feito uma função “na mão” (semelhante à promisify()), com passo a passo e com explicação detalhada, porque quero entender a lógica de implementação.

Esta minha dúivida é só uma prova de conceito e gostaria de saber…