betacode

Обработка ошибок в JavaScript

  1. Что такое Error?
  2. Обработка ошибок с помощью try-catch
  3. Блок try-catch-finally
  4. Built-in Errors
  5. Выбросить Error
  6. Свойства Error
  7. Перевыбросить ошибку (Re-throw Error)
  8. Исключения при схватке ошибок

1. Что такое Error?

Для начала рассмотрим пример, в данном примере я вызываю метод объекта, но данный объект на самом деле не имеет этот метод, и происходит ошибка.
hello-error-example.js
console.log("Three");

let myObj = {};

console.log("Two");

console.log("One");

// Объект myObj не имеет метода showMe().
// Но мы вызываем метод showMe().
// И ошибка происходит здесь.
myObj.showMe(); // ==> Error!!!!!!!!! 

// Срока кода ниже не будет выполнена.
console.log("Let's go!");
Результат запуска примера:
Вы можете увидеть уведомление ошибки на экране Console, уведомление ошибки очень понятное, на какой строке кода это произошло.
Просмотрите поток программы через следующее изображение.
  • Программа запущена абсолютно нормально в шагах (1), (2), (3), (4)
  • Шаг (5) происходит ошибка, когда вы пытаетесь вызвать метод объекта, хотя этот объект не имеет данный метод.
  • Код в шаге (6) не будет выполнен.

2. Обработка ошибок с помощью try-catch

Ошибки могут произойти во время работы (runtime) программы, может быть неожиданная вами ошибка. Используйте try-catch чтобы помочь найти и обработать ошибку при происхождении.
Вернитесь к примеру выше, мы добавим try-catch чтобы найти и обработать ошибку.
hello-catch-example.js
console.log("Three");

let myObj = {};

console.log("Two");

console.log("One");

