Javascript 在qooxdoo应用程序中使用承诺

Javascript 在qooxdoo应用程序中使用承诺,javascript,ecmascript-6,qooxdoo,ecmascript-harmony,Javascript,Ecmascript 6,Qooxdoo,Ecmascript Harmony,在qooxdoo类中,我有一组需要链接(序列化)的异步方法: 随着步骤数量的增加,链变得难以跟踪,代码变得不可读。我们可以做的是使用以下方法重写代码: 这很有效,但只有在我们添加一些真正的逻辑之前。请记住,这是一个qooxdoo类,其中包含了大量封装到中的内容。但突然发现,then()和catch()中使用的异步*方法和匿名函数都将其this上下文绑定到了全局对象window。为了能够使用实际的此,我们可以执行重新绑定: main: function() { new Promise(th

在qooxdoo类中,我有一组需要链接(序列化)的异步方法:

随着步骤数量的增加,链变得难以跟踪,代码变得不可读。我们可以做的是使用以下方法重写代码:

这很有效,但只有在我们添加一些真正的逻辑之前。请记住,这是一个qooxdoo类,其中包含了大量封装到
中的内容。但突然发现,then()和catch()中使用的异步*方法和匿名函数都将其
this
上下文绑定到了全局对象
window
。为了能够使用实际的
,我们可以执行重新绑定:

main: function() {
    new Promise(this.async1.bind(this))
    .then(function() {
        this.doSomeStuff();
        return new Promise(this.async2.bind(this));
    }.bind(this)).then(function() {
        return new Promise(this.async3.bind(this));
    }.bind(this)).then(function() {
        this.doSomeFinalStuff();
    }.bind(this)).catch(function() {
        this.doStuffOnError();
    }.bind(this));
},

async1: function(resolve, reject) {
    this.doOtherStuff();
    var json = new qx.data.store.Json("http://...");
    json.addListener("loaded", function(event) {
        ...
        resolve();
    });
}

这终于行得通了,但代码太难看了!有没有办法摆脱那些手动绑定?当我们引用实例方法
this.async1
时,为什么不隐式绑定
this

如果您添加
var self=this在顶部,在所有函数中,您可以通过调用self来引用对象本身:

main: function() {
    var self = this;
    new Promise(self.async1)
    .then(function() {
        return new Promise(self.async2);
    }).then(function() {
        return new Promise(self.async3);
    }).catch(...);
},
检查

基本上,从根本上看,你并没有做错什么。这就是上下文应该如何工作的。您真正需要的是为您的特定用例提供一些语法支持。您可以自己制作这些sugar扩展,也可以使用库来完成一些繁重的工作


您还可以像Danbopes建议的那样重新构造代码,并对其进行组织,以减少内联绑定。这将使您能够更好地阅读流。

不幸的是,这将只释放一半的绑定(用于匿名函数的绑定)。async*方法仍将恢复其
上下文,否则它将默认为
窗口
。观察一下:如果您需要调用一长串函数,无论它们是否异步,我认为您的总体设计很可能有问题。(当然,我可能错了——显然我没有看到代码。)至于默认情况下没有绑定的函数:将其设为默认值将防止传递未绑定的函数——这对于函数式编程来说是必不可少的——没有办法取消绑定一个函数。顺便问一下:如果您使用一个
self
变量,您是否需要上面的最后一个
bind()
调用,正如接受的答案中所建议的那样?我已经看到,当您需要多个服务器提供的资源来执行一个操作时,有必要进行一系列异步调用。我要做的是将所有逻辑打包到一个函数中,我将把它作为回调传递给所有需要异步获取的函数。此函数将首先检查是否满足所有先决条件,然后继续执行所有计算。依我看,如果可能的话,切换到这样的代码结构将显著提高可读性-而不是将可能相关的逻辑分散在多个函数中,而是将它们全部放在一个地方。或者,您可以使用基于事件的结构-而不是传递回调,您有对其注册事件处理程序的回调触发事件。依我看,这仍然会改进代码结构。如果只是简单的承诺,您将错失使用描述性函数名来记录意图的机会。对于事件,您可以获得两种文档:事件名称和处理程序名称。尝试想出链接异步调用的最佳位置-如果您实现质询-响应身份验证机制,我认为使用一系列异步调用更具描述性——我上面描述的两个解决方案没有提供强而明确的因果顺序保证(虽然qooxdoo事件提供隐式),但它是必需的,并且在挑战-响应身份验证的情况下记录它是很好的。但是除了类似的情况之外,我认为链接异步调用对代码的读者来说并不好。
main: function() {
    new Promise(this.async1.bind(this))
    .then(function() {
        this.doSomeStuff();
        return new Promise(this.async2.bind(this));
    }.bind(this)).then(function() {
        return new Promise(this.async3.bind(this));
    }.bind(this)).then(function() {
        this.doSomeFinalStuff();
    }.bind(this)).catch(function() {
        this.doStuffOnError();
    }.bind(this));
},

async1: function(resolve, reject) {
    this.doOtherStuff();
    var json = new qx.data.store.Json("http://...");
    json.addListener("loaded", function(event) {
        ...
        resolve();
    });
}
main: function() {
    var self = this;
    new Promise(self.async1)
    .then(function() {
        return new Promise(self.async2);
    }).then(function() {
        return new Promise(self.async3);
    }).catch(...);
},