Основы программирования на JavaScript
Шрифт:
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.
В следующей лекции будет рассмотрена рекурсия:
"Чтобы понять рекурсию, сначала необходимо понять рекурсию".Лекция 12. Рекурсия
Данное высказывание очень четко выражает суть рекурсии. Рекурсия является базовой концепцией программирования вообще, а не только JavaScript, понимание которой очень полезно. Она включает вызов функции из той же самой функции. Почему это может понадобиться? Предположим, что имеется массив массивов. Каждый из этих массивов может иметь в себе массивы, которые могут иметь массивы, которые могут иметь ... собственно, в этом и состоит идея. Таким образом мы имеем множество массивов в других массивах. Как выполнить одну и ту же операцию на всех элементах во всех этих массивах? Можно попробовать использовать простой цикл for, но неизвестно, сколько имеется массивов, и неизвестно, как глубоко распространяется вложение массивов. Поэтому остается только концепция рекурсии.
В этом примере мы циклически перебираем все элементы массива первого уровня. Если какой-либо из этих элементов в массиве сам будет массивом, мы снова вызываем функцию, передавая этот элемент как первичный массив. Затем функция будет перебирать этот массив и снова вызывать себя, пока не останется ни одного массива.
Другим хорошим примером рекурсии будет написание синтаксического анализатора документа XML. Каждый узел документа XML можно анализировать совершенно одинаково, поэтому мы можем разбить всю задачу на множество более мелких одинаковых шагов.
Самым трудным в рекурсии является ее понимание. Такие концепции, как циклы, воспринимаются достаточно естественно, в то время как рекурсия трудна для большинства людей. Рекурсивные функции также очень часто требуют больше памяти, чем нерекурсивные функции. Если имеется функция, которая вызывает себя на 20 уровней вглубь, потребуется как минимум в 20 раз больше памяти.
Простым примером будет написание рекурсивной функции факториала. Факториал N, записываемый как N!, определяется как произведение всех чисел от N до 1. Поэтому 5! будет равен 5*4*3*2*1 = 120.
function factorial(N){
return N<=1?1:N*factorial(N-1);
}
Демонстрационный пример
Факториал
Очень элегантное решение, не правда ли? В результате мы вызываем функцию факториала 5 раз для N = 5. Можно в действительности развернуть всю рекурсивную функцию и получить (5*(4*(3*(2*(1))))). Каждая пара скобок представляет новый вызов функции факториала. Можно также видеть, что если пользователь вводит число <=1, то всегда получит в качестве результата 1.
Давайте рассмотрим другой пример. При работе с программами рисования, такими, как Photoshop или MS Paint, иногда используется инструмент заливки (flood fill). Этот инструмент заливает выбранный цвет другим, указанным цветом. Это делается рекурсивно, и алгоритм заливки достаточно прямолинеен:
/*
это - псевдо-код, быстро написанный и нефункциональный,
который должен просто дать общую идею о том, как действует
реальный код
*/
function floodFill(x, y){
if(alreadyFilled(x, y)) return;
fill(x, y);
floodFill(x, y-1);
floodFill(x+1, y );
floodFill(x, y+1);
floodFill(x-1, y );
}
function fill(x, y){
// эта функция будет фактически изменять цвет поля
}
function alreadyFilled(x, y){
// эта функция проверяет, что поле уже было закрашено
}
Идея этого кода состоит в том, чтобы закрасить текущий квадрат или пиксель. Затем он пытается закрасить квадрат выше, справа, ниже и слева от себя. При таком алгоритме каждый квадрат будет закрашен достаточно быстро. Однако здесь возникает небольшая проблема - размер стека.