处理JavaScript中的特定错误(请考虑例外)


111

您将如何实现不同类型的错误,以便能够捕获特定错误并让其他错误冒出来..?

实现此目的的一种方法是修改Error对象的原型:

Error.prototype.sender = "";


function throwSpecificError()
{
    var e = new Error();

    e.sender = "specific";

    throw e;
}

捕获特定错误:

try
{
    throwSpecificError();
}

catch (e)
{
    if (e.sender !== "specific") throw e;

    // handle specific error
}


你们有其他选择吗?

Answers:


158

要创建自定义异常,可以从Error对象继承:

function SpecificError () {

}

SpecificError.prototype = new Error();

// ...
try {
  throw new SpecificError;
} catch (e) {
  if (e instanceof SpecificError) {
   // specific error
  } else {
    throw e; // let others bubble up
  }
}

在不继承Error的情况下,一种极简主义的方法可能是抛出一个具有名称和消息属性的简单对象:

function throwSpecificError() {
  throw {
    name: 'SpecificError',
    message: 'SpecificError occurred!'
  };
}


// ...
try {
  throwSpecificError();
} catch (e) {
  if (e.name == 'SpecificError') {
   // specific error
  } else {
    throw e; // let others bubble up
  }
}

2
从继承Error有问题。见stackoverflow.com/questions/1382107/...
新月新鲜的

5
此代码的问题:} catch (e) { if (e.name == 'SpecificError') { // specific error } else { throw e; // let others bubble up } }是它在IE7中将不起作用,从而引发“抛出并未捕获的异常”错误。以下是msdn极其愚蠢的解释(如往常一样):“您包含了throw语句,但未将其包含在try块中,或者没有关联的catch块来捕获错误。在try块中引发了异常使用throw语句,并使用catch语句将其捕获到try块之外。”
尤金·库兹曼科

1
好吧,Microsoft的C#当然比Javascript:P更能处理错误。Mozzilla在Firefox中添加了类似的内容。尽管它不在Ecmascript标准中,甚至不在ES6中,但他们也解释了如何使其符合标准,尽管它不是那么简洁。基本上与上述相同,但使用instanceOf在这里
巴特2015年

在Javascript中,您可以抛出任何想要的东西,无论是简单的字符串,数字(认为错误代码)还是完全合格的对象。甜!
亚伯拉罕·布鲁克斯

1
@LuisNell,如果仔细看一下我的代码示例,您会发现我没有建议使用name构造函数的属性。我建议抛出一个带有name属性的自定义对象,该对象不会损坏...
CMS

15

如下面的注释所述,这是Mozilla特定的,但是您可以使用“条件捕获”块。例如:

try {
  ...
  throwSpecificError();
  ...
}
catch (e if e.sender === "specific") {
  specificHandler(e);
}
catch (e if e.sender === "unspecific") {
  unspecificHandler(e);
}
catch (e) {
  // don't know what to do
  throw e;
} 

至少在语法上,这更类似于Java中使用的类型化异常处理。


结合CMS的答案,非常完美。
Ates Goral

3
有条件捕捞是我以前不知道或忘记的事情。感谢您的教育/提醒我!+1
Ates Goral

12
仅受Firefox支持(自2.0起)。它甚至不会在其他浏览器中解析;您只会收到语法错误。

10
是的,这是仅Mozilla的扩展,甚至没有提议进行标准化。作为语法级别的功能,无法嗅探它,也可以选择使用它。
bobince

3
另外,关于提议的解决方案是非标准的。引用[Mozilla的JavaScript参考[(developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…):]This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.
informatik01

10

try-catch-finally.js

使用try-catch-finally.js,您可以_try使用匿名回调来调用该函数,该匿名回调将调用该函数,并且可以将调用链接起来.catch以捕获特定的错误,并.finally可以执行任一方法进行调用。

_try(function () {
    throw 'My error';
})
.catch(Error, function (e) {
    console.log('Caught Error: ' + e);
})
.catch(String, function (e) {
    console.log('Caught String: ' + e);
})
.catch(function (e) {
    console.log('Caught other: ' + e);
})
.finally(function () {
    console.log('Error was caught explicitly');
});

现代箭头功能和模板文字的示例

_try(() => {
  throw 'My error';
}).catch(Error, e => {
  console.log(`Caught Error: ${e}`);
}).catch(String, e => {
  console.log(`Caught String: ${e}`);
}).catch(e => {
  console.log(`Caught other: ${e}`);
}).finally(() => {
  console.log('Error was caught explicitly');
});

2

出口使用模块

/**
 * Custom InputError
 */
class InputError extends Error {
  /**
   * Create InputError
   * @param {String} message
   */
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

/**
 * Custom AuthError
 */
class AuthError extends Error {
  /**
   * Create AuthError
   * @param {String} message
   */
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

/**
 * Custom NotFoundError
 */
class NotFoundError extends Error {
  /**
   * Create NotFoundError
   * @param {String} message
   */
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

module.exports = {
  InputError: InputError,
  AuthError: AuthError,
  NotFoundError: NotFoundError
};

导入脚本:

const {InputError, AuthError, NotFoundError} = require(path.join(process.cwd(), 'lib', 'errors'));

用:

function doTheCheck = () =>
  checkInputData().then(() => {
    return Promise.resolve();
  }).catch(err => {
    return Promise.reject(new InputError(err));
  });
};

外部调用代码:

doTheCheck.then(() => {
  res.send('Ok');
}).catch(err => {
  if (err instanceof NotFoundError) {
    res.status(404).send('Not found');
  } else if (err instanceof AuthError) {
    res.status(301).send('Not allowed');
  } else if (err instanceof InputError) {
    res.status(400).send('Input invalid');
  } else {
    console.error(err.toString());
    res.status(500).send('Server error');
  }
});

0

我不喜欢这些解决方案,所以我自己做了。try-catch-finally.js非常酷,只是如果您在尝试之前忘记了一个下划线(_),那么代码仍然可以正常运行,但是任何东西都不会被捕获!uck

CatchFilter

我在代码中添加了一个CatchFilter:

"use strict";

/**
 * This catches a specific error. If the error doesn't match the errorType class passed in, it is rethrown for a
 * different catch handler to handle.
 * @param errorType The class that should be caught
 * @param funcToCall The function to call if an error is thrown of this type
 * @return {Function} A function that can be given directly to the `.catch()` part of a promise.
 */
module.exports.catchOnly = function(errorType, funcToCall) {
  return (error) => {
    if(error instanceof errorType) {
      return funcToCall(error);
    } else {
      // Oops, it's not for us.
      throw error;
    }
  };
};

现在我可以过滤

现在,我可以像在C#或Java中那样进行过滤:

new Promise((resolve, reject => {
   <snip><snip>
}).catch(CatchFilter.catchOnly(MyError, err =>
   console.log("This is for my error");
}).catch(err => {
   console.log("This is for all of the other errors.");
});

-2
    <li>
      <span>onWarning:</span>
      <span id="msg_warning"></span>
    </li>

  try {
  // load face detection model
  await changeFaceDetector(MTCNN)
  changeInputSize(128)

  // try to access users webcam and stream the images
  // to the video element

    const stream = await navigator.mediaDevices.getUserMedia({ video: {} })
    const videoEl = $('#inputVideo').get(0)
    videoEl.srcObject = stream
  }
  catch(err) {
    //$("#msg_error").html(`Requested device not found`);
    $("#msg_error").html(err.message);
    console.log(err.message);
  }

嗨,欢迎来到StackOverflow。从已经发布的其他5个答案中,您的答案更好/更有效/如何?
mjuarez
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.