0

In Javascript, (a node environment if that helps), I have a few functions that require to query different databases and use the combined data. Since they are all asynch, it makes for some really messy nested code (for example)

database1.find(options, function(docs){
    docs1 = docs;
    database2.find(options, function(docs){
        docs2 = docs;
        database3.find(options, function(docs){
            docs3 = docs;
            //do things with docs1, docs2, docs3
        });
    });
});

Is there a way to write a wrapper (or maybe a library already exists) that would let me write something to call the function, and block until it returns with the requested value?

docs1 = waitUntilDone(database1.find(options, function(docs)));
docs2 = waitUntilDone(database1.find(options, function(docs)));
docs3 = waitUntilDone(database1.find(options, function(docs)));
//do things with docs1, docs2, docs3
avern
  • 4,741
  • 3
  • 11
  • 16
  • 3
    Not in pure JavaScript, but you don’t need to. Use promises and async/await instead. – Ry- Aug 24 '17 at 19:46
  • yes, convert the database calls to promise, and then use Async await.. A little note the callbacks in node are usually `function(error, docs)` what database are you using? – Keith Aug 24 '17 at 19:48

3 Answers3

2

Wrap your functions with Promises and use async/await syntax (async function).

Example (using your code):

const find = (database, options) => new Promise((resolve, reject) => {
  database.find(options, (docs) => {
    //error checking
    if(docs.error) return reject(docs.error);

    resolve(docs);
  });
});

(async () => {
  const options = {};

  const docs1 = await find(database1, options);
  const docs2 = await find(database2, options);
  const docs3 = await find(database3, options);
});
Artur
  • 628
  • 6
  • 14
  • 3
    This would be a good answer if it included an example and some links to documentation. As it is now, it's a good comment. – Scott Marcus Aug 24 '17 at 19:49
  • 1
    From what the OP has given this looks correct, my major concern with this, and the Op's original question. Were is the error checking?. Maybe docs returns an error property. If so, maybe `database.find(options, (docs) => { if (docs.error) reject(docs.error) else resolve(docs); })` – Keith Aug 24 '17 at 19:59
  • You should not mix callbacks with promises. Check [Never Mix Promises and Callbacks in NodeJS](https://spin.atomicobject.com/2017/04/06/nodejs-promises-callbacks/) and [Dont understand javascript promise antipattern, returning promise from callback](https://stackoverflow.com/questions/24708366/dont-understand-javascript-promise-antipattern-returning-promise-from-callback) for more info. – M3talM0nk3y Aug 24 '17 at 20:01
  • @Keith Edited my comment, the initial version of code looked different. Thanks for pointing that out. – M3talM0nk3y Aug 24 '17 at 20:05
-1

For control flow, I typically use the async library. Take a look at the async.waterfall() function; it allows you to execute n functions in series, each passing their result to the next function.

Here's an example:

async.waterfall([
    function(callback) {
        callback(null, 'one', 'two');
    },
    function(arg1, arg2, callback) {
        // arg1 now equals 'one' and arg2 now equals 'two'
        callback(null, 'three');
    },
    function(arg1, callback) {
        // arg1 now equals 'three'
        callback(null, 'done');
    }
], function (err, result) {
    // result now equals 'done'
});
M3talM0nk3y
  • 1,382
  • 14
  • 22
-2

First, you should avoid using sync methods in JS. Asynchronous nature of JS IS one of the best features of the language.

There are at least 3 ways to avoid boomerang code as you have: promises, yield (generators) and async/await.

First approach can be used in any browser without transpiling. Have a look at BlueBird library. It will make your life easier. The most advanced option is about using async/await language construction. Alas, you need to use transpiler for that, for example Babel JS.

Good luck!

Alex
  • 4,621
  • 1
  • 20
  • 30
  • 1
    `you need to use transpiler for that, for example Babel JS.` Not for the latest version of node, async / await is now built in. – Keith Aug 24 '17 at 20:01