4

Currently, this is how I perform a query using node-mysql

client.query( sql, function( error, result ) {
  console.dir( result );
});

I would like to do this synchronously, something like this

var result = client.querySync( sql );
console.dir( result );

I understand why blocking in node is bad, but I'm (almost) grown up enough to know when it's okay and when it's not. I only intend to make synchronous calls at the initialisation stage, outside of any event loops.

Does anybody know how I can achieve this please?

Edit...

Something along the lines of...

client.querySync = function( sql )
{
    var called = false;
    var result;

    while ( typeof result == 'undefined' ) {
        if ( ! called ) {
            called = true;
            this.query( sql, function( error, _result ) {
                result = { error: error, result: _result };
            });
        };
    }

    return result;
};
thomas-peter
  • 7,738
  • 6
  • 43
  • 58
  • possible duplicate of http://stackoverflow.com/questions/6048504/synchronous-request-in-nodejs – DhruvPathak Jul 27 '11 at 10:05
  • possible duplicate of [Call An Asynchronous Javascript Function Synchronously](http://stackoverflow.com/questions/9121902/call-an-asynchronous-javascript-function-synchronously) – pylover Sep 21 '13 at 23:47

5 Answers5

5

Your proposed solution (in your edit) won't work because you never give up the thread (so the callback can never be called, so the variable can never be set, so your loop never breaks). Node is not multi-threaded - there is only ever one thread executing javascript at any one time. There is no way to yield that thread except by returning from whatever code is running.

So, you can't do what you want to do. You could try to use some of the solutions that re-write your sync code into async behind the scenes, but I've personally found that approach isn't really worth the effort -- that's it better to just bite the bullet and just do everything with callbacks (over time the pain subsides :).

Geoff Chappell
  • 2,432
  • 1
  • 16
  • 12
  • OK, now we are getting somewhere. Or not. :) – thomas-peter Jul 27 '11 at 12:14
  • 1
    The mental model I use is of a job queue being serviced by a thread pool of 1. Any i/o completions create new jobs where the job is the appropriate callback. A job holds the thread until it returns from its entry function. I also find thinking of an app as a state machine helps keep things clear (rather than a series of highly nested callbacks). – Geoff Chappell Jul 27 '11 at 14:21
  • I agree. I always have to find out for myself. From my hacking at this, it feels like node is deferring I/O calls. I've experimented with putting infintae loops in various places and I see the pattern. I'm starting to see it more clearly, however, the likes of fs.readFileSync() are mudding my waters. – thomas-peter Jul 27 '11 at 15:09
2

Don't. Learn to do asynchronous programming.

Use flowcontrol like futuresJS for keeping your code organised

Raynos
  • 166,823
  • 56
  • 351
  • 396
  • Okay, thanks, I'll look at that. Do you know how I would create querySync. I believe I am capable of learning more than one solution and making up my own mind. – thomas-peter Jul 27 '11 at 09:52
  • @tomwrong you need to look at the API and find out if they expose `sync` calls. If they don't then your out of luck – Raynos Jul 27 '11 at 09:58
  • Thanks Raynos, I've added my own solution. If we can please put the rights and wrongs aside for the moment, would you happen to know why it doesn't work? – thomas-peter Jul 27 '11 at 11:36
1

My guess is that you could have add queueing system like an array of commands within the 'client' of commands that is added to and then looped through by every call to the syncronous method of your client and also by end of any 'blocking' action.

so:

client.mySyncMethod = function(command, callback)
{
    commandArray.push({command, callback});
    runCommands();
}

client.runCommands = function()
{
    for (var i in commandArray)
    {
        // run command
    }
}
obie
  • 578
  • 7
  • 23
0

What is the problem you are running into?

Your sample is procedural in nature due to the callbacks. If you don't want anything to run before all of this stuff is done then only execute the main code after all your callbacks finished:

client.query( sql, function( error, result ) {
  console.dir( result , function () {
      //now start your app code
  } );
});

Everything is still async and you are not fighting your environment while nothing will happen unless the procedural startup is done.. Wrap the whole thing in a simple function with the callback as an argument and you should be good to go.

As for doing this all synchronously: Node.js clearly does not allow you to halt the event-loop. That concept is not there and you simply can't. You can write your querySync as a chain of callbacks to make it behave synchronously.. but it won't be pretty.

Tigraine
  • 23,358
  • 11
  • 65
  • 110
-1

There's no way in node.js making asynchronous code behave like synchronous code.

Tobias P.
  • 4,537
  • 2
  • 29
  • 36
  • 2
    You seem so certain. What proof do have? – thomas-peter Jul 27 '11 at 12:28
  • For converting and asynchronous call to a synchronous one you need threading. The caller has to hear/lock on an attribute and the asynchronous callback has to set the data in the asynchronous callback. But threading is not possible in node.js, so there's really no way. – Tobias P. Jul 27 '11 at 14:00