Кидання рядків замість Помилок


80

Оскільки ми можемо кинути що-небудь із throwключовим словом у Javascript, чи не можемо ми просто кинути рядок повідомлення про помилку безпосередньо?

Хтось знає якийсь улов у цьому?

Дозвольте мені додати до цього деяку довідку: Дуже часто у світі JavaScript люди покладаються на перевірку параметрів на відміну від використання механізму try-catch, тому має сенс викидати лише фатальні помилки throw. Тим не менше, щоб мати змогу вловлювати деякі системні помилки, я повинен використовувати інший клас для власних помилок, і замість того, щоб створювати підклас Error, я думаю, що я повинен просто використовувати String.


1
Хоча це можливо, чи має сенс? Краще вловити помилку, ніж рядок.
Роб W


export.login = (req, res) => {login (req). then (({token, user}) => {res.send (token);}). catch (err => {if (typeof err = == 'рядок') {res.status (401) .send (помилка);} else {console.log (помилка); res.status (500) .send ('Щось пішло не так');}}); } Я обробляю помилки таким чином, я також розгублений, чи правильно це роблю.
Md Adil

Відповіді:


56

У той час як добре можна викинути будь-яке значення, як правило , вважається поганою формі , щоб кинути що - небудь інше , ніж екземпляр Errorабо один з його підкласів. Цьому є кілька причин:

  1. Ловля код може очікувати занедбаний об'єкт , щоб звичайні message, stacktraceі nameвластивості , які з'являються на Errorс.
  2. Відсутність стека робить налагодження проблематичним, особливо у випадку невловлюваних винятків / необроблених відмов. Наприклад, налагодження помилки "Uncaught [Object object]" може бути особливо болючим.

8
Наприклад, він може припустити, що .messageвластивістю Errorє рядок, спробувати викликати на ньому рядовий метод і вибухнути.
Mark Amery

5
Ви можете , але я б не сказав, що це "добре" .
1j01,

6
Це жахлива ідея, оскільки це означає, що вам буде набагато складніше налагодити помилку без трасування стека.
Бенджамін Груенбаум,

1
@BenjaminGruenbaum Якщо ви кидаєте рядок у Chrome, ви отримуєте трасування стека. Наприклад, функція a () {киньте "Привіт Світ"; } a (); `матиме такий стек:a @ main.js:4 (anonymous) @ main.js:7
doubleOrt

1
@Taurus дякую, я цього не знав - спробуй зараз зробити це за допомогою налагоджувача, не підключеного у firefox :)
Бенджамін Груенбаум

57

Так, ви можете кидати інші цінності , але це не є доброю практикою .

Хтось знає якийсь улов у цьому?

Рядок не є об'єктом помилки і не передає жодної корисної інформації щодо налагодження. Devtools покладаються на такі, як файл і рядок, де була створена помилка, стек стека в throwрозташуванні тощо, які доступні як властивості Errorоб'єктів.

Всякий раз, коли ви думаєте кинути примітивне значення рядка, new Error("<the string>")замість цього викиньте .


10
Варто зазначити, що програми devtools Chrome надрукують трасування стека, навіть якщо ви кинете рядок. Ви втрачаєте .stackвластивість, яка може бути корисною для автоматизованої обробки помилок (наприклад, при налаштуванні автоматичного повідомлення про помилки на сервер, щоб дозволити вам налагоджувати речі, які підуть не так у виробництві), але це скоріше суттєві випадки; щоденна ручна налагодження у браузері прекрасно працює, якщо ви кидаєте рядки.
Mark Amery

19

Ви знаєте, ви можете кидати помилки з повідомленнями.

try {
    throw new Error("This is an error");
} catch (e) {
    alert(e.message); // This is an error
}

Але насправді можна кидати струни:

try {
    throw "This is an error";
} catch (e) {
    alert(e); // This is an error
}

4
Вибачте, що не дав зрозуміти питань. Я знаю всі ці роботи, але мене цікавлять потенційні проблеми безпосереднього використання рядків на відміну від використання об’єкта Помилка.
billc.cn

Ага, добре, тоді просто погляньте на коментар Янз. У цьому підсумовуються всі застереження. Але моя порада - все-таки кидати Errorпредмети зі спеціальними повідомленнями. Це економить ваші проблеми з перевіркою типу помилки, щоб визначити помилки "ваших" від інших помилок, що генеруються власним шляхом ... Якщо, звичайно, ви не хочете це зробити спеціально (тоді, можливо, повторне перекидання Errorоб'єктів у catchобласть) .
MaxArt

5

Як згадували інші вище, якщо ви не кидаєте об'єкт Помилки, тоді вам потрібно мати блоки спроб / лову, щоб захопити ці об'єкти та обробляти їх належним чином, інакше опинитися у світі болю для налагодження.

Однак, коли справа доходить до викиду Помилок з метою обробки помилок, таких як контроль потоку програм, це може бути корисним способом використання throwбез Помилки.

Використовуючи броски для управління потоком програм, це може бути неефективним на будь-якій мові, оскільки час виконання часто робить багато важких робіт, щоб розмотати інформацію про стек викликів та серіалізувати дані, щоб вони були доступні для користувальницької області. Уникаючи створення помилок, ви можете уникнути цього влучення продуктивності. Ключ у тому, що у вас повинен бути обробник у стеку викликів, який знає, як вирішити цю ситуацію. Наприклад, якщо ви throw {isHardStop: true, stopCode: SOME_CODE}і розробляєте обробники для виявлення цього, можливо, ви зможете згладити частину коду або вибрати більш синтаксис.

Ваш обробник для цієї справи сходів може мати такий вигляд:

try { ... } catch(thr) {
    if(!thr){
       // Is not Error or Json - Handle accordingly
    } else if(thr.isHardStop){
       // Handle the stop
    } else {
       // Most likely a real error. Handle accordingly
    }
}

Ні, якщо вам потрібно керувати потоком програм, ви повертаєтеся / вирішуєте зі значенням, яке може обробляти потік програми. Виняток - винятковий. Якщо ви не можете відновити і вам потрібно, щоб система видала виняток, це не для потоку програм, а для обробки винятків.
Сукіма

Я погоджуюсь, що помилки та винятки не слід викидати з інших цілей, крім обробки винятків. Однак у моєму прикладі я просто кидаю об'єкт, а не створюю інстанцію помилки, а отже, просто використовую механізм try / catch для альтернативного управління потоком. Показник ефективності повинен бути незначним, але тренованість не є ідеальною. З урахуванням сказаного, я ніколи не робив цього сам і, мабуть, не зробив би цього дня. Натомість я б, мабуть, використав метод, подібний використаному в Erlang / Elixir, обертаючи логіку лямбда-сигналом, який повертає ідентифікатор успіху та значення результату.
Timothy C. Quinn

3

Хоча ви можете передавати будь-який тип даних, який хочете, це не є оптимальним під час налагодження. ErrorОб'єкт JS містить всю інформацію про помилку та повідомлення. Тоді як рядок може містити лише повідомлення.

Ця додаткова інформація включає:

  1. fileName : з якого файлу викинуто помилку
  2. Номер лінії : з якого рядка викинуто помилку
  3. stacktrace : з якої функції було викликано помилку

Ось, наприклад, стек стеку від chrome devtools:

введіть тут опис зображення

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