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

JavaScript Promises : Deep nested context with bind(this)

因为我使用的原型具有调用同一原型中其他函数的函数,所以我必须使用 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(... 我必须深度保存上下文,现在(在我的更大的版本)使这段代码难以使用。

问题:

这是 "man up and get use to the harder aspects of JavaScript" 的事情吗 - 还是您经验丰富的开发人员看到了可以避免像这样的深度绑定的简单方法?

如果您正在使用 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.")
        });
    });
}

对于初学者我不明白你在这里需要一个 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 初始化为空数组。

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 这样的库会更容易。