1

I am new to node and writing a small application. I haven't used a language as asynchronous as this on the server before and have myself in a bit of a pickle. I need to take a string, query a table for an id, then insert in a second table using the result, then return a string from the funtion two levels up. I have a custom dao I use for the db stuff. Here is the function where it all happens:

function generateToken(data, userId, client) {
    var random = Math.floor(Math.random() * 100001);
    var sha256 = crypto.createHmac("sha256", random );
    var token = sha256.update(data).digest("base64");
    var query = dao.select(
        'auth.apps', 
        {  
            name: client.name, 
            version: client.version, 
            subversion: client.subversion, 
            patch: client.patch    
        }
    ).done(
        function(result) {
            dao.insert(
                'auth.tokens',  
                { 
                    user_id:userId, 
                    app_id: result.rows[0].id, 
                    token:token         
                } 
             ); 
             return "mmmm yellllo";
         }
    ); 

    var ret_val = await(query);
    console.log("Token return: " + ret_val);

    return ret_val;
}

and here is the relevant part of my dao for select:

dbo.prototype.select = function(table, where, order_by) {

    var where_clause = this.construct_where(where);
    var sql = 'SELECT * FROM ' + table + ' WHERE ' + where_clause;

    if(order_by  !== undefined) {
        sql = sql + ' ORDER BY ' + order_by;
    };  
    var result = this.pool.query(sql);

    return result;
};

and insert:

dbo.prototype.insert= function(table, values) {
    var key_list='', value_list = ''; 

    for( var k in values) 
    {   
        key_list = key_list + ', ' + k;
        value_list = value_list + ", '" + values[k] + "'";
    }   

    // chop off comma space
    key_list = key_list.substring(2);
    value_list = value_list.substring(2);

    var sql = 'INSERT INTO ' + table + '(' + key_list + ') VALUES(' + value_list + ') RETURNING id';

    var result = this.pool.query(sql).catch(function(error) {
        console.log("SQL:" + sql + " error:" + error);
    });

    return result;
};

How do unwind the double promise. I want the generateToken function to return the token variable but only after the insert query has finished.

4
  • Easiest way is to use Promises. See stackoverflow.com/a/41567664/3830485 Commented Feb 2, 2017 at 4:36
  • The thing is generateToken integrates with an external library, so I don't have the flexibility to return a promise, I have to return the token string and I don't want to do that unless it has been saved in the db. Commented Feb 2, 2017 at 4:41
  • @FrankConry So as I understand your generateToken function is already used by someone so you are not able to change the structure, right? Commented Feb 2, 2017 at 5:09
  • yes, it's part of the restify oauth framework Commented Feb 2, 2017 at 5:10

1 Answer 1

1

There is a library named deasync. And the motivation to create it was to solve the situations when

API cannot be changed to return merely a promise or demand a callback parameter

So this is the primary and probably the only use case. Because in general Node.js should stay async.

To do the trick you basically should write a function that accepts a callback and then wrap it with deasync as follows:

var deasync = require('deasync');

//It can still take the params before the callback
var asyncGenerateToken = function (data, userId, client, callback) {
	var token = 'abc';

	//Async operation starts here
	setTimeout(function () {
		//Async operation is finished, now we can return the token
		//Don't forget that the error is 1st arg, data is the 2nd
		callback(null, token);
	}, 1000);
};

var generateToken = deasync(asyncGenerateToken);

//We'll retrieve a token only after a second of waiting
var token = generateToken('my data', 'my user id', 'my client');
console.log(token);

Hope this helps.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.