q.all似乎行为不同,为什么?

时间:2014-07-23 11:55:31

标签: javascript promise q

这是我的代码,我希望从顶部开始,执行将继续下去。前两个子句从数据库中获取记录,然后更新“self”对象。但是,当执行命中Q.all时,该方法返回Promises而不是实际解析promise并将值放入loc(最终是'self')。最终,承诺将得到解决,但后面的子句中返回'self self'。我需要在'return self'运行之前设置self.locations。

return dao.getRecords(APP_COLLECTION, filters).then(function(data) {
    return self.loadClientAppImpl(data);
}).then(function() {
    locArray = self.app.field_194_raw;
    return dao.getChildren("object_23", self.appId, "field_210", "field_164").then(function(knackRecord) {
        self.priorCarriers = knackRecord.records;
    });
}).then(function() {
    var locPromiseArray = getPromisesArray(locArray);
    return Q.all(locPromiseArray).then(function(locs){
        self.locations = locs;
    });
}).then(function() {
    return self;
}).done();

我认为多重承诺应该像单一呼叫承诺一样?

即。 dao.getRecords很好,但为什么Q.all([dao.getRecords1,dao.getRecord2等])不能正常工作(即在'return self;'之前没有解决)?

以下代码工作正常,我用一个承诺替换了Q.all,一切都按预期工作(即返回自己在链中称为last)。问题仍然存在:为什么Q.all的工作方式不一样?我假设这只是它应该工作的方式,我不了解实现。

return dao.getRecords(APP_COLLECTION, filters).then(function(data) {
    self.loadClientAppImpl(data);
}).then(function() {
    locArray = self.app.field_194_raw;
    return dao.getChildren("object_23", self.appId, "field_210", "field_164").then(function(knackRecord) {
        self.priorCarriers = knackRecord.records;
    });
}).then(function() {
    var locPromiseArray = getPromiseArray(locArray);
    return locPromiseArray[0].then(function(locs){
        self.locations = locs;
    });
}).then(function() {
    return self;
}).done();

这是getPromisesArray方法

function getPromiseArray (locArray) {
    var locationCollection = "object_22";
    //create a promise for all of the records
    var locationPromiseArray = [];
    if(locArray[0]){
        var locId0 = locArray[0].id;
        //dao.getRecord returns a promise
        locationPromiseArray.push(dao.getRecord(locationCollection, locId0));
    }       

    if(locArray[1]){
        var locId1 = locArray[1].id;
        locationPromiseArray.push(dao.getRecord(locationCollection, locId1));
    }

    if(locArray[2]){
        var locId2 = locArray[2].id;
        locationPromiseArray.push(dao.getRecord(locationCollection, locId2));
    }            

    if(locArray[3]){
        var locId3 = locArray[3].id;
        locationPromiseArray.push(dao.getRecord(locationCollection, locId3));
    }
    return locationPromiseArray;
};

感谢您的帮助!

标记

PS。我注意到下面的代码表现不同,我原本期望它的工作方式相同。开始怀疑我是否发现了一个bug。在第一种情况下,'结果'用值填充(应该是)。在第二种情况下,“结果”是一种承诺。它们不应该是这样或那样的吗?

return dao.getRecords(APP_COLLECTION, filters).then(function(data) {
    self.loadClientAppImpl(data);
}).then(function() {
    return dao.getChildren("object_23", self.appId, "field_210", "field_164");
}).then(function(knackRecord) {
    self.priorCarriers = knackRecord.records;
    locPromiseArray = getPromiseArray(self.app.field_194_raw);
    return Q.all(locPromiseArray).then(function(results){
            self.locations = results;
            return self;  
    });
});

return dao.getRecords(APP_COLLECTION, filters).then(function(data) {
    self.loadClientAppImpl(data);
}).then(function() {
    return dao.getChildren("object_23", self.appId, "field_210", "field_164");
}).then(function(knackRecord) {
    self.priorCarriers = knackRecord.records;
    locPromiseArray = getPromiseArray(self.app.field_194_raw);
    return Q.all(locPromiseArray);
}).then(function(results){
        self.locations = results;
        return self;  
});

