30

How can I make this work

var asyncToSync = syncFunc();

function syncFunc() {
    var sync = true;
    var data = null;
    query(params, function(result){
        data = result;
        sync = false;
    });
    while(sync) {}
    return data;
}

I tried to get sync function from async one, I need it to use FreeTds async query as sync one

user840250
  • 727
  • 1
  • 8
  • 20
  • 5
    Async callbacks always run after the function stack has cleared. Therefore, it is not possible to synchronously return an ansyc result. Any synchronous function that initiated an async action must necessarily have returned before the async action started. **Instead**, you want to make your outer function *also* asynchronous by having it accept a callback that is called inside the callback to `query`. – apsillers May 16 '13 at 13:33
  • 1
    Does the query function perform a database call? If so, the DB client may provide synchronous version of that query function. – helpermethod May 16 '13 at 13:43
  • Duplicate: [How to block on asynchronous functions in JavaScript](http://stackoverflow.com/questions/4345945/how-to-block-on-asynchronous-functions-in-javascript) (but not many good explanatory answers) – apsillers May 16 '13 at 13:45

5 Answers5

27

Use deasync - a module written in C++ which exposes Node.js event loop to JavaScript. The module also exposes a sleep function that blocks subsequent code but doesn't block entire thread, nor incur busy wait. You can put the sleep function in your while loop:

var asyncToSync = syncFunc();

function syncFunc() {
    var sync = true;
    var data = null;
    query(params, function(result){
        data = result;
        sync = false;
    });
    while(sync) {require('deasync').sleep(100);}
    return data;
}
abbr
  • 5,361
  • 6
  • 30
  • 44
  • 3
    This is the only one that you don't have to run inside a Fiber (which you can't always do if you don't control the calling code) – tmandry Sep 21 '15 at 21:17
  • 1
    Indeed! This is the only one worked with my case. Thanks! – yoshi Dec 26 '16 at 07:35
12

Nowadays this generator pattern can be a fantastic solution in many situations:

// nodejs script doing sequential prompts using async readline.question function

var main = (function* () {

  // just import and initialize 'readline' in nodejs
  var r = require('readline')
  var rl = r.createInterface({input: process.stdin, output: process.stdout })

  // magic here, the callback is the iterator.next
  var answerA = yield rl.question('do you want this? ', res=>main.next(res))    

  // and again, in a sync fashion
  var answerB = yield rl.question('are you sure? ', res=>main.next(res))        

  // readline boilerplate
  rl.close()

  console.log(answerA, answerB)

})()    // <-- executed: iterator created from generator
main.next()     // kick off the iterator, 
                // runs until the first 'yield', including rightmost code
                // and waits until another main.next() happens
drodsou
  • 2,970
  • 1
  • 21
  • 15
  • 2
    this still async outside main function, if you put `console.log("EOF")` at last line, you will see `do you want this? EOF` immediately. this is actually a hand-made `async/await` implementation – Nate Scarlet Jan 14 '21 at 07:00
9

You can do it with node-sync lib

var sync = require('sync');

sync(function(){
  var result = query.sync(query, params);
  // result can be used immediately
})

Notice: your query must use standart callback call (with error first): callback(error, result). If you can't change query method, just create .async() wrapper (see github link).

Dmitry Manannikov
  • 1,124
  • 1
  • 10
  • 14
  • 1
    I have async function with callback err and resutls, is "sync(function(){})" able to return value in normal js sync function ? – user840250 May 17 '13 at 06:21
  • No. sync() is just new thread context. It not retun anything. Just wrap all code by it and you could use .sync on async functions. – Dmitry Manannikov May 19 '13 at 00:40
3

I've been using syncrhonize.js with great success. There's even a pending pull request (which works quite well) to support async functions which have multiple parameters. Far better and easier to use than node-sync imho. Added bonus that it has easy-to-understand and thorough documentation, whereas node-sync does not.

shellscape
  • 840
  • 1
  • 6
  • 17
2

The issue you are having is that your tight while loop is blocking. So I don't think your query callback will ever be run. I think you need to use setTimeout or the like to prevent the function from blocking, but should you do so, the function will return before the callback is called. This functionality must be implemented at a lower level.

If you are in the browser, you might check out this article. In node you have to rely on the implementation of whatever you're querying. It may or may not provide synchronous methods.

Maus
  • 1,791
  • 1
  • 17
  • 28