3

I'm struggling with the async flow of Node.js. Assume you have class below:

function myClass() {
  var property = 'something';
  var hasConnected = false;

  this.connect = function(params) {
    //Some logic that connects to db and in callback returns if the connection is successful
    connectToSomeDB('ConnectionString', function(connectionResult) {
      hasConnected = connectionResult
    })
  };

  this.get = function(params) {
    if(hasConnected) {
      DoGetOperation() //
    }
    else {
      //Another question. What should be done here. Call the connect again?
    }
  }
}

Considering the Javascript and Node structures I certainly believe there are some major issues with my design but I cannot figure a way out since connect must be called in order for any operation to work properly. But when I do some logging after the operations:

brandNewObject = myClass();
brandNewObject.connect();
brandNewObject.get();

I observe that the get function is called before obtaining the global isConnected variable. What can I do to make this work without actually going against the async structure of Node?

Ideally, the solution I'm looking for is actually to handle 'connection' internally instead of defining a callback 'outer class'

3 Answers 3

1

There are different work-arounds for this.

One simple way is similar to what you are doing

this.get = function(params) {
    if (hasConnected) {
        DoGetOperation(params);
    } else {
        //here you can check the status of the connect. if it is still in 
        //progress do nothing. if the connection has failed for some reason
        //you can retry it. Otherwise send a response back indicating that the
        //operation is in progress.
    }
}

Another method might be to use the same async callback mechanism for your get function, which would change your method signature to something like this.

this.deferredOperations = new Array();

this.get = function(params, callback) {
    if (hasConnected) {
       //using a callback as an optional parameter makes the least 
       //impact on your current function signature. 
       //If a callback is present send the data back through it, 
       //otherwise this function simply returns the value (acts synchronously).
       if (callback !== null) {
         callback(DoGetOperation(params));
       } else {
         return DoGetOperation(params);
       }
    } else {
       this.deferredOperations.push([params,callback]);
    }
}

//connect changes now
this.connect = function(params) {
//Some logic that connects to db and in callback returns if the connection is successful
connectToSomeDB('ConnectionString', function(connectionResult) {
  hasConnected = connectionResult;
  if (hasConnected && this.deferredOperations.length > 0) {
    for (var i=0; i < this.deferredOperations.length; i++) {
      var paramFunction = this.deferredOperations.pop();
      var params = paramFunction[0];
      var func = paramFunction[1];
      DoAsyncGetOperation(params, func); //Need to write a new function that accepts a callback
    }
  }
})
};

HTH

Sign up to request clarification or add additional context in comments.

Comments

1

You have to use callbacks.

function myClass() {
  var property = 'something';
  var hasConnected = false;

  // added second parameter
  this.connect = function(params, callback) {
    //Some logic that connects to db and in callback returns if the connection is successful
    connectToSomeDB('ConnectionString', function(connectionResult) {
      hasConnected = connectionResult;
      // Now call the callback!
      callback();
    })
  };

  this.get = function(params) {
    if(hasConnected) {
      DoGetOperation() //
    }
    else {
      //Another question. What should be done here. Call the connect again?
    }
  }
}
brandNewObject = myClass();
brandNewObject.connect({}, function () {
  // this function gets called after a connection is established
  brandNewObject.get();
});

2 Comments

Thanks a lot for the answer. But that is kind of against the modularity I'm looking for. The reason is that the brandNewObject will be used throughout the entire project. Thus there will be multiple 'get's and 'set's. So if I want to perform an operation I have to make a connect for each function instead doing one connect and later on using it globally. Also, myClass aims to be a redisClient so I cannot connect for each function since it will increase the number of clients dramatically
I know of two ways to handle the async flow of node.js. The first one is using callbacks as I suggested, the second one is using Promises. Both are different than the "function returns value which I then can use"-flow you might be used to (You should not want to have this kind of flow in a node.js application). To learn more about promises I recommend playing around with Q (github.com/kriskowal/q)
1

Add a callback parameter to your connect method.

  this.connect = function(params, callback) {
    //Some logic that connects to db and in callback returns if the connection is successful
    connectToSomeDB('ConnectionString', function(connectionResult) {
      hasConnected = connectionResult;

      // Call the callback provided
      callback(params);
    })
  };

You can then call it like this:

brandNewObject = myClass();
brandNewObject.connect({}, function(/* optionally, "params" */) {
    brandNewObject.get();
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.