猫鼬承诺永远不会到达 .then()

Posted

技术标签:

【中文标题】猫鼬承诺永远不会到达 .then()【英文标题】:Mongoose promise never gets to .then() 【发布时间】:2021-03-04 15:36:23 【问题描述】:

我正在使用 q 并且我有多个 mongoose .exec() 承诺永远不会到达代码的 .then() 部分,所以永远不要让 q 解决。无法弄清楚为什么它永远不会回来。

    var defer = q.defer();
    var promises = [];
    console.log('Exams:', exams.length);
    for (var e=0; e<exams.length; e++) 
      console.log('Exams:', exams[e]._id);
      var newPromise = Pupilexam.find( _exam: exams[e]._id ).populate('_user').exec()
        .then((pupils) => 
          console.log("Adding pupils", exams[e]._id);
          exams[e].pupils = pupils;
          resolve(exams[e]);
        )
        .catch((err) => 
          reject(err);
        );
      console.log(typeof newPromise);
      promises.push(newPromise);
      console.log("Promised pushed");
    
    q.all(promises).then(function(data)
        console.log("q'd all");
        defer.resolve(res.status(200).json(exams));
    );
    return defer;

Pupilexam.find().exec() 永远不会到达 .then(),因此承诺永远不会解决,而延迟永远不会解决。为什么猫鼬会找不到.then()?我错过了什么?

*** 更新 ***

即使使用内置的 Promise,我们也会遇到同样的问题。 Pupilexams.find() 电话永远不会回来。

    var promises = [];
    for (var e=0; e<exams.length; e++) 
      console.log('e:', e);
      console.log('Exam', exams[e]._id);
      var newPromise = Pupilexam.find( _exam: exams[e]._id ).populate('_user').exec()
        .then((pupils) => 
          console.log("Adding pupils", exams[e]._id);
          exams[e].pupils = pupils;
        )
        .catch(handleError(res));
      promises.push(newPromise);
    
    Promise.all(promises).then((exams) => 
      console.log(values);
      res.status(200).json(exams)
    );

使用这种方法,我在调用 UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client 时也会收到标题错误

** 需要额外的代码 **

function handleError(res, statusCode) 
    statusCode = statusCode || 500;
    return function(err) 
      console.log(err.message);
      res.status(statusCode).send(err);
    ; 

【问题讨论】:

请问使用q-promises 有什么特别的原因吗? Promise.all 通过本机承诺开箱即用地支持。 避免使用deferred antipattern (q.defer()) 和Promise constructor antipattern (resolve(exams[e]);, reject(err);)! 你的逻辑不对。如果了解您有一系列考试。您希望每次考试都将学生的数据添加到考试对象中。每个考试数组都是一个对象数组,您可以添加到每个对象属性,包括学生的信息。如果您需要处理来自 mongo 的错误,请再次调用它。在与学生信息进行考试之后。没有你的逻辑。另外如果你只是从mongo读取数据,推荐使用lean函数, @eol 习惯。我在别处用过。但是当我使用 promises.all 时,我遇到了同样的问题。循环中的猫鼬调用永远不会返回并运行.then() 代码。 @Bergi 我已经更新了 promises.all 以避免,但遇到同样的问题。 【参考方案1】:

从你的代码看。

    //(async) function
    for (var e of exams) 
        try 
         const pupils = await  Pupilexam.find( _exam: exams[e]._id 
                ).populate('_user').exec().lean()
          e.pupils = pupils
             
        catch((err)
          //handleError
        ;
    
res.status(200).json(data: exams)
    

也许这会告诉你你错了多少匹配

【讨论】:

我不相信这会奏效。 api 将在所有 mongoose 调用返回并填充考试之前返回,所以我不会得到我想要的数据。 你知道然后网站加入 => join.me/remote-work。我想证明自己。什么时候可以?【参考方案2】:

看起来答案是,在这两行中,exams[e] 不在范围内,因为当承诺返回时,循环已经继续,所以 e 是错误的并且变得太高,所以它是错误的。

      console.log("Adding pupils", exams[e]._id);
      exams[e].pupils = pupils;

当我阅读@eol关于捕获的消息并决定正确捕获并输出时才发现。

【讨论】:

这无关紧要,不过我答对了。 问题是循环在promise返回之前改变了e的值,所以和数组中的相关考试不同步,导致了问题。【参考方案3】:

我猜你确实在返回你的承诺,但你返回的是一个空的 json。 您的方法有两个问题:

    你没有从你那里回来:应该返回学生并且它正在返回未定义

    您正在记录我不知道它是什么的值

     .then((pupils) => 
       console.log("Adding pupils", exams[e]._id);
       exams[e].pupils = pupils; 
       // you should return something // return pupils
     )
     promises.push(newPromise);             
    
     Promise.all(promises).then((exams) => 
     // ['undefined', 'undefined', ...]
           console.log(values);
           res.status(200).json(exams)
         );
    

【讨论】:

我故意不返回任何内容,因为我希望在测试时返回空值,但是是的,我需要一个返回值以供 promise.all 发回。您在寻找哪些价值观? exams 是一个来自 mongo 的对象数组。【参考方案4】:

回答有关Cannot set headers after they are sent to the client 错误的更新问题。看起来您在 handleError 函数中向客户端发送了响应。现在,如果不止一次 Pupilexam.find 调用失败,handleError 将被调用两次,导致上述错误。

您应该将catch-handler 移至Promise.all 调用:

const promises = [];
for (const exam of exams) 
    const newPromise = Pupilexam
        .find( _exam: exam._id ).populate('_user').exec()
        .then((pupils) => 
            exam.pupils = pupils;
        );
    promises.push(newPromise);

Promise.all(promises)
  .then((exams) => 
    res.status(200).json(exams);
   ) 
  .catch(handleError(res));

【讨论】:

以上是关于猫鼬承诺永远不会到达 .then()的主要内容,如果未能解决你的问题,请参考以下文章

猫鼬插入永远不会在单元测试中返回

节点递归承诺永远不会退出

Rxjs 可观察到承诺永远不会在 nodejs 中解决

返回承诺的 Vuex 操作永远不会解析或拒绝

承诺要么永远不会被调用,要么被拒绝(Parse JS SDK)

.then() 函数永远不会为调用区块链而运行