node.js - 从回调中捕获异常

标签 node.js mongodb

我正在使用native MongoDB driver for Node.js我正在尝试找到一种方法来捕获 API 回调中可能发生的异常。

我知道最佳实践是将代码包装在 try-catch block 中,但在我的特定情况下,我向用户公开驱动程序的 API,因此我没有那种级别的控制权。尽管如此,我仍然需要捕获回调中发生的潜在异常,以便发回相关的错误消息。

编辑:进一步解释。 想象一些“后端即服务”,用户可以在 Node.js 中创建在服务器上运行的 JS 代码。用户代码可以直接访问 db 对象(从驱动程序),并且可以对其执行任何操作,例如编写以下内容:

db.collection('test').findOne({ field: 'value' }, function(err, doc){
  throw new Error;
});

我需要以某种方式捕获它,但是 process.on('uncaughtException') 对我来说级别太低了。该用户代码是从 API 请求执行的,因此我想在其响应中返回相关错误消息。

到目前为止,我已尝试向 db 对象添加错误处理程序 (.on('error')),但它没有捕获任何内容。任何帮助将不胜感激。

谢谢!

最佳答案

来自 MongoDB 驱动程序 API 的任何错误都会作为第一个参数传递给回调。将调用包装在 try/catch 中不会对您有帮助,因为错误是异步发生的。换句话说,您对 MongoDB API 的所有调用所做的就是开始异步操作,传入一个回调,以便稍后在异步操作完成(您的数据库调用返回)时调用。如果在异步操作期间发生错误,您将无法使用 try/catch 捕获它。只有库本身才能捕获这些错误,这就是为什么库确保将它们作为第一个参数传递给您的回调。

collection.update({ a : 2 }, { $set: { b : 1 } }, function(err, result) {
  if (err) { /* do error handling */ return; }
  /* err is null, continue as normal */
});

如果我编写自己的 API 来封装其中一些调用,我会采用三种方式之一。

  1. 如果我公开的 API 是回调式 API,就像 MongoDB 驱动程序一样,那么我会这样做。

    exports.coolFunction = function (callback) {
      collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
        if (err) { callback(err); return; }
        callback(null, result);
    };
    

    然后有人可以像这样使用我的 API:

    var alexLib = require('alexLibExample');
    alexLib.coolFunction(function (err, result) {
      if (err) { /* consumer handles error how they want to in their app */ }
      /* all is good, no errors, continue normally */
    });
    
  2. 或者我可以使我的 API 成为启用 Promise 的 API。

    var Promise = require('bluebird');
    exports.coolFunction = function () {
      return new Promise(function (resolve, reject) {
        collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
          if (err) { reject(err); return; }
          resolve(result);
        });
      };
    };
    

    然后有人可以像这样使用我的启用了 Promise 的 API:

    var alexLib = require('alexLibExample');
    alexLib.coolFunction().then(function (result) {
      /* do stuff with result */
    }).catch(function (err) {
      /* handle error how user chooses in their app */
    });
    
  3. 或者我可以将错误作为错误事件发出,这似乎更符合您的需求。

    var EventEmitter = require('events').EventEmitter;
    exports.eventEmitter = new EventEmitter();
    exports.coolFunction = function (callback) {
      collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
        if (err) { exports.eventEmitter.emit('error', err); return; }
        callback(result);
      });
    };
    

    然后有人可以像这样使用我的事件式 API:

    var alexLib = require('alexLibExample');
    alexLib.eventEmitter.on('error', function (err) {
      /* user handles error how they choose */
    });
    alexLib.coolFunction(function (result) {
      /* do stuff with result */
    });
    

    API的事件风格通常与回调风格相结合。这意味着它们仍然将错误传递给回调函数,这是大多数用户在传递回调时所期望的。然后,它们还发出一个错误事件,作为用户可以订阅的一种全局错误处理程序。我知道就是这样Mongoose作品。我可以捕获各个 API 调用的错误,也可以设置错误事件处理程序并处理其中的所有错误。

    var EventEmitter = require('events').EventEmitter;
    exports.eventEmitter = new EventEmitter();
    exports.coolFunction = function (callback) {
      collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
        if (err) { exports.eventEmitter.emit('error', err); callback(err); return; }
        callback(null, result);
      });
    };
    

    然后用户可以灵活地处理错误。

    var alexLib = require('alexLibExample');
    alexLib.eventEmitter.on('error', function (err) {
      /* handle all errors here */
    });
    alexLib.coolFunction(function (err, result) {
      if (err) { return; }
      /* do stuff with result */
    });
    alexLib.coolFunction2(function (err, result) {
      if (err) { /* maybe I have special error handling for this specific call. I can do that here */ }
      /* do stuff with result */
    });
    

如果您真的想要变得更花哨,您可以结合所有三种风格。

var EventEmitter = require('events').EventEmitter;
var Promise = require('bluebird');
exports.eventEmitter = new EventEmitter();
exports.coolFunction = function (callback) {
  return new Promise(function (resolve, reject) {
    collection.update({ a : 2 }, { $set: { b : 1 } }, function(err, result) {
      if (err) {
        if (callback) { callback(err); }
        reject(err);
        exports.eventEmitter.emit('error', err);
      }
      if (callback) { callback(err, result); }
      resolve(result);
    });
  });
};

然后有人可以按照他们的选择使用我的 API。

var alexLib = require('alexLibExample');
alexLib.eventEmitter.on('error', function (err) {
  /* handle all errors here */
});
alexLib.coolFunction(function (err, result) {
  if (err) {
    /* handle this specific error how user chooses */
  }
  /* do stuff with result */
});

// or

alexLib.coolFunction().then(function (result) {
  /* do stuff with result */
}).catch(function (err) {
  /* handle any errors in this promise chain */
});

关于node.js - 从回调中捕获异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27843645/

相关文章:

node.js - NODE_PATH 无效

node.js - 使用 mongoose .exec 有什么好处?

html - 如何在nodeJS中获取多个图像?

node.js - 在 Node 中对 mongodb 客户端 findOne() 进行排序

node.js - MongoDB 从 $filter 返回一个对象

node.js - 如何在带有域的 Node 中进行正确的错误处理?

javascript - 延迟 Promise.all 序列

c# - 如何通过一次调用使用 mongodb C# 驱动程序添加嵌套元素或更新属性

java - 使用java从sqlserver将大数据导出到CSV

java - 将查询 mongo 转换为 spring Mongooperations