Using this within a promise in AngularJS

て烟熏妆下的殇ゞ 提交于 2019-11-29 03:11:57

问题


Is there a best-practice solution to be able to use within in promise this? In jQuery i can bind my object to use it in my promise/callback - but in angularJS? Are there best-practice solutions? The way "var service = this;" i don't prefer ...

app.service('exampleService', ['Restangular', function(Restangular) {
    this._myVariable = null;

    this.myFunction = function() {
        Restangular.one('me').get().then(function(response) {
            this._myVariable = true; // undefined
        });
    }
}];

Are there solutions for this issue? How i can gain access to members or methods from my service within the promise?

Thank you in advance.


回答1:


The generic issue of dynamic this in a callback is explained in this answer which is very good - I'm not going to repeat what Felix said. I'm going to discuss promise specific solutions instead:

Promises are specified under the Promises/A+ specification which allows promise libraries to consume eachother's promises seamlessly. Angular $q promises honor that specification and therefor and Angular promise must by definition execute the .then callbacks as functions - that is without setting this. In strict mode doing promise.then(fn) will always evaluate this to undefined inside fn (and to window in non-strict mode).

The reasoning is that ES6 is across the corner and solves these problems more elegantly.

So, what are your options?

  • Some promise libraries provide a .bind method (Bluebird for example), you can use these promises inside Angular and swap out $q.
  • ES6, CoffeeScript, TypeScript and AtScript all include a => operator which binds this.
  • You can use the ES5 solution using .bind
  • You can use one of the hacks in the aforementioned answer by Felix.

Here are these examples:

Adding bind - aka Promise#bind

Assuming you've followed the above question and answer you should be able to do:

Restangular.one('me').get().bind(this).then(function(response) {
    this._myVariable = true; // this is correct
});

Using an arrow function

Restangular.one('me').get().then(response => {
    this._myVariable = true; // this is correct
});

Using .bind

Restangular.one('me').get().then(function(response) {
    this._myVariable = true; // this is correct
}.bind(this));

Using a pre ES5 'hack'

var that = this;
Restangular.one('me').get().then(function(response) {
    that._myVariable = true; // this is correct
});

Of course, there is a bigger issue

Your current design does not contain any way to _know when _myVariable is available. You'd have to poll it or rely on internal state ordering. I believe you can do better and have a design where you always execute code when the variable is available:

app.service('exampleService', ['Restangular', function(Restangular) {
    this._myVariable =Restangular.one('me');
}];

Then you can use _myVariable via this._myVariable.then(function(value){. This might seem tedious but if you use $q.all you can easily do this with several values and this is completely safe in terms of synchronization of state.

If you want to lazy load it and not call it the first time (that is, only when myFunction is called) - I totally get that. You can use a getter and do:

app.service('exampleService', ['Restangular', function(Restangular) {
    this.__hidden = null;
    Object.defineProperty(this,"_myVariable", {
      get: function(){ 
        return this.__hidden || (this.__hidden = Restangular.one('me')); 
      }
    });
}];

Now, it will be lazy loaded only when you access it for the first time.



来源:https://stackoverflow.com/questions/26903430/using-this-within-a-promise-in-angularjs

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!