NodeJS未处理的承诺拒绝

时间:2017-10-19 21:03:20

标签: javascript node.js google-app-engine

我有一个方法getModel(kind),它返回NodeJS中的数据存储区数据模型。

我在getModel(kind)方法中创建了一个简单的类型-o,并发现了一个未被捕获的拒绝承诺的潜在问题。

如何在将来更新代码以捕获这些未捕获的异常?

调用getModel:

//Save the data to the database
getModel('transferrequest').create(TransferRequestNew, (err, savedData) => {
  if (err) {
  console.log('Transfer Request New unable to create new entity. Error message: ', err);
    next(err);
    return;
  }
  console.log('savedData: ', savedData);
  res.redirect(`${req.baseUrl}/history`);
});

getModel函数:

function getModel(kind) {
  const model = __modelsdir+'/model-'+__databackend+kind;

  return require(model);
}

使用getModel.create调用创建方法:

function create (data, cb) {
  update(null, data, cb);
}

未处理错误:

  

(node:31937)UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝ID:1):错误:找不到模块'/ mypath / projectname / models / model-datastoretransferrequest'

2 个答案:

答案 0 :(得分:3)

首先,我会说动态require是一种让自己陷入困境的方法。让我将我的答案分为两部分,重点说明应该避免的原因并提出一些解决方案。

潜在问题

  1. 运行时的同步加载

    require是一个同步操作,众所周知,这些操作会阻止事件循环。想象一下,相对大量的用户同时使用您的应用程序,并且环路延迟超过合理值或者至少会导致性能问题。

  2. 难以测试此类动态模块

    如果没有适当的测试覆盖率,您如何保证您的应用程序足够稳定?对于动态需求,它变成了一项非常重要的任务。这导致另一个问题 - 你真的有这么多的数据模型需要动态创建和加载吗?如果没有,您可以使用定义明确且明确要求的数据模型使您的工作更加舒适,而不是“神奇”加载容易出错。而且,不要忘记循环依赖和其他可怕的可憎行为,在进口时刻之前它们将一直保持沉默。

  3. 此类应用程序的总体设计

    值得在global-require上阅读ESLint topic,并了解为什么默认情况下不允许在各种规则集中使用它(例如Airbnb)。但你实际上自己提到过:

      

    我在getModel(kind)方法中创建了一个简单的类型o并且发现了一个   未被捕的承诺拒绝的潜在问题。

    如果这足以打破您的应用程序,那么这个应用程序是否可以被认为是健壮的?它与raw strings作为参数是一样的:一个应该使它们成为常量或者作为函数本身出现,摆脱难以调试的运行时错误,以换取启动时的简单语法错误。

    < / LI>

    可能的解决方案

    明确要求的模型

    创建明确定义的对象结构,表示数据结构并从一个聚合的index.js文件中显式加载它们:

    // models/transfer-request.js
    class TransferRequest {
      create(instance, cb) {
        // Implementation...
      }
    }
    
    module.exports = TransferRequest;
    
    // models/index.js
    const TransferRequest = require('./transfer-request.js');
    // Other models requires...
    
    module.exports = {
      TransferRequest,
      // Other models exports...
    };
    

    使用Factory 创建实例:

    如果您仍想坚持使用与现在类似的东西,请使用标准模式创建模型工厂:

    class ModelFactory {
      constructor(model){
        switch(model) {
          case 'transferrequest':
            // Implementation of TransferRequest object creation...
          break;
    
          case 'othertransferrequest':
            // Implementation of OtherTransferRequest object creation...
          break;
    
          default:
            throw new Error('Unknown class');
        }
      }
    }
    

    以清晰可见的方式创建实际模型对象的时间和次数,在代码中定义明确,而不是通过动态加载来模糊可能的选项。

    是的,如果您仍希望在运行时require,请使用try/catch来处理拒绝。

答案 1 :(得分:0)

这只是解决方法的一个小方法,但可能有一些更好的方法。为什么不尝试 - 捕获require语句?我测试了这个,这很好用:

function getModel(kind, cb) {

  var model = __dirname + kind;
  try {
    var requiredModel = require(model);
    return cb(null, requiredModel)
  }
  catch (e) {
    return cb(new Error("model not found!"), null);
  }
}

我已经使用__dirname对此进行了测试,但这不会产生任何影响。

顺便说一句:这不会显示最佳实践错误处理,只是在我的咖啡休息时写下来。