Xử lý các lỗi cụ thể trong JavaScript (nghĩ rằng ngoại lệ)


111

Bạn sẽ triển khai các loại lỗi khác nhau như thế nào, vì vậy bạn có thể bắt được những lỗi cụ thể và để những lỗi khác nổi lên ..?

Một cách để đạt được điều này là sửa đổi nguyên mẫu của Errorđối tượng:

Error.prototype.sender = "";


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

    e.sender = "specific";

    throw e;
}

Bắt lỗi cụ thể:

try
{
    throwSpecificError();
}

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

    // handle specific error
}


Các bạn có lựa chọn thay thế nào không?

Câu trả lời:


158

Để tạo ngoại lệ tùy chỉnh, bạn có thể kế thừa từ đối tượng Lỗi:

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
  }
}

Một cách tiếp cận tối giản, không kế thừa từ Lỗi, có thể là ném một đối tượng đơn giản có tên và thuộc tính thông báo:

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
Kế thừa từ Errorcó vấn đề. Xem stackoverflow.com/questions/1382107/…
Crescent Fresh,

5
vấn đề với mã này: } catch (e) { if (e.name == 'SpecificError') { // specific error } else { throw e; // let others bubble up } }là nó sẽ không hoạt động trong IE7, gây ra lỗi "Ngoại lệ được ném và không bị bắt". Sau đây là lời giải thích cực kỳ ngu ngốc (như mọi khi) từ msdn: "Bạn đã bao gồm một câu lệnh ném, nhưng nó không được bao gồm trong khối try hoặc không có khối bắt liên quan để bẫy lỗi. Các ngoại lệ được ném ra từ bên trong khối try bằng cách sử dụng câu lệnh ném và bắt bên ngoài khối thử bằng câu lệnh bắt. "
Eugene Kuzmenko 14/10/12

1
Chà C # của Microsoft chắc chắn xử lý lỗi tốt hơn Javascript: P. Mozzilla đã thêm một cái gì đó tương tự như vậy vào Firefox. Mặc dù nó không nằm trong tiêu chuẩn Ecmascript, thậm chí không phải ES6, nhưng họ cũng giải thích cách làm cho nó phù hợp, mặc dù nó không thành công. Về cơ bản giống như trên, nhưng sử dụng instanceOf. Kiểm tra ở đây
Bart

Trong Javascript, bạn có thể ném bất cứ thứ gì bạn muốn, có thể là một chuỗi đơn giản, một số (mã lỗi) hoặc một đối tượng đủ điều kiện. Ngọt!
Abraham Brookes

1
@LuisNell, Nếu bạn xem kỹ ví dụ mã của tôi, bạn sẽ thấy rằng tôi không đề xuất sử dụng thuộc nametính của hàm tạo. Tôi đã đề xuất ném một vật thể tùy chỉnh với một thuộc nametính, nó sẽ không bị vỡ ...
CMS

15

Như đã lưu ý trong các bình luận bên dưới, đây là Mozilla cụ thể, nhưng bạn có thể sử dụng các khối 'bắt có điều kiện'. ví dụ:

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;
} 

Điều này mang lại một cái gì đó giống với xử lý ngoại lệ đã nhập được sử dụng trong Java, ít nhất là về mặt cú pháp.


Kết hợp với câu trả lời của CMS và nó hoàn hảo.
Ates Goral

3
Bắt có điều kiện là điều mà tôi không biết trước đó hoặc đã quên mất. Cảm ơn vì đã giáo dục / nhắc nhở tôi! +1
Ates Goral

12
Chỉ được hỗ trợ bởi Firefox (kể từ 2.0). Nó thậm chí không phân tích cú pháp trong các trình duyệt khác; bạn chỉ nhận được lỗi cú pháp.
Crescent Fresh

10
Vâng, đây là một tiện ích mở rộng chỉ dành cho Mozilla, nó thậm chí không được đề xuất để tiêu chuẩn hóa. Là một tính năng cấp cú pháp, không có cách nào để phát hiện ra nó và tùy chọn sử dụng nó.
bobince

3
Ngoài ra, liên quan đến giải pháp được đề xuất không phải là tiêu chuẩn. Trích dẫn biểu mẫu [Tài liệu tham khảo JavaScript của Mozilla [( 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

Sử dụng try-catch-last.js , bạn có thể gọi _tryhàm bằng một lệnh gọi lại ẩn danh, hàm này sẽ gọi và bạn có thể chuỗi .catchcác cuộc gọi để bắt các lỗi cụ thể và một .finallylệnh gọi để thực thi theo một trong hai cách.

Thí dụ

_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');
});

Ví dụ với các hàm mũi tên hiện đại và các chữ mẫu

_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

Mô-đun để xuất sử dụng

/**
 * 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
};

Nhập vào tập lệnh:

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

Sử dụng:

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

Mã gọi bên ngoài:

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

Tôi không thích bất kỳ giải pháp nào trong số này nên tôi đã tự làm. Try-catch-last.js khá tuyệt, ngoại trừ việc nếu bạn quên một dấu gạch dưới (_) trước khi thử thì mã sẽ vẫn chạy tốt, nhưng sẽ không có gì bị bắt! Kinh quá.

CatchFilter

Tôi đã thêm CatchFilter trong mã của mình:

"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;
    }
  };
};

Bây giờ tôi có thể lọc

Bây giờ tôi có thể lọc như trong C # hoặ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);
  }

Xin chào, chào mừng bạn đến với StackOverflow. Làm thế nào là câu trả lời của bạn tốt hơn / hiệu quả hơn / etc từ 5 câu trả lời khác đã được đăng?
mjuarez
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.