0

I know it's quite a typical question and I should look into callback functions, but as much as I've tried, I couldn't solve this one. Maybe you can help?

The problem is very simple. At a certain point of my code I've got the following function that queries Neo4J database (through node.js node-neo4j library) and gets the results into statements.data variable.

   dbneo.cypherQuery(rangeQuery, function(err, statements){

            if(err) {
                err.type = 'neo4j';
                return fn(err);
             }

            console.log(statements);

            fn(null,statements.data);

     });

     var results = statements.data; // THIS DOESN'T WORK! HOW TO CHANGE IT?

What I need is that another variable results gets the statements.data from that DB request and the script continues.

How would I need to rewrite this code in order to do that?

I'm not very familiar with JavaScript, so I tried different syntax but it didn't work. For example, when I wrap the dbneo.cypherQuery function into another function and call its results, I still can't pass the value I need to the parameter.

Thank you and sorry if this question is irritating in my inability to solve such a simple problem.

Aerodynamika
  • 7,883
  • 16
  • 78
  • 137
  • possible duplicate of [How to return value from an asynchronous callback function?](http://stackoverflow.com/questions/6847697/how-to-return-value-from-an-asynchronous-callback-function) – jillro Feb 20 '14 at 19:43

3 Answers3

0

I think that the problem is that you shouldn't return values when using asynchronous javascript.

Callbacks are the most common implementation for asynchronous behaviour, whereas returning values is a common synchronous operation.

You can solve your problem by passing as a parameter the function that needs statements.data and invoke it inside your function like this:

var functionThatRequireData = function (data) { .... }

dbneo.cypherQuery(rangeQuery, function(err, statements, functionThatRequireData){

            console.log(statements);

            functionThatRequireData(statements.data);

     });

That way you can have the data you need, without using return.

As an alternative, if storing the definition of the function functionThatRequireData in a variable doesn't seem to work, you can still do something like:

var auxiliarFunction = function(data){
    functionThatRequireData(data);
}

And call auxiliarFunction function instead of functionThatRequireData (just in case you have problems with the scope or something similar).

Hope this helps.

jpgc
  • 764
  • 5
  • 19
  • Thanks, @jpgc, that's what I also thought, but it doesn't work for me... Says "undefined is not a function" – Aerodynamika Feb 20 '14 at 20:45
  • please edit your question with the code that's giving you that error, so we can check it out :) – jpgc Feb 20 '14 at 21:30
  • well actually this is the code that's in the question above. a more general version of it would be function(range, function(err, result) { var x = 'y'; }); and how would I return x outside of to pass it to another value. – Aerodynamika Feb 21 '14 at 12:22
0

Your problem is that you're trying to use statements.data and that object is only defined inside your anonymous function.

Try this way:

var results;
dbneo.cypherQuery(rangeQuery, function(err, statements){
    if(err) {
        err.type = 'neo4j';
        return fn(err);
    }

    console.log(statements);

    fn(null,statements.data);

    results = statements.data;
});
vsgoulart
  • 151
  • 1
  • 6
0

You are facing the situation why javascript is often said to lead to callback hell. You cannot do var results = statements.data this because at the time that line is executed, the async callback function function(err, statements){... may not yet be executed and thus your results will be undefined.

If you want your code to behave synchronously you need to use something called promises.

One good post about promises is here:

http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/

To solve your problem with the excellent Q library ( https://github.com/kriskowal/q ) you could write your function for example like this:

function cypherQuery() {
    var deferred = Q.defer();

    dbneo.cypherQuery(rangeQuery, function(err, statements){
        if(err) {
            err.type = 'neo4j';
            deferred.reject(err);
        } else {
            deferred.resolve(statements.data);
        }

        return deferred.promise;
 });
}

then you can call your function like this:

cypherQuery().then(function(result) {
    console.log(result);
})
hequ
  • 761
  • 6
  • 14
  • 2
    I think it is best the user understand async callbacks before making the choice to use promises, which is not the native way to handle a sync work in node.js. Furthermore, Promises have a lot of problems, such as they are slower than traditional callback. You should at least have adviced bluebird rather than Q. Bluebird is the only promise library which cares about performance and make benchmarks. Others are extremely slow, and Q despite its popularity, is one of the worst. – jillro Feb 20 '14 at 19:47
  • I agree, I wouldn't like to use promises as it's a node.js app... but thank you for your help! – Aerodynamika Feb 20 '14 at 20:45
  • Please could you clarify what are the problems when you say that promises have a lot of problems? Please also elaborate when you say that promises are not a "native" way to handle async? Callbacks are a mess and promises are a good way to avoid that mess. Also I would sacrifice performance over readability to a certain point anytime. – hequ Feb 20 '14 at 21:36