1

I'm learning node. I have a web application that is interfacing with bitcoind through the bitcoin package, and PostgreSQL through knex. I need to get a bit of data from each module and then pass it all to my view for rendering. My code looks like this so far:

exports.index = function(req, res){
  var testnet='';
  bitcoin.getInfo(function(e, info){
    if(e){ return console.log(e);}
    if(info.testnet){
      testnet='bitcoin RPC is testnet';
    }else{
      testnet='nope.. you must be crazy';
    }
    var c=knex('config').select().then(function(k){
      res.render('index', { title: k[0].site_name, testnet: testnet });
    });
  });
};

The way this is structured though, it will first wait for Bitcoin to reply, and then it will issue the request to PostgreSQL, and then wait a while longer for it to reply. These two wait periods could clearly happen simultaneously. However, I don't know how to do that with promises/callbacks in Javascript. How can I manage this to happen asynchronously, rather than serially?

3
  • does your request to Postgre rely on the response from Bitcoin? Commented Dec 10, 2013 at 3:40
  • @r3mus not always. Sometimes it can be in parallel Commented Dec 10, 2013 at 3:47
  • 1
    If not, then Joe's answer is definitely the way to go. If ever it does reply on the response, then you won't be able to run those async. Commented Dec 10, 2013 at 3:48

3 Answers 3

3

You are looking for the async module which will let you fire off both tasks then continue on.

An untested example to give you the idea:

exports.index = function(req, res){
    var testnet='', k={};

    async.parallel([
      function(){ 
        bitcoin.getInfo(function(e, info){
          //your getInfo callback logic
           },
      function(){
        knex('config').select().then(function(result) {       
         //your knex callback
         k = result;
      } ],
      //Here's the final callback when both are complete
      function() {
         res.render('index', { title: k[0].site_name, testnet: testnet });
      });
}
Sign up to request clarification or add additional context in comments.

2 Comments

The actual code that would make this work is significantly more complicated, especially with error handling :/
btw, for future reference, this is the relevant commit I made to my code. Notable is that each parallel task must take and call a callback function to indicate it's done. github.com/Earlz/d4btc/commit/…
2

You can either use a library like caolan/async's #parallel() method or you could poke around its source and learn to role your own

Comments

1

You need to promisify callback methods, not mix callbacks and promises.

var Promise = require("bluebird");
var bitcoin = require("bitcoin");
//Now the bitcoin client has promise methods with *Async postfix
Promise.promisifyAll(bitcoin.Client.prototype);

var client = new bitcoin.Client({...});

Then the actual code:

exports.index = function(req, res) {
    var info = client.getInfoAsync();
    var config = knex('config').select();

    Promise.all([info, config]).spread(function(info, config) {
        res.render('index', {
            title: config[0].site_name,
            testnet: info.testnet ? 'bitcoin RPC is testnet' : 'nope.. you must be crazy'
        });
    }).catch(function(e){
        //This will catch **both** info and config errors, which your code didn't
        //do
        console.log(e);
    });
};

Promise module bluebird is used.

2 Comments

That is very interesting. I didn't know about Promisify, or how elegant the code could be when it was all promises
@Earlz yep, having the results as values in normal variables is really awesome

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.