我有一个点击处理程序,需要一个接一个地进行多次异步调用。我选择使用 promise(准确地说是 RSVP )来构建这些调用。
下面,您可以看到 Controller 内部的 clickA
处理程序(这是一个 Ember 应用程序,但我认为问题更普遍):
App.SomeController = Ember.Controller.extend({
actions: {
clickA: function() {
var self = this;
function startProcess() {
return makeAjaxCall(url, {
'foo': self.get('foo')
});
}
function continueProcess(response) {
return makeAjaxCall(url, {
'bar': self.get('bar')
});
}
function finishProcess(response) {
return new Ember.RSVP.Promise(...);
}
...
startProcess()
.then(continueProcess)
.then(finishProcess)
.catch(errorHandler);
}
}
});
看起来不错,但现在我必须添加第二个操作来重用某些步骤。
由于每个内部函数都需要从 Controller 访问属性,因此一种解决方案是使它们成为 Controller 的方法:
App.SomeController = Ember.Controller.extend({
startProcess: function() {
return makeAjaxCall(url, {
'foo': this.get('foo')
});
},
continueProcess: function(response) {
return makeAjaxCall(url, {
'bar': this.get('bar')
});
},
finishProcess: function(response) {
return new Ember.RSVP.Promise(...);
},
actions: {
clickA: function() {
this.startProcess()
.then(jQuery.proxy(this, 'continueProcess'))
.then(jQuery.proxy(this, 'finishProcess'))
.catch(jQuery.proxy(this, 'errorHandler'));
},
clickB: function() {
this.startProcess()
.then(jQuery.proxy(this, 'doSomethingElse'))
.catch(jQuery.proxy(this, 'errorHandler'));
}
}
});
所以,我的问题是:有没有更好的方法?我可以以某种方式摆脱所有那些
jQuery.proxy()
调用吗? 最佳答案
一个解决方案是使用更好的 promise 库。
Bluebird 有一个 bind 函数,它允许您将上下文绑定(bind)到整个 promise 链(您传递给 then
或 catch
或 finally
的所有函数都使用此上下文调用)。
这是一篇(我写的)关于像你想保留 Controller /资源一样使用绑定(bind) promise 的文章:Using bound promises to ease database querying in node.js
我这样建立我的 promise :
// returns a promise bound to a connection, available to issue queries
// The connection must be released using off
exports.on = function(val){
var con = new Con(), resolver = Promise.defer();
pool.connect(function(err, client, done){
if (err) {
resolver.reject(err);
} else {
// the instance of Con embeds the connection
// and the releasing function
con.client = client;
con.done = done;
// val is passed as value in the resolution so that it's available
// in the next step of the promise chain
resolver.resolve(val);
}
});
// the promise is bound to the Con instance and returned
return resolver.promise.bind(con);
}
这让我可以这样做:
db.on(userId) // get a connection from the pool
.then(db.getUser) // use it to issue an asynchronous query
.then(function(user){ // then, with the result of the query
ui.showUser(user); // do something
}).finally(db.off); // and return the connection to the pool
关于javascript - 链式 promise 和保留 `this`,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21315817/