try {
    // Объект myObj не имеет метод showMe().
    // Но мы вызываем метод showMe().
    // И ошибка происходит здесь.
    myObj.showMe(); // ==> Error!

    // Данный код будет пропущен
    console.log("!!!"); 
} catch (e) {
    console.log("Catched error: " + e);
    console.log("OK continue...");
} 
console.log("Let's go!");
И результаты запуска примера:
Three
Two
One
Catched error: TypeError: myObj.showMe is not a function
OK continue...
Let's go!
Изображение ниже объясняет поток (flow) программы:
  • Шаги (1)-(4) абсолютно нормальны.
  • Исключение происходит в шаге (5), кода вы пытаетесь вызвать метод объекта, но объект не имеет данный метод.
  • Он сразу же прыгает выполнять команду в блоке catch, шаг (6) пропускается.
  • Шаг (7), (8) будет выполнен.
  • Шаг (9 будет выполнен.

3. Блок try-catch-finally

Выше мы ознакомились с обработкой исключений через блок try-catch. Полная обработка ошибки использует try-catch-finally. Блок finally всегда выполняется, несмотря не то, происходит ошибка в блоке try или нет.
try {  
   // Сделать что-то здесь.
} catch (e ) { 
   // Сделать что-то здесь.
} finally  {
   // Блок finally всегда выполняется.
   // Сделать что-то здесь.
}
Пример:
try-catch-finally-example.js
function getGreeting(language) {
    try {
        console.log("Code in try block (*)"); 
        // Вызвать метод greeting() объекта 'language'.
        // Здесь может выброситься исключение
        // если даный объект не имеет метода greeting()
        let v = language.greeting(); 
        console.log("Code in try block (**)"); 
        return v; 
    } catch (e) { 
        console.log("Code in catch block. Something Error: " + e); 
    } finally {
        // Блок 'catch' будет выполнен.
        console.log("Code in finally block");
    } 
    return " !! ";
} 
// ----------------------- TEST --------------------------------- 
// Test 1:
console.log("----- Call getGreeting(null) -----"); 
let v1 = getGreeting(null);
console.log("Greeting: " + v1);  
// Test 2:
console.log("------ Call getGreeting(language) ------"); 
let language = new Object(); 
language.greeting = function() {
    return "Hello Everybody";
} 
let v2 = getGreeting(language); 
console.log("Greeting: " + v2);
Запуск примера:
----- Call getGreeting(null) -----
Code in try block (*)
Code in catch block. Something Error: TypeError: Cannot read property 'greeting' of null
Code in finally block
Greeting:  !!
----- Call getGreeting(language) -----
Code in try block (*)
Code in try block (**)
Code in finally block
Greeting: Hello Everybody
Изображение ниже иллюстрирует поток программы при происхождении ошибки в блоке try, блок finally всегда выполняется.
Изображение ниже иллюстрирует поток программы если нет ошибки в блоке try. В данном случае блок finally выполняется сразу перед выполнением команды return блока try.

4. Built-in Errors

ECMAScript имеет встроенные классы для представления ошибки, ниже является их иерархия (heirachy).
RangeError
RangeError выбрасывается если вы используете число вне разрешаемого диапазона.
error-RangeError-example.js
let num = 1;
try {

  // A number cannot have 500 significant digits
  num.toPrecision(500); // ==> RangeError!!
 
}
catch(err) {
  console.log(err.name);
  console.log(err);
}
ReferenceError
ReferenceError выбрасывается (throw) если вы используете переменную, которая не была объявлена.
error-ReferenceError-example.js
var x;
try {
  x = y + 1;   // y cannot be referenced (used)
}
catch(err) {
   console.log("Error Name: "+ err.name);
   console.log(err);
}
SyntaxError
SyntaxError выбрасывается (throw) если вы пытаетесь оценить (evaluate) код содержащий ошибку синтаксиса.
error-SyntaxError-example.js
try {
  let x;
  eval(" x  = 'Hello  ");   // Missing ' will produce an error
}
catch(err) {
  console.log("Error Name: " + err.name);
  console.log(err);
}
TypeError
TypeError выбрасывается (throw) если вы используете значение неожидаемого вида. Например ошибка происходит, когда вы вызываете метод объект, и объект не имеет данный метод.
error-TypeError-example.js
var num = 1;
try {
  num.toUpperCase(); // Number has no method toUpperCase()
}
catch(err) {
  console.log("Error Name: " + err.name);
  console.log(err);
}
URIError
URIError выбрасывается (throw) если вы используете символы недопустимые в функции URI:
error-URIError-example.js
try {
  decodeURI("%%%");   // You cannot URI decode percent signs
}
catch(err) {
  console.log("Error Name: " + err.name);
  console.log(err);
}

5. Выбросить Error

ECMAScript позволяет вам выбросить (throw) нечто во время работы программы, программа будет считать что произошла ошибка.
throw-any-example.js
console.log(" -------- Test throw any object ------------");
try {
   let myObj = {};
   throw myObj;
} catch(e)  {
   console.log("Catch error: ");
   console.log(e);
}
console.log(" -------- Test throw a Symbol ------------");
try {
   let mySymbol = Symbol();
   throw mySymbol;
} catch(e)  {
   console.log("Catch error: ");
   console.log(e);
}
console.log(" -------- Test throw a Number ------------");
try {
   let myNumber = 100;
   throw myNumber;
} catch(e)  {
   console.log("Catch error: ");
   console.log(e);
}
console.log(" -------- Test throw a String ------------");
try {
   let myString = "Some error";
   throw myString;
} catch(e)  {
   console.log("Catched error: ");
   console.log(e);
}
Output:
-------- Test throw any object ------------
Catch errorr:
{}
 -------- Test throw a Symbol ------------
Catch error:
Symbol()
 -------- Test throw a Number ------------
Catch error:
100
 -------- Test throw a String ------------
Catched error:
Some error
Обычно вы используете класс Error чтобы создать объект ошибки. Другие классы как SyntaxError, InternalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError так же можно использовать в подходящем контексте.
Объект ошибки создается через класс Error (или его подклассы), при выбрасывании (throw) он будет содержать важную информацию как файл из-за которого произошла ошибка, местоположение ошибки, и информацию помогающую вам найти ошибку.
throw-error-example.js
console.log("Three");

// Create an Error
let myError = new Error("Something error!");
console.log("Two");
// Throw it!
throw myError;
console.log("One");
В простом случае вы можете выбросить что угодно, не объект класса Error (Или его подклассы). Но при нахождении ошибок данного вида вы не сможете имет информация как файл из-за которого происходит ошибка, местоположение происхождения ошибки,...
throw-string-error-example.js
console.log("Three");
try {
  console.log("Two");
  // Throw a String!
  throw "Some error!!";
} catch(e)  {
   console.log("typeof e = " + (typeof e));
   // Log the error
   console.log(e); // Some error!!
}
console.log("One");
Output:
Three
Two
typeof e = string
Some error!!
One
В ECMAScript, каждый блок try имеет соответствующий блок cache. Но в блоке try могут произойти разные виды ошибок, в данном случае вам нужно проверить ошибку найденную в блоке catch чтобы предоставить подходящую обработку для каждого вида ошибки.
catch-complex-example.js
let err = new Error("My Error");
let rangeErr = new RangeError();
let evalErr = new EvalError("My Eval Error");

// A random value in [0.. 9]
let randomValue = Math.floor(Math.random() * 10);

// [0,1,2,3]
let random0123 = randomValue % 4;
console.log("random0123 = " + random0123);
try {
   if(random0123 == 0) {
      throw err;
   } else if(random0123 == 1){
      throw rangeErr;
   } else if(random0123 == 2)  {
      throw evalErr;
   } else if(random0123 == 3)  {
      throw "A String Error";
   }
} catch(e)  {
   console.log("typeof e = " + (typeof e));// 'object' or 'string'
   if(e instanceof RangeError) {
      console.log("--> RangeError!!");
   } else if(e instanceof EvalError) {
      console.log("--> EvalError!!");
   } else if(e instanceof Error) {
      console.log("--> Error!!");
   } else if (typeof e == "string"){
      console.log("--> String Error!!");
   } else  {
      console.log("--> Error!!");
   }
   console.log(e);
}

6. Свойства Error

В ECMAScript, ошибка которую вы нашли может быть "Error object" или любой вид данных. Если это "Error object" у вас будет важная информация как название файла создавшая ошибку, местоположение ошибки, Stack Trace,..
Есть некоторые важные свойства (property) класса Error:
  • name: Название ошибки.
  • message: Содержание ошибки.
  • stack (Readonly): текст содержащий информацию, помогающая вам найти местоположение ошибки.
error-properties-example.js
// Create an Error
let myError = new Error();

myError.name = "MyError";
myError.message = "My Error String"; 
try {
  throw myError; 
} catch(err)  {
  console.log("Error Name: " + err.name);
  console.log("Error Message: " + err.message);
  console.log("Type of err.stack: " + (typeof err.stack));
  console.log("--- Stack Trace: ---");  
  console.log(err.stack);
}

7. Перевыбросить ошибку (Re-throw Error)

При обработке исключения вы можете схватить это исключение и обработать или перевыбросить (rethrow) его наружу.
rethrow-example.js
function checkScore(score) {
    if (score < 0 || score > 100) {
        throw "Invalid Score " + score;
    }
} 
function checkPlayer(name, score) { 
    try { 
        checkScore(score)
    } catch (e) {
        // Сделать что-то с exception
        console.log("Something invalid with player: " + name + " >> " + e); 
        // Перевыбросить наружу.
        throw e;
    } 
    console.log("OK Player " + name + " has score: " + score );
}  
// --------------- TEST -------------- 
checkPlayer("Tom", 90); 
checkPlayer("Jerry", -10);
Например, схватить исключение и перевыбросить (rethrow) другое исключение.
rethrow-example2.js
function checkScore(score) {
    if (score < 0 || score > 100) {
        throw "Invalid Score " + score;
    }
} 
function checkPlayer(name, score) { 
    try { 
        checkScore(score)
    } catch (e) {
        // Сделать что-то с exception
        console.log("Something invalid with player: " + name + " >> " + e); 
        // Потом выбросить другое исключение
        throw ("Score " + score +" invalid for player " + name);
    } 
    console.log("OK Player " + name + " has score: " + score );
}  
// --------------- TEST -------------- 
checkPlayer("Tom", 90); 
checkPlayer("Jerry", -10);

8. Исключения при схватке ошибок

В ECMAScript имеются ситуации, когда вы думаете возникнет ошибка, но это не происходит. Например деление на 0 не создает ошибку, результат возвращает Infinity или -Infinity.
ex-Infinity-example.js
console.log( typeof Infinity ); // number

let a = 1 / 0;
console.log(a); // Infinity

let b = -1 / 0;
console.log(b); // -Infinity
Возьмите значение не число, чтобы поделить на число, результатом будет NaN (Not a Number).
ex-NaN-example.js
console.log( typeof NaN ); // number
console.log( isNaN(1) ); // false
console.log( isNaN( NaN ) ); // true

let a = "A String" / 2;
console.log(a); // NaN

let obj = {};
let b = obj / 2;
console.log(b); // NaN
Вы можете получить доступ в элемент с индексом любого массива (Array) не вызывая ошибку.
ex-array-index-example.js
let myArray = [1, 100, 20];

console.log( myArray[1]); // 100
console.log( myArray[10] ); // undefined
console.log( myArray[-10] ); // undefined

Pуководства ECMAScript, Javascript

Show More