嵌套 Promise 不会将错误传播到 Node.js 中的父 Promise?

Posted

技术标签:

【中文标题】嵌套 Promise 不会将错误传播到 Node.js 中的父 Promise?【英文标题】:Nested Promise is not propagating error to parent Promise in Node.js? 【发布时间】:2017-11-10 15:09:39 【问题描述】:

我正在使用运行 Express 的 Node.js/TypeScript 创建一个 API。以下是我的 get 方法的摘录。在 format 方法中触发了一个错误,它抛出了一个错误,该错误被 Promise 捕获,但在 throw 后没有传播到父 Promise:

            this.getModel(objectName).findAll(queryParameters).then(function(databaseObjects) 
                for (let databaseObject of databaseObjects) 
                    var jsonObject = ;
                    //console.log("Database object: ");
                    //console.log(databaseObject);
                    transform.baseFormat(databaseObject, jsonObject)
                    .then(() => transform.format(databaseObject, jsonObject))
                    .then(() => 
                        res.locals.retval.addData(jsonObject);
                    ).catch((e) => 
                        console.log("Caught error during format of existing object: ");
                        console.log(e);
                        throw e;
                    );
                
            )
            .then(() => 
                if (metadata) 
                    this.metadata(objectName, false, transform, res.locals.retval);

                    delete queryParameters.limit;
                    delete queryParameters.offset;
                    console.log("RUNNING METADATA COUNT: ");
                    this.getModel(objectName).count(queryParameters).then(function(count) 
                        res.locals.retval.setMetadata("records", count);
                        return next();
                    ).catch(function(e) 
                        this.error(e, res);
                        return next();
                    );
                 else 
                    console.log("NO METADATA");
                    return next();
                
            )
            .catch((e) => 
                // TODO: Move status into error() function
                console.log("500 Error on GET");
                console.error(e);
                res.locals.retval.addError(ErrorCode.InternalError, e);
                res.status(ErrorCode.InternalError).send(res.locals.retval);
                return next();
            );

这是输出:

(node:8277) Warning: a promise was created in a handler at /Library/WebServer/adstudio/dist/server.js:555:51 but was not returned from it, see
at Function.Promise.bind (/Library/WebServer/adstudio/node_modules/bluebird/js/release/bind.js:65:20)
Caught error during format of existing object: 
Test Error
END FUNCTION HAS BEEN REACHED!

然后请求无法完成。

我已经阅读了很多关于 Promises 的内容,但我无法找到与我类似的问题/解决方案。

http://bluebirdjs.com/docs/warning-explanations.html http://taoofcode.net/promise-anti-patterns/ https://www.reddit.com/r/javascript/comments/4bj6sm/am_i_wrong_to_be_annoyed_with_promise_error/ https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html Chained promises not passing on rejection http://wiki.commonjs.org/wiki/Promises/A https://promisesaplus.com/

【问题讨论】:

你总是需要 return 来自then 回调的内部承诺,否则它不可能被等待(或者它的拒绝被传播)。 【参考方案1】:

在该 for 循环中运行不是异步的,因此您的承诺基本上会在循环完成后立即解决,但在所有格式化完成之前。

使用承诺控制流,例如 bluebird 的 Promise.each,它是串行的或只是 Promise.all。然后将捕获任何异常。

this.getModel(objectName).findAll(queryParameters).then(function (databaseObjects) 
  var promises = databaseObjects.map(databaseObject => 
    var jsonObject = 
          // console.log("Database object: ");
          // console.log(databaseObject);
    return transform.baseFormat(databaseObject, jsonObject)
          .then(() => transform.format(databaseObject, jsonObject))
          .then(() => 
            res.locals.retval.addData(jsonObject)
          ).catch((e) => 
            console.log('Caught error during format of existing object: ')
            console.log(e)
            throw e
          )
  )
  return Promise.all(promises)
)
.catch((e) => 
    // TODO: Move status into error() function
  console.log('500 Error on GET')
  console.error(e)
  res.locals.retval.addError(ErrorCode.InternalError, e)
  res.status(ErrorCode.InternalError).send(res.locals.retval)
  return next()
)

【讨论】:

啊,我在 Express 中的 POST 命令上使用了Promise.all,但使用逆逻辑为请求承诺中的每个对象创建承诺,然后使用@987654325 异步处理它们@。不应该肯定结果。 哦,我记得我没有偏离循环的原因;因为有时结果是依赖于顺序的,我担心Promise.all 会破坏从数据库返回的对象的顺序。看起来这不是问题。

以上是关于嵌套 Promise 不会将错误传播到 Node.js 中的父 Promise?的主要内容,如果未能解决你的问题,请参考以下文章

在 Angular 4 中,为啥异步验证的嵌套控件不会将其有效性传播到父 FormGroup?

将嵌套循环查询组合到父数组结果 - pg-promise

蓝鸟嵌套承诺与每个/传播

在 Node 中正确批处理嵌套的 Promise

深入浅出:promise的各种用法

为啥这个简单的 Node, Sequelize Promise 代码会挂起?