在 node.js 中引发错误

Posted

技术标签:

【中文标题】在 node.js 中引发错误【英文标题】:Throwing an error in node.js 【发布时间】:2016-01-10 05:37:48 【问题描述】:

我有一个小模块,可以作为我的数据模型。它位于我的路线和特定数据(在我的情况下为用户数据)的数据库之间。

我在我的路由代码中需要这个模块,调用它拥有的subscribe 方法,并通过将所需数据存储在我的数据库中来为用户订阅特定的邮件列表。耶!

我的“订阅”方法接受电子邮件和电子邮件列表 ID 作为两个参数。我将草率而快速地编写代码并为不存在的列表放入一个 id 是合理的。拼写错误,你说吧。

如何抛出错误并指向具有不正确 id 的行号?

model/user.js 内部的代码:

if (emailLists.indexOf(listId) === -1) 
  throw new Error('listId does not exist');

route.js 内部的代码:

user.subscribe('fake@email.com', 'knewsletterr', function (error, success) 
  if (error)  return sendResponse(500, 'Ahhhhhhh!'); 
  if (!error)  return sendResponse(200, 'subscribed'); 
);

现在,我得到:

/home/.../project/models/user.js:85
if (emailLists.indexOf(listId) === -1)  throw new Error('listId does not exist'); 
                                                   ^
Error: listId does not exist

【问题讨论】:

你的源代码中没有定义listId变量 哈哈,我知道了。我是那个抛出错误的人。我只想知道如何将适当的行号和文件名与错误一起抛出。 var e = new Error("asdf"); console.log(e.stack) 【参考方案1】:

如果您使用节点样式的回调,convention 与throw 相比不是。而是将错误作为第一个参数传递给回调 -

// divide with callback
function div (x, y, done) 
  if (y === 0)
    return done (Error ('Cannot divide by zero'))
  else
    return done (null, x / y)


div (6, 3, function (err, result) 
  // *always* check for err
  if (err)
    console.log ('error', err.message, err.stack)
  else
    console.log ('result', result)
)

使用回调是一种愚蠢的函数,因为它可以以纯同步方式编写,但希望这能说明这种模式


您的函数可能已经以同步方式编写了 - 不用担心,我们可以使用下面的 cps2 将其转换为节点样式的回调函数 -

// a "normal" synchronous function that throws an error
const div = (x, y) =>
 if (y === 0)
    throw Error ('cannot divide by zero')
  else
    return x / y

  
// convert it to a continuation passing style (cps) function
const cps2 = (f, x, y, k) =>
 try
   return k (null, f (x, y)) 
  catch (err)
   return k (err) 


// logging utility for demos below
const logger = (err, result) =>
 if (err)
    console.log ('error:', err.message, err.stack)
  else
    console.log ('result:', result)

  
cps2 (div, 6, 3, logger)
// result: 2

cps2 (div, 6, 0, logger)
// error: cannot divide by zero

综上所述,现在大多数人都在使用 Promise。下面我们演示如何将节点样式的回调函数转换为返回 Promise 的回调函数。注意,node 提供此功能为util.promisify,虽然我在这里实现它是为了演示目的 -

// a conventional function with a node-style callback
const div = (x, y, done) =>
 if (y === 0)
    return done (Error ('cannot divide by zero'))
  else
    return done (null, x / y)


// convert a node-style callback function to a promise-returning function
const promisify = f => (...args) =>
  new Promise
    ( (resolve, reject) =>
        f ( ...args
          , (err, result) =>
              err
                ? reject (err)
                : resolve (result)
          )
    )

// logging utility for demos below
const logger = p =>
  p .then (console.log, console.error)
  
logger (promisify (div) (6, 3))
// 2

logger (promisify (div) (6, 0))
// Error: cannot divide by zero

Continuations 只是函数,所以你可以用任何你喜欢的方式编写这种东西——不要认为你必须使用节点样式的“回调”或 Promise,因为这是你见过的唯一方式-

const cont = (...values) =>
  k => k (...values)

const div = (x, y) =>
  y === 0
    ? cont (Error ('cannot divide by zero'))
    : cont (null, x / y)

const logger = (err, result) =>
  err
    ? console .log ('error:', err.message)
    : console .log ('result:', result)

div (6, 3) (logger)
// result: 2

div (6, 0) (logger)
// error: cannot divide by zero

【讨论】:

谢谢,这很有帮助!这是我采用的第一种方法,但我会根据您订阅某人时发生的情况做三件不同的事情(“已经订阅”、“成功”、“其他错误”),因此从概念上区分事物是很棘手的。也许我应该像应用程序不会运行错误一样处理错误,并将其他所有内容的结果作为规则处理。 一般来说throw是一种同步处理错误的方法。使用回调时,假设您正在处理 throw 不会特别有用的异步代码。这个想法是您不必在链中的每个回调中捕获err。如果你不想在中间处理错误,你可以把它传递给done(err,x);如果errnull,什么都不会发生,但是如果err是一个Error,上面的函数有机会抓住它。 说了这么多,但这并不意味着这是设计异步错误处理的最佳方法。它恰好是节点中的约定,因此它可能是最好的选择如果你正在编写一个其他人最终会使用的应用程序/库。如果您只是为自己编写应用程序,您可以设计您认为最适合您的错误处理方式,并且只需使用与其他库交互的节点约定。 而不是console.log ('error:', err.message, err.stack) 也不建议简单地使用throw err @JoãoPimentelFerreira 约定不是throw,因为你不能异步catch。 Promise 和 async/await 等较新的机制允许使用 throw,但不允许在节点样式的回调中使用。【参考方案2】:

This 会帮助你!

var el = document.getElementById('el');

var log = function( val )
  el.innerhtml+= '<div><pre>' + val + '</pre></div>';
;


try 
  
  throw Error('error in code');
  
 catch (e) 

  log( e.message );
  log( e.fileName );
  log( e.lineNumber );
  log( e.stack );

;
&lt;div id='el'&gt;&lt;/div&gt;

【讨论】:

谢谢,我阅读了 MDN 页面。这是我认为我遇到问题的 node.js 堆栈跟踪。我承认,在这一点上我有点困惑。 所以:joyent.com/developers/node/design/…

以上是关于在 node.js 中引发错误的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 捕获生成后引发的 ENOMEM 错误

在 ES6 Node.js 中导入“.json”扩展会引发错误

Node.js 的设计错误

使 Node.js Redis 客户端的 .multi() 和 .batch() 在结果中返回错误以进行测试

Node.Js执行原理图引发的思考

游戏开发日志升级node.js依赖包引发的BUG