Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript承诺:绑定的深层嵌套上下文(this)_Javascript_Promise_Ecmascript 6_Es6 Promise - Fatal编程技术网

JavaScript承诺:绑定的深层嵌套上下文(this)

JavaScript承诺:绑定的深层嵌套上下文(this),javascript,promise,ecmascript-6,es6-promise,Javascript,Promise,Ecmascript 6,Es6 Promise,因为我使用的原型中有函数调用同一原型中的其他函数,所以我必须使用this 问题此产生: 但正因为如此,我必须保留一个上下文来使用这个,这让我形成了非常丑陋的。绑定(这个)墙。 这是一个简单的例子,我为笑 Killmyself.prototype.fireLeMissles = function () { return new Promise(function(resolve,reject) { this.anotherFunction(param).then(funct

因为我使用的原型中有函数调用同一原型中的其他函数,所以我必须使用
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的更难的方面”的事情吗?或者你有经验的开发人员看到了避免这种深度绑定的简单方法吗?

如果你使用的是ES6,你可以从中受益,这样可以保留上下文

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
,也可以将
指定给函数中具有所需上下文的其他内容,然后在内部函数中使用该变量

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.")
        });
    });
}

首先,我不理解您需要一个
新承诺。
这里,就像@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."));

}

注:我不确定这个
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这样的库,这会变得更容易。

我会使用
.bnd(这个)
如果
嵌套
是一个级别,那么其他人会使用
var\u this=this
,并会在嵌套函数中引用
\u this
。既然你用ES6标记了它,你熟悉箭头函数吗?@loganfsmyth我一直尝试使用es5,因为我从来没有想过用babel进行服务器端编码,但是我很熟悉arrow函数的一个优点,我相信,就是上下文是隐含的。很好地澄清一下,因为您标记了ES6,我以为您要求的是ES6解决方案。节点4和节点5支持arrow函数和承诺,所以很多人都使用它们。@loganfsmyth抱歉,我忘了标记es5。我只是假设我是猪让自己陷入一个糟糕的设计,或是一个更圆滑的es6解决方案(我还没有深入研究)出于这些目的而存在。@Amir正在使用es6,node.js服务器端编码非常常见?每当我看到es6代码时,我总是想到前端编码可以使用es6,只要它与babel或其他类似产品捆绑在一起。另外,感谢您的一篇非常有见地的帖子!我一定会在社区回复后给予赞扬。:)@当然,NickPineda。我总是在我的节点项目中使用es6。对于服务器端部分,节点本身支持这一点,并且由于所有操作都将在服务器上执行,所以您不必担心客户端的支持。如果您愿意在客户端使用es6,我建议使用像babeljs这样的transpiler。@NickPineda我在sev中使用过es6生产中的所有项目。包括客户端和服务器端。使用
grunt
gulp
或类似工具设计工作流程并不困难,可以将所有es6文件转换为es5,以便交付生产。es6在数月前正式发布,目前还没有任何工具100%支持它,但足以回答这个问题stion.Yes promiseList将是一个简单的数组。我对原始代码进行了大量的简化,以强调我正在处理的重复绑定问题。如果原始代码仍然是这样的话,请确保牢记
新承诺
这一点。这是正确的答案,重构了[deferred antipattern](stackoverflow.com/questions/23803743/what-is-explicit-promise-construction-antipattern-and-how-do-i-avoid-it)。我猜您可以进一步将其缩短为
someList.map(this.fireLeMissles,this)
:)