我应该使用console.error()还是throw new Error()?

15

我见过两种情况:

throw new Error(error);

&

console.error(error);

E.G:

jQuery:

                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }

&
Vue.js:

      if (config.warnHandler) {
        config.warnHandler.call(null, msg, vm, trace);
      } else if (hasConsole && (!config.silent)) {
        console.error(("[Vue warn]: " + msg + trace));
      }

两种错误处理方式都看起来可靠且被广泛使用。但我的问题是:

它们之间有什么区别?如果有的话,我应该在什么情况下使用哪一个?

4个回答

12

关键区别:抛出异常会停止执行,而console.error则不会。

大多数情况下,最好抛出一个错误。

这是一种内置的方法来表示某些操作失败了,如果错误没有被预期、捕获和妥善处理,正常的执行将无法继续。

在大多数平台上,未捕获的异常也会被记录到控制台中以警告开发人员,但已捕获的异常不会被记录,因为它们被认为已被代码处理。

在错误发生但不致命的情况下使用console.error可以提醒开发人员。

然而,过度使用此功能很容易导致其他错误和更难调试的代码。例如,请考虑以下代码:

const elem = document.querySelector('.elem')
if(!elem) 
  console.error('elem cannot be found!')
const returnValue = functionThatDoesSomethingWithElem(elem)
if(!returnValue.success) 
  console.error('Doing something with elem has failed!')
if(!returnValue.doSomethingElse()) 
  console.error('Doing something else with elem has failed!')

如果没有elem,上面的代码将会记录三个错误,但是执行仍然会继续,可能会导致更多的错误。通过抛出异常,可以避免这种情况:

const elem = document.querySelector('.elem')
if(!elem) 
  throw new Error('elem cannot be found!')
const returnValue = functionThatDoesSomethingWithElem(elem)
if(!returnValue.success) 
  throw new Error('Doing something with elem has failed!')
if(!returnValue.doSomethingElse()) 
  throw new Error('Doing something else with elem has failed!')

如果您不将其放入 try..catch 结构中,这将仅打印第一个错误消息,并停止执行,例如:

try{
  const elem = document.querySelector('.elem')
  if(!elem) 
    throw new Error('elem cannot be found!')
  const returnValue = functionThatDoesSomethingWithElem(elem)
  if(!returnValue.success) 
    throw new Error('Doing something with elem has failed!')
  if(!returnValue.doSomethingElse()) 
    throw new Error('Doing something else with elem has failed!')
}catch(exception){
  console.error(exception)
  fallbackMethod()
}

另外还有一个不同之处:throw的错误可以被函数的调用者捕捉到,因此可以通过编程方式处理它们(使执行继续,并且不显示错误)。另一方面,如果使用console.error,调用者无法确定错误是否是预期的,这会导致即使错误是正常的,也会记录错误,因此控制台可能变得混乱(您无法确定哪些是真正的错误,哪些不是)。


4
那两个是完全不同的,让我们看一下每个的文档:
console.error:
输出错误消息到Web控制台。
Throw:
抛出用户定义的异常。当前函数的执行将停止(throw之后的语句将不会被执行),并且控制权将传递到调用堆栈中第一个catch块中。如果在调用程序函数中不存在catch块,则程序将终止。
所以,正如你所看到的,它们的工作方式不同,你可以在你的代码中使用两者,所以请记住,只有console打开的用户才能看到消息,而throw将被注意到,因为所有的都将停止。
让我们看一些功能性的例子:
- console.error 请注意,“自定义”错误将显示在控制台上,但代码仍然在执行,您只能在这里看到错误消息,因为控制台正在显示在stackOverflow。要停止执行,需要在console.error之后加上return。

function changeString(currentString, append) {
  if (typeof append != 'string') {
    console.error("Cannot change string!");
  }

  //THIS PART BELOW WILL EXECUTE, even with error logged
  console.log(currentString + append);

}

changeString("I will show up even with error logged ", null)


  • 抛出

需要注意的是当错误被抛出时,代码会停止执行并且错误信息与console.error显示的不同。

function changeString(currentString, append){
  if (typeof append != 'string'){
    throw new Error("Cannot change string!");
  } 
  
  //THIS PART BELOW WONT EXECUTE
  console.log(currentString + append);
  
}

changeString("I wont show up in the console", null)

Here I added a try/catch, note the catch block being executed, this way I have control over the error and what should happen after the error being thrown, also, I mixed both: Throw and console.error

function changeString(currentString, append) {
  try {
    if (typeof append != 'string') {
      throw new Error("Cannot change string!");
    }
    
    console.log(currentString + append);
    
  } catch (er){
    console.error("I'm being logged from inside a catch block because an error was thrown");
    //DO WHATEVER YOU NEED TO FIX THE ERROR AND ALERT THE USER HERE
  }
}

changeString("I wont show up in the console", null)


官方文档进一步阅读:
Throw
console.error


2

我认为它们并不可互换。Console.error()只是以特殊格式将错误记录到控制台。

当你真正抛出一个错误时,你实质上会终止执行,除非你使用try catch块或其他形式的错误处理来捕获该错误。


0
为什么不这样做,两者兼备:
throw new ConsoleError('bad thing');

源代码:

// based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
class ConsoleError extends Error {
  constructor(...args) {
    const returnValue = super(...args);
    console.error(...args);
    // Maintains proper stack trace for where our error was thrown (only available on V8)
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, ConsoleError);
    }

    this.name = 'ConsoleError';
    this.message = args[0];
    // Pass remaining arguments (including vendor specific ones) to parent constructor
    return returnValue;
  }
}
window.ConsoleError = ConsoleError;

你可能也想在出现错误时向用户显示信息,为此可以使用

// this to avoid crashing:
window.toastError('nice user error message', 'extra developer data:', someObject)

// this to crash:
throw new ToastError('we made a mistake')

源代码:

window.toastError = (userMsg, ...developerDebugArgs) => {
  // TODO: implement toast notifications
  // only use userMsg for the toast notification
  // Using DOMPurify and rendering userMsg as (potential) html may be nice,
  // but backend team may prefer to simple return plain text instead of html
  // may need to de-dupe messages being sent to toast component
  console.log(
    `%c${userMsg}`,
    'color: orangered;font-style:italic;',
    ...developerDebugArgs
  );
};

class ToastError extends Error {
  constructor(...args) {
    const returnValue = super(...args);
    window.toastError(...args);
    // Maintains proper stack trace for where our error was thrown (only available on V8)
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, ToastError);
    }

    this.name = 'ToastError';
    this.message = args[0];
    // Pass remaining arguments (including vendor specific ones) to parent constructor
    return returnValue;
  }
}
window.ToastError = ToastError;

如果你喜欢的话,也可以将 ToastError 类重命名为 ToastException


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接