JavaScript Promises:带有bind的深层嵌套上下文(this)

时间:2016-01-12 04:11:24

标签: javascript promise ecmascript-6 es6-promise

因为我正在使用具有在同一原型中调用其他函数的函数的原型,所以我必须使用this来引用该方法

问题this已创建:

但是正因为如此,我必须保留一个上下文来使用this来构建非常丑陋的.bind(this)墙。

这是我为笑而做的一个简化例子。

Killmyself.prototype.fireLeMissles = function () {

    return new Promise(function(resolve,reject) {
        this.anotherFunction(param).then(function(result) {

        someList.forEach(function(item) {
          this.fireLeMissles().then(function(anotherResult){
            promiseList.push(anotherResult)
          })
        },this);
        Promise.all(promiseList).then(function(promiseItem){
          childPlacesIds.forEach(function(childPlaceId) {
            //Do Other Stuff
          },this);
        });
      resolve(result);
    }.bind(this).catch(function(err){
      console.log("Yea, life sucks sometimes.")
    }));
  }.bind(this));
}

Killmyself.prototype.another = function(){
   //Other stuff
}

你可以看到,因为在this.anotherFunction( ...和this.fireLeMissles(等同一个原型中调用函数...我必须深入保存上下文,现在(在我更大的中)这个版本很难使用这个代码。

问题:

这是一个“男人并且习惯于JavaScript的更难处理”的事情 - 或者你是否经验丰富的开发人员看到这样的深层绑定可以避免的简单方法?

3 个答案:

答案 0 :(得分:13)

如果您使用的是 ES6 ,则可以从保留上下文的arrow functions中受益。

var counter = function () {
    this.count = 0;
    setInterval( () => { // arrow function
        console.log(this.count++); // context is preserved
    }, 1000)
}
var counter = new counter();

因此,您的代码将变为:

Killmyself.prototype.fireLeMissles = function() {
    return new Promise((resolve, reject) => {
        this.anotherFunction(param).then(result => {
            someList.forEach(item => {
                this.fireLeMissles().then(anotherResult => {
                    promiseList.push(anotherResult)
                });
            });
            Promise.all(promiseList).then(promiseItem => {
                childPlacesIds.forEach(childPlaceId => {
                    //Do Other Stuff
                });
            });
            resolve(result);
        }).catch(err => {
            console.log("Yea, life sucks sometimes.")
        });
    });
}

对于 ES5 ,你可以像你做的那样使用.bind,也可以将this分配给具有所需上下文的函数中的其他内容,然后在内部函数中使用该变量。

Killmyself.prototype.fireLeMissles = function() {
    var self = this; /// use `self` instead of `this` from now on.
    return new Promise(function(resolve, reject) {
        self.anotherFunction(param).then(function(result) {
            someList.forEach(function(item) {
                self.fireLeMissles().then(function(anotherResult) {
                    promiseList.push(anotherResult)
                })
            });
            Promise.all(promiseList).then(function(promiseItem) {
                childPlacesIds.forEach(function(childPlaceId) {
                    //Do Other Stuff
                });
            });
            resolve(result);
        }).catch(function(err) {
            console.log("Yea, life sucks sometimes.")
        });
    });
}

答案 1 :(得分:2)

对于初学者我不明白你在这里需要new Promise..,就像@loganfsmyth所说的那样,我只会使用箭头功能并降低复杂性:

Killmyself.prototype.fireLeMissles = function (param) {

  return this.anotherFunction(param)
  .then(someList => {
    var promiseList = someList.map( item => this.fireLeMissles(item));
    return Promise.all(promiseList);
  }).then(childPlacesIds => {
    childPlacesIds.forEach(childPlacesId = {
      // .... do something;
    });
    // return something.
  }).catch(err => console.log("Yea, life sucks sometimes."));

}

P上。 S:我不确定这个param, someList, childPlacesIds的来源,并假设您正在将promiseList初始化为空数组。

答案 2 :(得分:0)

Mido的答案很好,我只是想提供一个替代方案,我认为这对我们来说很有用 - 使用代理商的承诺:

Killmyself.prototype.fireLeMissles = function () {
  let fn = this.anotherFunction(param);
  let others = fn.then(_ => someList.map(this.fireLeMissles, this));
  let othersP = Promise.all(others);
  othersP.then(/* do OtherStuff */);
  return othersP; // or whatever its then returned
}

当然,使用像bluebird这样的库会更容易。