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)
:)