返回promise链中的引用数据

时间:2017-06-23 17:38:46

标签: javascript mongoose promise

说我需要找一些学生:

var promise = Student.find({..}).exec();

然后我需要访问单独引用它们的文档并将它们嵌入返回:

promise.then(function(students) {
  var promises = [];
  students.forEach(function(student) {
    var groupPromise = Group.find({ studentRef: student._id }).exec();
    groupPromise.then(function(group) {
      ...
      student.embed = group;
      return student;
    });
    promises.push(groupPromise);
  });
  return Promise.all(promises);
}).then(function(result) {
   // expect result to be array of students, with { embed: group }
   // instead result is array of groups
});

我在搞清楚承诺方面走了很长的路,但我错过了一些东西。我希望groupPromise.then(...)能够在Promise.all(...)被评估之前执行。由于情况显然不是这样,我需要一种方法来确保每个student都嵌入了正确的group

3 个答案:

答案 0 :(得分:2)

您放入数组并传递给Promise.all()的承诺需要是groupPromise.then()返回的结果,而不是groupPromise本身。由于您使用的是groupPromise,因此您无法看到groupPromise.then()的结果。

请记住,每个.then()都会返回一个承诺,并且它会跟踪跟踪.then()结果的新承诺。您没有将新承诺传递给Promise.all(),因此您的结果未显示.then()内发生的结果。

更改为:

promise.then(function(students) {
  var promises = [];
  students.forEach(function(student) {
    var p = Group.find({ studentRef: student._id }).exec().then(function(group) {
      ...
      student.embed = group;
      return student;
    });
    promises.push(p);
  });
  return Promise.all(promises);
}).then(function(result) {
   // result is array of students, with { embed: group }
});

仅供参考,使用.map()代替.forEach()时,这会更加精简:

promise.then(function(students) {
    return Promise.all(students.map(function(student) {
        return Group.find({ studentRef: student._id }).exec().then(function(group) {
            ...
            student.embed = group;
            return student;
        });
    }));
}).then(function(result) {
   // result is array of students, with { embed: group }
});

而且,使用Bluebird's promise library中的Promise.map()更简单一点:

promise.then(function(students) {
    return Promise.map(students, function(student) {
        return Group.find({ studentRef: student._id }).exec().then(function(group) {
            ...
            student.embed = group;
            return student;
        });
    });
}).then(function(result) {
   // result is array of students, with { embed: group }
});    

答案 1 :(得分:1)

基本上只有一件事是错的:

groupPromise.then(function(group) {
  ...
  student.embed = group;
  return student;
})
.then(function(student){
  //this is what you want
});

groupPromise.then(function(group){
  //this is what you do
});

groupPromise始终解析为<​​em>组。可以将groupPromise.then Promise解析为学生的Promise.all:

promises.push(groupPromise.then(function(group) {
  ...
  student.embed = group;
  return student;
}));

我将如何做到这一切:

promise.then(function(students) {
    return Promise.all(students.map(function(student) {
        return Group.find({ studentRef: student._id }).exec().then(function(group) {
            ...
            student.embed = group;
            return student;
        });
    }));
}).then(function(result) {
// expect result to be array of students, with { embed: group }
});

答案 2 :(得分:0)

我发现从变量声明中移除promise是有效的:

var promise = Student.find({..}).exec();
promise.then(function(students) {
  var promises = [];
  students.forEach(function(student) {
    promises.push(
      Group.find({ studentRef: student._id }).exec()
        .then(function(group) {
          ...
          student.embed = group;
          return student;
        })
    );
  });
  return Promise.all(promises);
}).then(function(result) {
  // now results is an array of students with { embed: group }}       
});

我必须承认,我不知道它为什么会起作用。任何人吗?

编辑:找到解决方案。 正如你聪明的人所指出的,重要的是承诺的部分归还。推入promises数组的承诺需要是.then()返回的承诺。这些方法实际上只是一种语法上的类比,但我认为它们可能会为未来的读者提供启发。

方法一 - 完全推送promise.then():

var promises = [];
students.forEach(function(student) {
  promises.push(Group.find().exec().then(function(group) {
     student.embed
     return student;
  });
});
return Promise.all(promises); 

不是特别漂亮。

方法二 - 将promise.then()分配给另一个变量:

var promises = [];
students.forEach(function(student) {
  var groupPromise = Group.find().exec();
  var embedPromise = groupPromise.then(function(group) {
     student.embed
     return student;
  });
  promises.push(embedPromise);
});
return Promise.all(promises);

比方法一更漂亮,但它实际上并不容易阅读。

方法三 - 正如jfriend00和Jonas w所建议的,.map()很优雅:

promise.then(function(students) {
  return Promise.all(students.map(function(student) {
    return Group.find({ studentRef: student._id }).exec().then(function(group) {
      ...
      student.embed = group;
      return student;
    });
  }));
}).then(function(result) {
  // expect result to be array of students, with { embed: group }
});