Книга: Основы программирования на JavaScript
Лекция 11. Обработка ошибок в JavaScript
Лекция 11. Обработка ошибок в JavaScript
Обработка ошибок в JavaScript: Синтаксические ошибки. Ошибки времени выполнения. Window.onerror. Try/Catch/Finally и Throw. Обработка ошибок в AJAX
Вы написали приложение JavaScript, и оно работает отлично – пока вы не получите сообщение об ошибке. Это нечто неприглядное, выскакивающее на экране, что-нибудь вроде 'myObject.fields is null or not an object'. Что это значит? В этом уроке мы рассмотрим, как избавиться от ошибок, и покажем несколько различных методов для общей обработки ошибок.
JavaScript имеет два основных уровня обработки ошибок: синтаксические ошибки и ошибки времени выполнения. Синтаксические ошибки возникают до выполнения кода JavaScript, означая в основном, что код невозможно компилировать. Возьмем, например, следующий код:
for(var i=0; i<10; i++)
// рабочий код здесь
}
Обратите внимание, что здесь пропущена открывающая скобка {. Если попробовать выполнить этот код, то немедленно появится сообщение об ошибке, даже если код находится в функции, которая не выполняется сразу. Такие ошибки почти всегда легко находятся и исправляются. В этом случае будет получено сообщение, говорящее что-нибудь подобное "Ожидалась ')', строка 10, позиция 18". Если перейти к строке 10, то там обычно будет находиться достаточно очевидная ошибка, такая, как пропущенная ), дополнительный знак <или какая-то другая опечатка. С такими ошибками ничего нельзя сделать, кроме как просто исправить и двигаться дальше. Ниже представлен список некоторых наиболее распространенных синтаксических ошибок:
[x] Пропущенные или непарные фигурные, круглые или квадратные скобки
Каждая фигурная {, круглая (, или квадратная [ скобка должна иметь свою закрывающую парную скобку. Если имеются вложенные скобки, то внутренние должны быть закрыты прежде, чем внешние. Например, набор скобок {[}] является недопустимым.
Условия операторов if, for и while должны помещаться в круглые скобки. Выражнение "if x=5{" является недопустимым, так как "x=5" должно быть заключено в круглые скобки. Если с этим возникнут проблемы, то существуют редакторы, такие, как EditPlus, которые могут выделять соответствующие пары скобок, и т.д.
[x] Пропущенные или непарные кавычки
Это очень распространенная проблема. Строки в JavaScript начинаются символом 'или " и должны заканчиваться таким же символом. Если этот символ существует в строке, то он должен быть экранирован. Например, код
var x = 'It's a beautiful day';
является недопустимым, потому что ' в It's не экранировано. Этот код должен выглядеть следующим образом:
var x = 'It's a beautiful day';
// или
var x = "It's a beautiful day";
Еще одной достаточно распространенной ошибкой является завершение строки другим символом, т.е.:
var x = "It's a beautiful day';
Эта строка начинается с символа ", поэтому должна закончиться также символом ".
[x] Пропущенная точка с запятой.
Хотя точки с запятой обычно не нужны в JavaScript, но лучше все же их использовать. Например, если нужно сократить файл JavaScript, то обычно удаляют все переносы строк. Возьмем следующий код:
var x=5
var y=10
Если удалить переносы строк, то получим код
var x=5 var y=10
который вызовет ошибку. Если бы использовались точки с запятой, то проблемы не было бы.
Перейдем к ошибкам времени выполнения. После запуска кода на исполнение начинают появляться ошибки времени выполнения. Эти ошибки могут возникать в связи с множеством причин. Каждый из следующих далее блоков кода будет порождать ошибку:
alert(x); // 'x' не определено
var x;
x[5] = 'test'; // 'x' будет null или не является объектом
window.frames = 5; // Не реализовано
var for; // ожидается идентификатор
document.doesNotExist(5);
// объект не поддерживает это свойство или метод
alert(parseInt('5')); // ожидается объект
Многие из этих проблем вызываются более общими ошибками, которые приходится разыскивать.
[x] Неправильное использование прописных букв
Все встроенные функции JavaScript используют специальную форму записи имен функций, предполагающую, что имя функции начинается со строчной буквы, а в начале каждого следующего слова будет использоваться прописная буква: parseInt, getElementById, createElement, appendChild, и т.д.
Так как JavaScript учитывает регистр символов, то неправильный ввод имени одной из этих функций часто будет приводить к ошибке во время выполнения.
[x] Ссылка на несуществующий код, функции или объекты DOM
Эта проблема возникает обычно в отношении объектов DOM. Предположим, что имеется код, который изменяет некоторые элементы формы на странице. Если делается попытка выполнить этот код до появления элементов формы, например, если поместить его в тег <HEAD>, то будет получена ошибка JavaScript.
Обычно эта проблема легко решается. Лучшим решением будет выполнение кода по событию onload, например:
<BODY>
или, еще лучше, присоединение события к загрузке тела:
document.captureEvents(Event.LOAD);
document.onLoad=loadFunction;
[x] Использование зарезервированного слова
Существует длинный список зарезервированных ключевых слов JavaScript. Если делается попытка использовать многие из них вне их специального контекста, как, например, запись
var for = 5;
то будет возникать ошибка.
[x] Использование пропущенного параметра
При определении функции обычно используется некоторое количество аргументов. Если некоторые из этих аргументов пропущены и делается попытка их использовать, то возникнут ошибки.
Большинство из этих проблем попадают в категорию опечаток и просто обычных ошибок, которые можно исправить, но необходимо о них знать, чтобы случайно не сделать.
Однако последний тип ошибки из этого списка с пропущенными параметрами можно проверить достаточно легко:
function myFunction(a, b, c){
if(a){
// выполняется работа с a
}
if(b && c){
// выполняется работа с b и c
}
}
Если функция вызывается только с одной переменной, то проблемы не возникает. Однако надо помнить об одной вещи: если входящая по значению переменная может быть определена как false (0 или false), то код не будет работать. В связи с этим лучше проверять, что переменная не была определена:
function myFunction(a, b, c){
if(typeof(a)!='undefined'){
// выполнение кода с a
}
if((typeof(b)!='undefined') && (typeof(c)!='undefined')){
// выполнение кода с b и c
}
}
В этом случае, даже если одна из переменных будет передана как 0, false или null, код все равно будет работать.
Сейчас мы перейдем к изучению механизмов обработок ошибок – с помощью операторов Try/Catch и функции window.onerror.
Откровенно говоря, функция window.onerror имеет небольшую практическую пользу. Ее чаще всего используют для полного отключения всех сообщений об ошибках во время выполнения:
window.onerror = function(){
return true;
}
С этим кодом сообщение об ошибке никогда не будет выводиться. Однако в связи с этим приложение может не работать. Например, если бы переменная была null и с ней была выполнена какая-то операция, то в обычной ситуации должно появиться сообщение об ошибке. При использовании этого кода функция или сценарий в случае возникновения ошибки будет просто молча останавливаться.
Функцию window.onerror можно также использовать для вывода пользователям несколько более дружественных сообщений об ошибках. Можно просто вывести, например, сообщение 'Произошла ошибка, свяжитесь, пожалуйста, с Web-мастером', вместо вывода пользователю всех технических деталей ошибки (что большинство браузеров делает по умолчанию).
Еще одно использование window.onerror состоит в отправке разработчику списка всех ошибок, произошедших на сайте. Можно использовать AJAX для отправки сообщений об ошибках в форме, чтобы можно было позже их исправить. Все это возможно сделать неявно, без взаимодействия с пользователем.
Операторы Try/Catch являются несомненно наиболее распространенным и обычно лучшим способом реализовать обработку ошибок в JavaScript. Но не только это – операторы Try/Catch могут иногда быть единственным способом реализовать некоторые задачи, такие, как обнаружение объекта. Возьмем, например, простую функцию для создания в Internet Explorer объекта XMLHttp:
var activeXObjects = ['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0',
'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];
for(var i=0; i<activeXObjects.length; i++){
try{
return new ActiveXObject(activeXObjects[i]);
}catch(err){}
}
Заранее неизвестно, какие объекты установил пользователь, и, к сожалению, браузер не предоставляет никакого механизма это определить. Поэтому остается создавать каждый из 6 возможных объектов, пока один из них (будем надеяться) не заработает.
Операторы Try/Catch можно использовать для перехвата ошибок двух типов: ошибок времени выполнения и ошибок пользователя. Ошибки времени выполнения, как говорилось ранее, возникают, когда у компилятора JavaScript существует проблема с созданным кодом. Ошибки пользователя, с другой стороны, будут технически проходить без проблем, но возникают в связи с контекстом приложения. Если имеется поле, в которое пользователь, например, должен ввести свой возраст, и пользователь вводит – 2, то это приводит к появлению ошибки.
Блок Try/Catch имеет достаточно простой синтаксис:
try{
// код
}catch(err){
// код обработки ошибки
}
Если код в блоке try приводит к ошибке, то сценарий немедленно переходит в блок catch. Объект ошибки err в JavaScript имеет ряд полезных свойств – описание, сообщение, имя и номер, которые можно использовать для вывода информации о том, что произошло:
try{
var x;
x[5] = 5;
}catch(err){
alert('An error occured: '+err.description);
}
Если в операторе catch окажется ошибка, то JavaScript сможет обратиться в дальнейшем к ее описанию.
Такой блок кода Try/Catch можно применять в любом месте. Однако, обычно, код должен быть написан таким образом, чтобы это не нужно было использовать, – в частности, весь ввод должен проверяться.
Блок Try/Catch можно применять также для создания своих собственных ошибок:
function setAge(x){
if(typeof(x)=='undefined') throw('Вы должны ввести возраст');
if(typeof(x)!='number') throw('Возраст должен быть числом');
if(x<0) throw('Возраст не может быть меньше 0');
if(x>120) throw('Возраст не может быть больше 120');
var myAge = x;
// еще код
}
try{
setAge(userInput);
}catch(err){
alert(err);
}
В этом случае выполняется проверка того, что пользователь вводит возраст. Если он вводит недопустимые данные, сценарий немедленно завершается, а пользователь получает сообщение об ошибке.
Блок try/catch имеет еще одну часть, оператор finally:
try{
// код
}catch(err){
// код
}finally{
// код
}
Код в "завершающем блоке" будет выполняться независимо от того, что происходит с операторами Try/Catch. В чем же разница между завершающим блоком и простым размещением кода после блока try/catch? В большинстве случаев никакой разницы не будет. Однако, если блок try/catch находится в функции и происходит выход из функции в блоке try или catch, то возникнет существенное различие:
function myFunction(){
try{
return someValue;
}catch(err){
return defaultValue;
}finally{
alert('finally!');
}
alert('End!');
}
В этом случае оба блока try и catch возвращают значение. Мы получим сообщение "finally!", но не получим сообщение "End!", потому что произойдет выход из функции до сообщения alert('End!'). То же самое остается справедливым для операторов Try/Catch, которые осуществляют выход из тела цикла for или while, например:
for(var i=0; i<10; i++){
try{
if(i==5) continue;
}catch(err){
// обработка ошибки
}finally{
// код
}
// еще код
}
Запросы XMLHttp, рассмотренные в предыдущей лекции, могут иметь совершенно другой тип ошибки: данные просто не проходят. Это можно проверить через статус объекта XMLHttp:
function processingFunction(){
if(oXml.readyState!=4) return; // запрос не выполнен
switch(oXml.status){
case 0: case 200: // запрос выполнен
break;
case 408: case 504: // запрос превысил время ожидания
// код
break;
default: // ошибка запроса
// код
return; // возможно, вы захотите выйти
break;
}
// продолжение обработки запроса
}
oXml в этом примере является объектом XMLHttp, а функция processingFunction была присоединена к свойству onreadystatechange этого объекта.
Проверяя код статуса, мы узнаем, был ли запрос обработан успешно. Код 200 является в HTTP стандартным кодом статуса "Все прошло нормально" . Код 0 возникает при загрузке файлов из локальной файловой системы (если для этого есть соответствующие полномочия). Статус код 0 часто возникает при локальном тестировании приложения.
Коды статуса 408 и 504 представляют ситуацию с превышением времени ожидания. Очень часто это указывает на сетевые проблемы, и простое повторение запроса может разрешить проблему. Однако отметим, что эти коды представляют также слишком длительную работу сервера над ответом. Например, если существует ошибка сценария на сервере, которая приводит к бесконечному циклу, то может возникнуть код ошибки 408 или 504. В этом случае повторная попытка будет вредоносной, поэтому надо быть осторожным. Самым безопасным является уведомление пользователя и выход из функции, но это не очень корректно по отношению к пользователю.
Все другие коды ошибок имеют свои собственные значения, но в данной ситуации это не важно. Нас интересует только то, что мы не получили нужные данные. Поэтому если код попадает в область "default", то мы имеем проблему. Наверно в этой ситуации лучше всего сообщить пользователю о проблеме и выйти из функции.
Это почти все об обработке ошибок в JavaScript. Имеет смысл включать в функции обработку ошибок, но, возможно, что это не требуется для каждой функции или каждого фрагмента кода. В большинстве ситуаций достаточно проверки ввода пользователей. Для реализации проверки пользователя наиболее полезным средством является использование блоков Try/Catch/Throw.
В следующей лекции будет рассмотрена рекурсия:
"Чтобы понять рекурсию, сначала необходимо понять рекурсию".
- Лекция 1. Язык сценариев JavaScript
- Лекция 2. Операторы и функции
- Лекция 3. Формы и циклы
- Лекция 4. Функции и концепция объектов
- Лекция 5. Строки, числа и массивы
- Лекция 6. Объектная модель документа
- Лекция 7. Объект документа и объект окна
- Лекция 8. Основы объектно-ориентированного программирования
- Лекция 9. Наследование и замыкание
- Лекция 10. Основы приложений AJAX
- Лекция 11. Обработка ошибок в JavaScript
- Лекция 12. Рекурсия
- Дополнение I. Краткое руководство по AJAX
- Дополнение II. Учебное руководство по XHTML
- Содержание книги
- Популярные страницы
- Основы программирования на JavaScript
- Лекция 11. Обработка ошибок в JavaScript
- Верстак JavaScript
- Обработка ошибок времени выполнения
- Справочкик по JavaScript
- Перехват ошибок
- Обработка перехваченных ошибок
- Лекция 15. Работа с базами данных
- 5.4 Команда trap: обработка прерываний
- 15.3. Обработка изображений при помощи RMagick
- 12. Лекция: Создание приложений с графическим интерфейсом пользователя.