การจัดการข้อผิดพลาดเฉพาะใน JavaScript (คิดว่ามีข้อยกเว้น)


112

คุณจะใช้ข้อผิดพลาดประเภทต่างๆอย่างไรเพื่อที่คุณจะสามารถจับข้อผิดพลาดที่เฉพาะเจาะจงและปล่อยให้คนอื่นพูดถึง .. ?

วิธีหนึ่งในการบรรลุเป้าหมายนี้คือการปรับเปลี่ยนต้นแบบของ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
}


พวกคุณมีทางเลือกอื่นหรือไม่?

คำตอบ:


159

ในการสร้างข้อยกเว้นที่กำหนดเองคุณสามารถสืบทอดจากวัตถุข้อผิดพลาด:

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/…
Crescent Fresh

5
ปัญหาเกี่ยวกับรหัสนี้} catch (e) { if (e.name == 'SpecificError') { // specific error } else { throw e; // let others bubble up } }คือมันจะไม่ทำงานใน IE7 ทำให้เกิดข้อผิดพลาด "Exception throw and not caught" ต่อไปนี้เป็นคำอธิบายที่โง่มาก (เช่นเคย) จาก msdn: "คุณรวมคำสั่ง throw แต่ไม่ได้อยู่ในบล็อก try หรือไม่มีบล็อก catch ที่เกี่ยวข้องเพื่อดักจับข้อผิดพลาดข้อยกเว้นจะถูกโยนออกจากภายใน try block โดยใช้คำสั่งโยนและจับนอกบล็อกด้วยคำสั่งจับ "
Eugene Kuzmenko

1
C # ของ Microsoft จัดการข้อผิดพลาดได้ดีกว่า Javascript: P Mozzilla เพิ่มบางอย่างใน Firefox ที่เป็นเช่นนั้น แม้ว่าจะไม่ได้อยู่ในมาตรฐาน Ecmascript ไม่ใช่แม้แต่ ES6 แต่ก็ยังอธิบายถึงวิธีการทำให้เป็นไปตามนั้นแม้ว่าจะไม่เป็นความสำเร็จก็ตาม โดยทั่วไปเหมือนกับด้านบน แต่ใช้instanceOfไฟล์. ตรวจสอบที่นี่
บาร์ต

ใน Javascript คุณสามารถโยนอะไรก็ได้ที่คุณต้องการไม่ว่าจะเป็นสตริงธรรมดาตัวเลข (คิดว่ารหัสข้อผิดพลาด) หรือวัตถุที่มีคุณสมบัติครบถ้วน หวาน!
Abraham Brookes

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) มันไม่ได้แยกวิเคราะห์ในเบราว์เซอร์อื่น ๆ คุณจะได้รับข้อผิดพลาดทางไวยากรณ์เท่านั้น
Crescent Fresh

10
ใช่นี่เป็นส่วนขยาย Mozilla เท่านั้นซึ่งไม่ได้เสนอให้เป็นมาตรฐาน การเป็นคุณสมบัติระดับไวยากรณ์จึงไม่มีวิธีใดที่จะใช้มันและเลือกใช้มันได้เช่นกัน
Bobince

3
นอกจากนี้เกี่ยวกับการแก้ปัญหาที่นำเสนอไม่ได้มาตรฐาน ใบเสนอราคาจาก [อ้างอิง JavaScript ของ 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

ด้วยการใช้try-catch-ในที่สุด 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

ฉันไม่ชอบวิธีแก้ปัญหาเหล่านี้ดังนั้นฉันจึงทำด้วยตัวเอง ลองจับในที่สุด js นั้นค่อนข้างดียกเว้นว่าหากคุณลืมขีดล่าง (_) เล็กน้อยก่อนการลองรหัสจะยังทำงานได้ดี แต่จะไม่มีอะไรติดอยู่เลย! Yuck.

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 คำตอบของคุณดีขึ้น / มีประสิทธิภาพมากขึ้น / etc จากอีก 5 คำตอบที่โพสต์ไว้แล้วอย่างไร?
mjuarez
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.