0

For anyone who uses callbacks, how do I approach it when the method is an asynchronous setter?

Here's an example

class API
{
  constructor()
  {
     this.token = null;
  }
  refreshToken(callback)
  {
    request("http://api.com/token", (token) => {
      this.token = token;
      callback(token);
    });
  }
}

What would be the point of returning the token if I've already set it in the object's property?

I find myself dumbfounded when I end up doing something like this:

api.refreshToken((token) => {
  //callback is used as a 'wait until token arrives' for proceeding code
  request("http://api.com/data?token=" + token);
});

But I need it as an object property so that I can reuse the token, such as: request("http://api.com/data?token=" + this.token);

But now I have two variables for the same thing, provided by OOP's property and the callback. It's a pretty stupid problem, but I need direction.

  • It stores the token so you don't have to. The callback is a signal that something happened. You don't need to use the arg right away. – ratchet freak Jun 21 '17 at 11:38
  • @ratchetfreak Or do I assign the token in the method's callback to justify using the argument? Feels like I might be pondering on how "atomic" each function should be. – Vic Jun 21 '17 at 11:41
  • You wouldn't even need to have a token class member unless you intend to cache it. Simply assigning it is unnecessary until you actually use it outside of the context of the callback. – Neil Jun 21 '17 at 12:29
  • @Neil I did say so that I can reuse the token... – Vic Jun 21 '17 at 12:30
1

There is nothing inherently wrong with this. If provided an argument I feel like getToken is a more appropriate method name, which could call refreshToken if required:

class API {
    constructor() {
        this.token = null;
    }
    getToken(callback) {
        if (this.tokenIsValid()) {
            callback(this.token);
        } else {
            this.refreshToken((token) => {
                this.token = token;
                callback(token);
            });
        }
    }
    tokenIsValid() {
        // ...
    }
    refreshToken(callback) {
        // ...
    }
}

Now a token argument makes sense:

api.getToken(token => {
    request("http://api.com/data?token=" + token);
});

Refreshing the token is an implementation detail that should not be leaking out to code using your class. Give outside code a getToken method. Refreshing the token is not the responsibility of the code using your API class. They only need to get the token, and they shouldn't have to care if the token is stale and needs to be renewed.

The big advantage here is you are free to refactor the API class to change how it handles tokens, and prevent downstream changes in code using the API class.

This would be called Separation of Concerns.

  • Damn, this seems like a better approach than my auto-refresher. Thanks for the answer, I will wait for more though. – Vic Jun 21 '17 at 12:03
  • @Vic: This isn't a replacement for the auto-refresher. Instead it is an augmentation of that feature, separating the "refresh token" part from the "get token" part to clarify how your api object should be used. – Greg Burghardt Jun 21 '17 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.