2 个答案:

答案 0 :(得分:1)

很难理解为什么用Q.all(...)替换单个承诺会得到所需的结果。您对正在发生的事情的分析可能是不正确的。

但是,这里有一些想法。

除非通过返回新的承诺或不同的值进行过滤,否则不需要中间链.then()。一个中间链.then(),它的回调只是做出一个贡献,是一个候选人。你有两个这样的任务。

  • self.priorCarriers = knackRecord.records;
  • self.locations = locs;

这样的事情很容易出错,但我认为你的主要代码块会重新排列如下:

return dao.getRecords(APP_COLLECTION, filters).then(function(data) {
    return self.loadClientAppImpl(data);
}).then(function() {
    return dao.getChildren("object_23", self.appId, "field_210", "field_164");
}).then(function(knackRecord) {
    self.priorCarriers = knackRecord.records;
    return Q.all(getPromisesArray(self.app.field_194_raw));
}).then(function(locs) {
    self.locations = locs;
    return self;
}).done();

请注意,赋值现在也在返回某些内容的函数中,重要的是self.locations = locs与返回self的函数相同。这可能会或可能不会解决您的问题,尽管它有希望 [原文如此]。

对于记录,getPromiseArray()还应简化如下:

function getPromiseArray (locArray) {
    return locArray.map(function(loc) {
        return dao.getRecord("object_22", loc.id);
    });
};

答案 1 :(得分:0)

事实证明答案很简单,它的全部内容都是关于返回类型以及如何设置promises,这对于Q来说就是传播,在这里讨论:

https://github.com/kriskowal/q

引用:

var outputPromise = getInputPromise()
  .then(function (input) {
    }, function (reason) {
  });
  

如果在处理程序中返回一个值,则将完成outputPromise。

     

如果在处理程序中抛出异常,则会得到outputPromise   拒绝。

     

如果在处理程序中返回一个promise,则outputPromise将“变为”那个   诺言。能够成为新的承诺对于管理是有用的   延迟,结合结果或从错误中恢复。

以上是返回值或Promise的情况。关键是这个期待的来电者是什么?就我而言,它期待一个价值。当使用像这样的承诺(第一种情况)时,这是有效的:

return dao.getRecords(APP_COLLECTION, filters).then(function(data) {
    self.loadClientAppImpl(data);
}).then(function() {
    locArray = self.app.field_194_raw;
    return dao.getChildren("object_23", self.appId, "field_210", "field_164").then(function(knackRecord) {
        self.priorCarriers = knackRecord.records;
    });
}).then(function() {
    var locPromiseArray = getPromiseArray(locArray);
    return locPromiseArray[0].then(function(locs){
        self.locations = [locs];
    });
}).then(function() {
    return self;
}).done();

'self'最终被返回,并且调用者很高兴,因为这是它所期望的,一个值。但是,使用以下代码(来自原始问题),不返回值,而是返回承诺(第二种情况):

return dao.getRecords(APP_COLLECTION, filters).then(function(data) {
    return self.loadClientAppImpl(data);
}).then(function() {
    locArray = self.app.field_194_raw;
    return dao.getChildren("object_23", self.appId, "field_210", "field_164").then(function(knackRecord) {
        self.priorCarriers = knackRecord.records;
    });
}).then(function() {
    var locPromiseArray = getPromisesArray(locArray);
    return Q.all(locPromiseArray).then(function(locs){
        self.locations = locs;
    });
}).then(function() {
    return self;
}).done();

即。当使用Q.all时,你得到一个需要解决的承诺,而在第一种情况下,返回self(一个值)。

我现在已经大大清理并优化了代码,但我希望为其他人关闭循环,以防它们可能有所帮助。

顺便说一句 - 从调用代码中可以轻松解决这种情况,Q提供了一种“何时”的方法,以便在您不确定是否收回Promise或值时使用
return Q.when(valueOrPromise, function (value) {
}, function (error) {
});

我最终将这个用于测试这两种情况,并且可以看到'valueOrPromise'变量填充了值(第一种情况)或Promise(第二种情况)。

感谢所有为此做出贡献的人 - 欢呼!