5

Is there a way to deal with callback functions inside an async function() other than mixing in bluebird or return new Promise()?

Examples are fun...

Problem

async function bindClient () {
  client.bind(LDAP_USER, LDAP_PASS, (err) => {
    if (err) return log.fatal('LDAP Master Could Not Bind', err);
  });
}

Solution

function bindClient () {
  return new Promise((resolve, reject) => {
    client.bind(LDAP_USER, LDAP_PASS, (err, bindInstance) => {
      if (err) {
        log.fatal('LDAP Master Could Not Bind', err);
        return reject(err);
      }
      return resolve(bindInstance);
    });
  });
}

Is there a more elegant solution?

kevingilbert100
  • 1,303
  • 4
  • 22
  • 38
  • 2
    nodejs v.8.x.x `util.promisify` (: – num8er Jul 26 '17 at 22:19
  • 1
    Write a generic function that does the `new Promise` call for you. Or just use one of the many existing, be it from node's `util`, from `Bluebird`, or any other library. – Bergi Jul 26 '17 at 23:00
  • **util.promisify** wrapper for objects and functions: https://www.npmjs.com/package/doasync – Do Async Oct 12 '17 at 22:03

2 Answers2

9

NodeJS v.8.x.x natively supports promisifying and async-await, so it's time to enjoy the stuff (:

const 
  promisify = require('util').promisify,
  bindClient = promisify(client.bind);

let clientInstance; // defining variable in global scope
(async () => { // wrapping routine below to tell interpreter that it must pause (wait) for result
  try {
    clientInstance = await bindClient(LDAP_USER, LDAP_PASS);
  }
  catch(error) {
    console.log('LDAP Master Could Not Bind. Error:', error);
  }
})();

or just simply use co package and wait for native support of async-await:

const co = require('co');
co(function*() { // wrapping routine below to tell interpreter that it must pause (wait) for result
  clientInstance = yield bindClient(LDAP_USER, LDAP_PASS);

  if (!clientInstance) {
    console.log('LDAP Master Could Not Bind');
  }
});

P.S. async-await is syntactic sugar for generator-yield language construction.

num8er
  • 18,604
  • 3
  • 43
  • 57
  • async / await is natively supported without flags? – kevingilbert100 Jul 27 '17 at 16:24
  • @kmgilbert100 of course not. there are 2 ways: 1. harmony flag, 2. using babel. Question was that how to write shorter version of converting callback to promise - latest node does it well. – num8er Jul 27 '17 at 16:26
  • you answered the question correctly. But the async / await syntax IS officially supported in 7 / 8 without a flag - http://node.green/#ES2017-features-async-functions – kevingilbert100 Jul 27 '17 at 16:45
  • @kmgilbert100 that's super! (: I'm not switching my code to async await stuff until it show's good performance. For now I'm comfortable with promises. – num8er Jul 27 '17 at 16:46
  • I've used it in a couple production applications to-date and it's performing well! - Haven't noticed any issues... But remember that node will kill process on un-handled rejection now... so if you plan to use async functions in combination with express / etc make sure you wrap it with a try/catch and some special error handling :) – kevingilbert100 Jul 27 '17 at 17:03
  • @kmgilbert100 I'm familiar with try..catch and all that stuff with promises (: thanks for good news. In containerized environment I like to see that it's crashing to be informed and fix it asap – num8er Jul 27 '17 at 17:04
  • Yea crashing isn't always a bad thing if you plan for it to crash (and someone can't DDOS and crash your child processes) Lol – kevingilbert100 Jul 27 '17 at 18:19
  • FYI, in many cases `bindClient = promisify(client.bind);` will not be sufficient, and you'd need to do `bindClient = promisify(client.bind.bind(client));` or `bindClient = promisify((...args) => client.bind(...args));` in order to properly bind the function to the correct context. – Patrick Roberts May 10 '19 at 17:29
  • @PatrickRoberts of course. I'm just responding to question. Feel to extend my answer with Your idea. – num8er May 10 '19 at 18:52
-2

Use modules! pify for instance

const pify = require('pify');
async function bindClient () {
  let err = await pify(client.bind)(LDAP_USER, LDAP_PASS)
  if (err) return log.fatal('LDAP Master Could Not Bind', err);
}

Haven't tested it yet

Yerko Palma
  • 12,041
  • 5
  • 33
  • 57