ewok
ewok

Reputation: 21443

node async library: converting a promise structure with callbacks

I'v got the following code block:

new Promise((res, rej) => {
  if (checkCondition()) {
    res(getValue())
  } else {
    getValueAsync((result) => {
      res(result)
    })
  }
}).then((value) => {
  doStuff(value)
})

I want to use the async library, which is what the rest of the codebase uses. I'm trying to figure out which function best solves this problem. I've only beena ble to come up with one solution, but it seems a bit clunky:

async.tryEach([
  (cb) => {
    if (checkCondition()) {
      cb (null, getValue())
    } else {
      cb (1)
    }
  },
  (cb) => {
    if (!checkCondition()) {
      getValueAsync((result) => {
        cb(null, result)
      })
    } else {
      cb (1)
    }
  }],
  (err, value) => {
    doStuff(value)
  }
)

Like I said, this feels clunky. It's nice that it runs the checks asynchronously and I'm pretty sure it will always get the right result, but the code block is now much bigger and more confusing.

My only purpose here is to use the same libraries and techniques as the rest of the codebase, which doesn't use promises at all. I haven't been able to find a similar control flow block anywhere, which is why I needed to construct it myself. If I'm stuck with promises, so be it, but I'd like to find a solution using the library.

Upvotes: 1

Views: 76

Answers (1)

Jordan Running
Jordan Running

Reputation: 106027

I think you're probably overthinking this.

The async library is meant for use with Node.js-style asynchronous code. Per the docs:

All these functions assume you follow the Node.js convention of providing a single callback as the last argument of your asynchronous function -- a callback which expects an Error as its first argument -- and calling the callback once.

As such, the async-style version of your promise code looks like this:

function myThing(cb) {
  if (checkCondition()) {
    cb(null, getValue());
  } else {
    getValueAsync(result => cb(null, result));
  }
}

myThing((err, res) => doStuff(res));

You'll note that this looks a lot like your original promise code.

Since myThing accepts a Node.js-style callback function as its last argument, you can now use it with any of the async library's functions, e.g.:

async.series(
  [ myThing, myThing, myThing ],
  (err, res) => doStuff(res)
);

You can see a working example in the below snippet.

const condition = false;
const checkCondition = () => condition;
const getValue = () => 123;
const getValueAsync = cb => setTimeout(() => cb(getValue()), 250);
const doStuff = value => console.log('doStuff', value);

function myThing(cb) {
  if (checkCondition()) {
    cb(null, getValue());
  } else {
    getValueAsync(result => cb(null, result));
  }
}

myThing((err, res) => doStuff(res));

async.series(
  [ myThing, myThing, myThing ],
  (err, res) => doStuff(res)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/async/2.6.0/async.min.js"></script>

Upvotes: 1

Related Questions