javascript - 在无效函数输入时返回未定义或抛出错误?

标签 javascript node.js error-handling javascript-framework

我知道这是重复的,但这里的答案根本不让我满意:

JS library best practice: Return undefined or throw error on bad function input?

我想谈谈一些已被指出的事情以及我仍不清楚的事情。

首先,我想举一个例子,我个人宁愿抛出一个错误然后返回未定义的。

function sum(a, b)

假设消费者传递了一个字符串,因为他传递了一个输​​入框的直接值,而最终用户输入的不是数字。

如果我作为 sum 的作者在字符串输入时返回了 undefined,那么即使开发人员在某个时候输入了一个字符串,也不会发生任何事情,他也不会在意,就像那样什么是可以预期的。但在这种情况下,如果我抛出一个错误,开发人员会意识到这实际上是一个必须处理的边缘情况,因为毕竟,没有人希望他们的程序出现错误。

那么基本上,为什么不通过实际抛出错误让开发人员了解边缘情况呢?

这是对上面提到的问题的评论,这几乎正是我要问的,但还没有人回答:

"But since it takes 1 extra min for me to throw an error instead of dying silently, won't that save hours in debugging time for those who didn't take the time to read the docs?"

上面接受的答案中的另一点:

"Catching an exception is a lot slower than testing a return value so if an error is a common occurrence, then exceptions will be a lot slower."

我能想到的唯一适用于此 qoute 的情况是 I/O 或网络内容,其中输入始终采用正确的格式,但例如不存在具有该 ID 的用户。

在这种情况下,我理解为什么抛出错误会减慢进程。但同样,一个仅由纯同步函数组成的数学库又如何呢?

检查输入而不是检查输出不是更聪明吗? (确保输入有效,而不是运行函数并检查是否返回 undefined)

我的很多困惑实际上源于类型检查,因为我确实来自 C# 世界,并且认为库应该按照预期的方式使用,而不是仁慈地工作。

最佳答案

我认为对于 OO 语言来说,返回 null 是很常见的,尽管这是不好的做法,null 的发明者将其称为 billion dollar mistake .

函数式语言甚至在 OO 出现之前就通过 Maybe 类型解决了这个问题。

在编写函数时,您可以使用包含成功或失败的 Maybe 变体,Scott Wlaschin 将其称为 railway orientated programming而 Promises 是一种面向铁路的编程。

在 OO 中使用 Maybe 的问题是你没有 union types .在 F# 中,您的代码将如下所示:

let x = 
  // 9/0 throws so divideBy returns None the caller of divideBy can
  //decide what to do this this.
  match (divideBy 9 0) with
  | Some result -> //process result
  | None -> //handle this case

在 F# 中匹配某些内容时,如果您忘记了大小写(未处理 None),则会出现编译时 错误。在 OO 中,您不会,并且会遇到运行时错误或悄悄失败。当您尝试访问可空类型时,C# 中的改进可能会伴随编译器警告您,但这只会处理 if not null,它不会强制您提供 else。

所以在 JavaScript 中,我会建议使用 Promises 或返回结果对象。 Promises 原生于现代浏览器和 nodejs。在浏览器中,当您不处理失败的 promise 时,它会在控制台中对您大喊大叫(控制台中的错误和源代码中未捕获的拒绝中断)。将来;对于 Node ;它会导致您的进程像未处理的异常一样停止。

//example with promises
const processNumber = compose([
  //assuming divideBy returns a promise that is rejected when dividing by zero
  divideBy(9)
  ,plus(1)
  ,minus(2)
  ,toString
])
// 9/0 returns rejected promise so plus,minus and toString are never executed
processNumber(0) 
.then(
  success => //do something with the success value
  ,fail => //do something with the failure
);

//example of result type:
const Success = {}
,Failure = {}
,result = (type) => (value) => 
  (type === Failure)
    //Failure type should throw when trying to get a value out of it
    ? Object.create({type:type,error:value}, {
      value: {
        configurable: false,
        get: function() { 
          throw "Cannot get value from Failure type"
        }
      }
    })
    : ({
      type:type
      ,value:value    
    })
;
//convert a function (T->T) to (result T->result T)
const lift = fn => arg => {
  //do not call funcion if argument is of type Failure
  if(arg.type === Failure){
    return arg;
  }
  try {
    const r = fn(arg.value);
    //return a success result
    return result(Success)(r);
  } catch (e) {
    //return a failure result
    return result(Failure)(e);
  }
};
//takes a result and returns a result
const processNumber = compose(
  [
    //assuming divideBy throws error when dividing by zero
    divideBy(9)
    ,plus(1)
    ,minus(2)
    ,toString
  ].map( //lift (T->T) to (result T -> result T)
    x => lift(x)
  )
);

const r = processNumber(result(Success)(0));//returns result of type Failure
if(r.type === Failure){
  //handle failure
} else {
  //handle r.value
}

您可以只返回 null 或抛出,但越来越多的 OO 人开始意识到那是 not the best way处理事情。抛出是一种副作用,因此会使函数变得不纯(函数越不纯,维护代码就越难)。

Null 不是反射(reflect)可能失败的函数的好类型。您不知道为什么它未能返回预期的类型,现在必须对原因做出假设,在代码中做出假设会使您的代码更难维护。

关于javascript - 在无效函数输入时返回未定义或抛出错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47296984/

相关文章:

c# - 无效的ID应该抛出什么异常?

javascript - 如何获取具有相同类名的span元素名称

node.js - Mocha 和 JSOver

node.js - Req.session undefined with express 4 and Redis store, express-session

Node.js 反向代理/负载均衡器

javascript - 语法错误: missing ) after argument list in google script while i was creating event from GoogleAppsScript to Google Calendar

error-handling - Camel : defer ActiveMQ messages until error condition gets resolved

javascript - Mongoose $in 运算符仅更新一个文档

javascript - 滑入/滑出菜单问题

javascript - 如何用视频填充屏幕?