Поводження з конкретними помилками в 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

Щоб створити спеціальні винятки, ви можете успадкувати об’єкт 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
  }
}

Мінімалістичний підхід, не успадковуючи від помилки, може бути киданням простого об'єкта, що має ім’я та властивості повідомлення:

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: "Ви включили оператор кидання, але він не був укладений у блок" спробу ", або не було пов'язаного блоку вилову, щоб відловити помилку. Винятки викидаються з блоку спробу. за допомогою оператора кидка та опинився поза блоком спробу із заявою.
Євген Кузьменко

1
Добре, що C # Microsoft, безумовно, обробляє помилки краще, ніж Javascript: P. Mozzilla додала щось подібне до Firefox, що таке. Хоча це не в стандарті Ecmascript, навіть не в ES6, але вони також пояснюють, як зробити його відповідним, хоча це не так просто. В основному те саме, що вище, але використовуючи instanceOf. Перевірте тут
Барт

У 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, і це ідеально.
Атес Гораль

3
Умовний вилов - це те, про що я раніше не знав або забув. Дякуємо за навчання / нагадування про мене! +1
Ates Goral

12
Підтримується лише Firefox (починаючи з 2.0). Він навіть не розбирає в інших браузерах; ви отримуєте лише синтаксичні помилки.
Півмісяць свіжий

10
Так, це лише розширення Mozilla, воно навіть не пропонується для стандартизації. Будучи функцією на рівні синтаксису, немає ніякого способу нюхати її та необов'язково використовувати.
bobince

3
Крім того, щодо запропонованого рішення є нестандартним. Цитувати форму [Посилання на JavaScript 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-final.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-final.js досить крутий, за винятком того, що якщо ви забудете одну маленьку підкреслення (_) перед спробою, код все одно буде працювати просто чудово, але нічого не застане ніколи! Гидота.

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.