6

We are writing server code in nodejs and using Parse javascript sdk. Often we need to fetch or update various Parse objects. For example, fetch a user with username 'Example'.

  function fetchUser(username)
  {
      var User = Parse.Object.extend("User");
      var query = new Parse.Query("User");
      query.equalTo("username",username);

      query.first({
        success: function(results) {
        console.log("Successfully retrieved " + results.length + " scores.");
        return results;
      },
      error: function(error) {
        console.log("Error: " + error.code + " " + error.message);
      }
     });
  }

This function might be called by some other function:

function test()
{
    var user = fetchUser("example");
    console.log(user); // would often print undefined
    return user;
}

function top()
{
    // some code
    var user = test();
    //some code
}

// and the function top() mmight be called by some other functions

The problem is that I would get undefined results because the find/first operations runs asynchronously. Is there any way to ensure that fetchUser() function returns only when the find/first operation is successful/complete?

Paagalpan
  • 1,261
  • 2
  • 16
  • 25
  • why don't you just provide a callback to fetchUser and test? If you want to have a better readable code use promises instead of callbacks. – Tobi Nov 02 '16 at 13:38
  • 2
    You can't make async operations be synchronous. Cannot be done in Javascript. Stop trying. Learn how to program asynchronously with callbacks or promises or switch to a blocking/threaded environment like Java that lets you do things like this blocking/synchronously in threads (with the associated compromises of that architecture). – jfriend00 Nov 02 '16 at 17:36
  • Really new to javascript. Sometimes, simply a 'just not possible' is also a good enough response. Thanks. :) – Paagalpan Nov 03 '16 at 11:20

2 Answers2

5

JavaScript is asynchronous by its nature. You have to pass a callback to the fetchUser() function and rewrite your client code to something like this:

function fetchUser(username, callback) {
    // do request and call callback(null, user) on success
    // or callback(some_error_object) on failure.
}

function test(callback) {
    var onFetched = function(err, user) {
        console.log(user);
        callback(err, user);
    }
    var user = fetchUser("example", onFetched);
}

Also you can use promises or generators (since EcmaScript 6) approaches.

UPD: Although some APIs (DB drivers, fs and so on) allow one to use them in a synchronous manner, it's considered as bad way to write a code in JavaScript. Since JS runs your code in a single thread, blocking this thread by using synchronous calls will block all other tasks. So, if you develop a web server that handles a few clients simultaneously and decided to use synchronous calls to some API, only one client at a time will be served while other clients will be in a pending state.

Ivan Velichko
  • 6,348
  • 6
  • 44
  • 90
  • Thanks a lot for the response and the great example. And the update was really helpful. So thanks. I couldnt decide which answer to accept but went with the other one as it had an example for promises as well. Sorry. – Paagalpan Nov 03 '16 at 11:19
3

NodeJs is single threaded, so we should not block process.

in your case you have two options 1. passing callback 2. using Promise library (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)

Ex 1: passing callback

    function fetchUser(username, callback)
  {
      var User = Parse.Object.extend("User");
      var query = new Parse.Query("User");
      query.equalTo("username",username);

      query.first({
        success: function(results) {
        console.log("Successfully retrieved " + results.length + " scores.");
        callback(null,results)
      },
      error: function(error) {
        console.log("Error: " + error.code + " " + error.message);
        callback(error)
      }
     });
  }

Client code:

  function test()
    {
        var user = fetchUser("example", function(error, user){
         if(error){
          console.error(error)
         }else {
          console.log(user)
         }
      });
 }

Ex 2: Using Promising library

  function fetchUser(username){
    return new Promise(function(resolve, reject){
        var User = Parse.Object.extend("User");
        var query = new Parse.Query("User");
        query.equalTo("username",username);

        query.first({
            success: function(results) {
                console.log("Successfully retrieved " + results.length + " scores.");
                resolve(results)
            },
            error: function(error) {
                console.log("Error: " + error.code + " " + error.message);
                reject(error)
            }
        });
    })
}

Client code:

function test()
    {
      fetchUser("example")
        .then(function(user){
          console.log(user)  
        })
        .catch(function(error){
         console.error(error)
        })  
 }
  • Thanks for detailed examples in both cases. :) – Paagalpan Nov 03 '16 at 11:18
  • [Parse Queries](http://parseplatform.org/Parse-SDK-JS/api/classes/Parse.Query.html#methods_find) return a Parse.Promise, which is almost entirely Promises/A+ compliant - so you don't have to wrap it in another Promise library.... – simonberry Jul 04 '17 at 18:19