如何避免通过多个回调传递承诺来解决承诺? - Deft.js

时间:2013-12-24 20:06:55

标签: extjs asynchronous rally promise deftjs

正如我的代码所示,我目前正在向一个承诺传递两个异步回调函数(成功和回调)。我认为应该可以这样做,但我还没有找到其他办法。

这是我创建承诺的函数,并等待所有这些完成:

_onModelLoaded: function(model) {
    var promises = [];

    _.each(this._customRecords, function(defect, index) {
        promises.push(this._getHistory(model, defect));
    }, this);

    Deft.Promise.all(promises).then({
        success: function(something) {
            console.log('woot',something);
        }
    });
},

_getHistory函数创建一个promise,然后将它传递给两个函数(_onHistoryLoaded和_onRevisionsLoaded),这样一旦运行了这些回调,promise就会得到解决:

_getHistory: function(model,defect) {
    var deferred = Ext.create('Deft.promise.Deferred');

    model.load(Rally.util.Ref.getOidFromRef(defect.RevisionHistory), {
        scope: this,
        success: function(record) {
            this._onHistoryLoaded(defect, record, deferred);
        }
    });

    return deferred.promise;
},

_onHistoryLoaded: function(defect, record, def) {
    record.getCollection('Revisions').load({
        fetch: ['RevisionNumber', 'CreationDate', 'User', 'Description'],
        scope: this,
        callback: function(revisions) {
            this._onRevisionsLoaded(revisions, defect, def);
        }
    });
},

_onRevisionsLoaded: function(revisions, defect, def) {

    _.each(revisions, function(revision, revisionIndex) {
        // Do stuff with each revision
    }, this);

    def.resolve(defect);
},

我不一定需要通过承诺传递最终缺陷,我只是将它放在resolve语句中进行测试。

注意:我的代码运行正常,我只是在寻求简化。

有没有办法避免创建一个承诺,只是通过几个异步函数传递它才能解决它?

2 个答案:

答案 0 :(得分:2)

我将尝试提供一些有用的提示,但首先要注意几点。

  1. 我对你要解决的领域问题一无所知,这使得很难确定事物的最佳名称,或者确切地说每个功能单元适合于宏观方案。< / p>

  2. 您正在使用的库似乎不支持Promise / A +和下一版JavaScript中使用的Promise API。您可以在http://promisesaplus.com/阅读真实承诺的规范,并在http://www.promisejs.org/implementations/

  3. 维护我最喜欢的实施的简短列表

    我会尝试编写代码,因为我会用“Promise”编写代码,这是第一个实现,也是我自己编写的代码。

    由于onHistoryLoaded实际上是一个异步操作,因此将其名称更改为它执行的操作并让它返回一个promise。对onRevisionsLoaded执行相同操作,并使getHistory只执行一项工作:

    _onModelLoaded: function(model) {
        var promises = _.map(this._customRecords, function(defect, index) {
            this._getHistoryRevisions(model, defect).then(function (revisions) {
                _.each(revisions, function (revision, revisionIndex) {
                  // Do stuff wich each revision
                }, this);
            }.bind(this));
        }, this);
    
        Promise.all(promises).done(function(something) {
            console.log('woot',something);
        });
    },
    
    _getHistoryRevisions: function (model, defect) {
        return this._getHistory(model, defect).then(function (record) {
            return this._getRevisions(record);
        }.bind(this));
    },
    
    _getHistory: function(model, defect) {
        return new Promise(function (resolve, reject) {
            model.load(Rally.util.Ref.getOidFromRef(defect.RevisionHistory), {
                scope: this,
                success: function(record) {
                    resolve(record);
                }
            });
        }.bind(this));
    },
    
    _getRevisions: function(record) {
        return new Promise(function (resolve, reject) {
            record.getCollection('Revisions').load({
                fetch: ['RevisionNumber', 'CreationDate', 'User', 'Description'],
                scope: this,
                callback: function(revisions) {
                    resolve(revisions);
                }
            });
        }.bind(this));
    }
    

    只要有可能,最好在他们做的事情之后命名这些函数,而不是导致它们的原因。它们不应该真正需要与它们之前或之后发生的事情相结合。承诺背后的大部分想法是,它使我更容易回到我调用函数的编程的同步模型,它做了一件事,然后返回一个值。函数对其使用位置的认识越少,在其他地方重用的越容易:)

答案 1 :(得分:0)

@ForbesLindesay提供的答案非常有用。但是,我使用的是Deft 0.8.0,因此这些承诺的实施存在一些差异。以下是我如何让链条起作用:

_onModelLoaded: function(model) {
    var promises = [];

    _.each(this._customRecords, function(defect, index) {
        promises.push(this._getHistoryRevisions(model, defect).then(function (revisions) {
            // do stuff with revisions
        }.bind(this)));
    }, this);

    Deft.Promise.all(promises).then(function(something) {
        console.log('woot',something);
    }.bind(this));
},

_getHistoryRevisions: function (model, defect) {
    return this._getHistory(model, defect).then(function (record) {
        return this._getRevisions(record);
    }.bind(this));
},

_getHistory: function (model, defect) {
    var deferred = Ext.create('Deft.promise.Deferred');

    model.load(Rally.util.Ref.getOidFromRef(defect.RevisionHistory), {
        scope: this,
        success: function(record) {
            deferred.resolve(record);
        }
    });

    return deferred;
},

// grabbing the revisions for each defect
_getRevisions: function(record) {
    var deferred = Ext.create('Deft.promise.Deferred');

    record.getCollection('Revisions').load({
        fetch: ['RevisionNumber', 'CreationDate', 'User', 'Description'],
        scope: this,
        callback: function(revisions) {
            deferred.resolve(revisions);
        }
    });

    return deferred;
},

主要区别来自最后两个函数_getHistory_getRevisions - 我不得不创建一个new Promise(...)的延迟对象而不是Ext.create('Deft.promise.Deferred');来返回并在回调中解决。

希望这可以帮助其他人解决使用旧版DeftJS

的问题