4

I am trying to write a validation function, that validates my request headers. It returns true if all headers are ok and false if there is something wrong. I execute this function for every (almost) request. The problem is, I don't know how to return the main function in case I use callbacks and setting any flags does not work, due to some issues with variable scope. Everything was good when I was working without callbacks, I just used underscore to query my JSONs. Now I use NeDB and bound to callbacks I cannot get the job done. I tried to use a global "res" variable but the problem is, when I assign the value of parameter "cnt" (0 if token not found, 1 if there is a token) to "res", then the value of "res" is always 1 iteration behind "cnt": i.e.:

request1 (valid): cnt = 1; res = undefined;
request2 (valid): cnt = 1; res = 1;
request3 (invalid): cnt = 0; res = 1;
request4 (valid): cnt = 1; res = 0;

All I want to do is to return the main function with true if "cnt" = 1 and false if "cnt" = 0, either with help of a global variable or using another method.

function validateHeaders(request) {
    if (request.headers.username && request.headers.deviceid) {

        if (...) {
            function getResult(callback) {
                db.tokens.count({...
                }, function (err, cnt) {
                    if (err) {
                        console.log(err);
                    } else {
                        callback(cnt);
                    }
                });
            }

            getResult(function (cnt) {
                res = cnt;
                console.log({
                    count: cnt
                });
            });

            console.log({
                result: res
            });
        } else {
            return false;
        }
    } else {
        return false;
    }
}
Zbyslaw Tomyn
  • 41
  • 1
  • 2
  • Since the function has an asynchronous function inside and you shouldn't return until this has finished, you need to make your main function `validateHeaders` asynchronous too, by adding a callback. – Ben Fortune Oct 01 '14 at 15:14
  • "asynchronous" means the function is entered into an event queue to be run -- *at the earliest* -- when the current synchronous function has completed. Thus, the JavaScript engine strictly guarantees that `validateHeaders` will completely run and return a value before any asynchronous operation begins (such as the callback to `db.tokens.count`). – apsillers Oct 01 '14 at 15:33
  • This is basically a duplicate of [How to return the response from an Ajax call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) -- simply substitute "Ajax success function" with `db.tokens.count`. Other similar questions are [Understanding Node.js processing order](http://stackoverflow.com/q/14564408/710446) and [how to make synchronous call to indexeddb method from javascript](http://stackoverflow.com/q/13972243/710446) – apsillers Oct 01 '14 at 15:35

2 Answers2

2

You can't return a meaningful value like that from a function that performs asynchronous, non-blocking operations inside. What you need to do instead is pass in a callback:

function validateHeaders(request, cb) {
  if (request.headers.username && request.headers.deviceid) {
    if (...) {
      db.tokens.count({
        // ...
      }, function (err, cnt) {
        if (err) {
          cb(err);
        } else {
          cb(null, cnt === 1);
        }
      });
      return;
    }
  }
  cb(null, false);
}

Then use it like:

validateHeaders(req, function(err, success) {
  if (err) throw err; // TODO: improve error handling
  console.log(success);
});
mscdex
  • 104,356
  • 15
  • 192
  • 153
0

if you want to use the return value of callback function of nodejs. You can't use it in sync style. you can obey convention of nodejs.

function validateHeaders(request, cb) {
    if (request.headers.username && request.headers.deviceid) {

        if (...) {
            function getResult(callback) {
                db.tokens.count({...
                }, function (err, cnt) {
                    callback(err, cnt);
                });
            }

            getResult(function (err, cnt) {
                if (err) {
                    cb(err);
                } else {
                    if (cnt === 0)
                        cb(null, false);
                    else
                        cb(null, true);                    
                }
            });
        } else {
            cb(null, false)
        }
}

you can use the callback result. Notice: do not use return in async function. use callback to transfer the value. the callback function of nodejs style has 2 arguments. The first is err, the second is result.

lutaoact
  • 4,149
  • 6
  • 29
  • 41