Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ajax_v_deystvii.pdf
Скачиваний:
34
Добавлен:
05.03.2016
Размер:
5.83 Mб
Скачать

100Часть I. Новый взгляд на Web-приложение

Вглаве 2 мы обсудили основные технологии, составляющие инфраструктуру Ajax. Оказывается, что, пользуясь лишь давно известными нам средствами, можно написать превосходное Ajax-приложение, о котором мы давно мечтали. К сожалению, можно создать себе и массу проблем и получить

врезультате длительной работы запутанный клубок кода, HTML-элементов и стилей, непригодных для сопровождения. Не исключено, что однажды по непонятным причинам результат вашего труда вдруг окажется полностью неработоспособным. А может быть еще хуже. Приложение будет работать, пока вы стоите рядом, затаив дыхание. Если подобная ситуация возникнет

спрограммой, написанной для себя лично, — это неприятно. А если таким результатом завершилась работа по заданию руководства и к тому же возникла необходимость изменить некоторые детали — это просто ужасно!

Ксчастью, подобные проблемы возникали уже на заре компьютерной эры и даже до ее начала. Разработчики нашли способ справляться со сложными проектами и держать в порядке коды большого объема. В этой главе мы рассмотрим базовые инструменты для работы с кодом, которые помогут вам создать Ajax-приложение, изменить его по требованию заказчика и при этом не задерживаться на работе после окончания рабочего дня.

Ajax отличается от DHTML не только способом применения уже известных технологий, но и масштабом их использования. В Ajax-приложении содержится гораздо больший объем JavaScript-кода, чем в классическом приложении. Кроме того, код присутствует в браузере в течение гораздо более длительного времени. Следовательно, возникает задача управления сложностью, которая не стояла перед специалистами, использовавшими DHTML.

В этой главе мы рассмотрим инструменты и приемы, позволяющие наводить порядок в коде программы. Важность этих средств зависит от сложности Ajax-приложения, которое вы создаете. Если вы собираетесь ограничиться созданием лишь простых продуктов, мы советуем вам пропустить материал книги вплоть до главы 9, в которой мы начнем рассмотрение программ, управляемых примерами. Если вы уже знакомы с принципами реструктуризации и образами разработки, перейдите к главам 4-6, в которых будет рассматриваться применение этих средств. В любом случае базовые понятия, рассматриваемые здесь, важны для управления JavaScript-кодом, и мы надеемся, что рано или поздно вы вернетесь к данной главе. В конце главы приведен обзор библиотек независимых производителей, ориентированных на Ajax, поэтому если вы ищете набор инструментов для своего проекта, обратитесь к разделу 3.5.

3.1. Порядок из хаоса

Основной прием, который мы будем применять для упорядочения кода приложения, — это реструктуризация (refactoring), т.е. процесс изменения кода, при котором выполняемые им функции не изменяются, но сам код становится более понятным. Наведение порядка имеет смысл уже само по себе, но, кроме того, выполнить подобную работу необходимо из соображений целесообразности.

Глава 3. Управление кодом Ajax 101

Если код имеет ясную и понятную структуру, гораздо проще реализовы- Бать новые функции, а также модифицировать и удалять уже существующие. Если код выполнен неаккуратно, он, может быть, и соответствует текущим требованиям, но никто из команды разработчиков не представляет, почему же он все-таки работает.

Практически каждому разработчику приходится реагировать на изменяющиеся условия. Как правило, приводить программу в соответствие новым требованиям приходится в сжатые сроки. В процессе реструктуризации код упорядочивается и становится пригодным к сопровождению. Реструктуризировав код, вы можете без страха изучать новые требования и выполнять их.

Элементарные действия по реструктуризации уже описывались в главе 2, когда речь шла о размещении JavaScript, HTML-кода и таблиц стилей в отдельных файлах. Однако JavaScript-код считается длинным, если он превышает 120 строк и объединяет в себе низкоуровневые функции (например, поддержку запроса серверу) с фрагментами кода, управляющими объектами документа. При работе над большим проектом иметь один JavaScript-файл (равно как и один файл со стилями) крайне неудобно. Гораздо лучше создавать небольшие фрагменты кода, удобные для чтения и модификации, каждый из которых выполняет конкретную задачу. Такой подход принято называть распределением функций, или распределением ответственности

(separation of responsibilities).

Реструктуризация преследует и другую цель — идентификацию общих решений и приведение кода в соответствие конкретному образу разработки. Этот вопрос желательно обсудить подробнее.

3.1.1. Образы разработки

Если код соответствует некоторому хорошо зарекомендовавшему себя шаблону, есть все основания предполагать, что он будет удовлетворительно работать, хотя бы потому, что подобная задача уже была решена ранее. Разработчики обдумали все основные вопросы и решили большинство проблем. Если повезет, может оказаться, что существуют даже базовые программные средства, пригодные для повторного использования.

Такие шаблоны, отражающие опыт предшественников, принято называть образами разработки. Это понятие было введено в 1970-х годах в архитектуре, а в последние годы его начали применять и разработчики программного обеспечения. Образы разработки широко применяются при создании Javaпрограмм, предназначенных для выполнения на сервере, а корпорация Microsoft активно внедряет его в .NET Framework. Данный термин звучит внушительно, напоминает нечто, относящееся к "чистой науке", и бывает, что кто-то, не потрудившись разобраться в данном вопросе, применяет его лишь для того, чтобы произвести впечатление на собеседников. Многие неправильно истолковывают это понятие. На самом деле образ разработки — это описание способа решения задачи, связанной с разработкой программы. Благодаря применению образов разработки ряд абстрактных решений получили имена, а это упрощает их обсуждение и понимание.

102 Часть I. Новый взгляд на Web-приложение

Образы разработки важны при реструктуризации, поскольку позволяют кратко описать основную цель этого процесса. Инструкция типа "оформить этот фрагмент кода в виде объектов, инкапсулирующих выполнения действия пользователем и позволяющих отменить это действие" слишком многословна, поэтому ее трудно удержать в голове, выполняя реструктуризацию кода. Если же вы скажете, что необходимо привести код в соответствие с образом разработки Command, то задача будет поставлена гораздо точнее и обсуждать ее станет намного удобнее.

Если вы давно занимаетесь разработкой серверных программ на Java, то, вероятно, скажете, что мы не сообщили вам ничего нового. Другие, возможно, подумают, что мы агитируем их применять нечто вроде блок-схем. В любом случае мы готовы услышать вопрос: какое отношение имеет вышесказанное к Ajax? Ответ прост: большое! Давайте выясним, какие выгоды может получить от реструктуризации программист, использующий Ajax.

3.1.2. Реструктуризация и Ajax

Мы уже говорили о том, что Ajax-приложения, как правило, содержат большой объем JavaScript-кода, который длительное время сохраняется

вбраузере.

Вклассическом Web-приложении сложный код находится на сервере и образы разработки применяются к серверным программам PHP, Java или .NET. Используя Ajax, мы должны применить те же средства к клиентскому коду.

Можно даже утверждать, что JavaScript-код больше нуждается в реструктуризации, чем программы, написанные на Java и С# . Несмотря на синтаксис, JavaScript больше напоминает такие языки, как Ruby, Python и даже Common Lisp, чем Java или С# . Он обеспечивает необычайную гибкость и богатые выразительные средства. Квалифицированный разработчик несомненно воплотит эти возможности в программу высокого качества, однако средний программист может не справиться с ними, в результате пострадает надежность программы. Языки, ориентированные на создание корпоративных приложений, такие как Java и С#, напротив, ориентированы на команду специалистов средней квалификации, состав которой может изменяться.

Опасность создать посредством JavaScript запутанный и сложный для восприятия код достаточно высока, и если этот код ориентирован не на одну Web-страницу, а на целое приложение, необходимо принимать меры для исключения такой возможности либо для уменьшения ее вероятности. Поэтому мы настаиваем на реструктуризации Ajax-программ и считаем, что она должна производиться более тщательно, чем это делается при работе с такими относительно "безопасными" языками, как Java и С# .

3.1.3. Во всем надо знать меру

Приступая к реструктуризации, необходимо помнить, что она, как и образы разработки, является средством, а не целью. Выполнять ее надо лишь До тех пор, пока это оправдано. Если вовремя не остановиться, произойдет

Глава 3. Управление кодом Ajax 103

"блокировка разработки из-за анализа" — ситуация, при которой реализация приложения откладывается на неопределенное время из-за бесконечного поиска наилучшего решения. Разработчик пытается еще больше повысить гибкость системы, довести ее структуру до идеального состояния, чтобы будущие изменения не вызывали никаких затруднений. Следует ли говорить, что до изменений дело может вовсе не дойти, так как под угрозу ставится существование самой программы.

Подобную ситуацию описал Эрик Гамма (Erich Gamma), признанный специалист по образам разработки, в недавнем интервью (ссылка на него приведена в конце главы). Подобно тому как разработчик включает в свою программу целочисленные переменные, строки и массивы лишь там, где они необходимы, применять образы разработки надо только тогда, когда они нужны.

Э. Гамма считает, что наилучшим способом применения образов разработки является реструктуризация. Следует написать код так, чтобы он лишь выполнял поставленную задачу, а затем, приводя его в соответствие с образом разработки, можно решить типичные проблемы. Если у вас уже написан большой объем кода и вы собираетесь привести его в порядок или сделать то же самое с программой, написанной другим программистом, то в обычных условиях вам придется приложить все силы и все равно успех не будет гарантирован. К счастью, применять шаблоны разработки можно к коду любой сложности и любого качества. В следующем разделе мы рассмотрим фрагменты, приведенные в качестве примеров в главе 2, и выясним, как можно преобразовать их путем реструктуризации.

3.1.4. Реструктуризация в действии

На первый взгляд, преимущества реструктуризации кажутся очевидными, но программисты-практики, наверное, захотят увидеть их на конкретном примере. Потратим немного времени, чтобы применить процедуру реструктуризации к Ajax-коду, который был представлен в листинге 2.11. Как вы помните, мы определили функцию sendRequest(), предназначенную для передачи запросов серверу. Для извлечения объекта XMLHttpRequest эта функция обращается к initHttpRequest (), а обработка ответа производится посредством функции обратного вызова onReadyState (). Объект XMLHttpRequest был помещен в глобальную переменную, что позволило функции обратного вызова использовать его. Обработчик ответа, действующий по принципу обратного вызова, анализировал состояние объекта запроса и генерировал информацию, предназначенную для отладки.

Код, представленный в листинге 2.11, выполняет необходимые действия, но повторно использовать его будет непросто. Обычно,-передавая запрос серверу, мы собираемся анализировать ответ и, в зависимости от его содержания, выполнять действия, необходимые для решения текущей задачи. Для того чтобы включить в имеющийся код бизнес-логику, нам пришлось бы модифицировать функцию onReadyState ().

104 Часть I. Новый взгляд на Web-приложение

Наличие глобальной переменной также может привести к возникновению проблем. Если надо будет одновременно передать несколько запросов серверу, нам придется указывать для каждого из них отдельный обработчик. Кроме того, получив набор ресурсов, необходимо будет следить, какие из них должны отображаться взамен существующих, а какие не надо учитывать.

В объектно-ориентированном программировании стандартным решением задач подобного рода является инкапсуляция требуемых функциональных возможностей в составе объекта. Объектные средства JavaScript позволяют нам сделать это. Мы назовем наш объект ContentLoader, поскольку он загружает данные с сервера. Каким должен быть этот объект? Наверное, он должен создаваться на основе URL ресурса, которому передается запрос. Нам также надо указать ссылку на произвольный обработчик обратного вызова, который будет выполнен при успешной загрузке документа. Необходима еще одна ссылка на обработчик, который получит управление при наличии ошибки. Обращение к объекту может выглядеть следующим образом:

var loader=new net.ContentLoader('mydata.xml', parseMyData);

где parseMyData — функция обратного вызова, соответствующая успешной загрузке документа. Код объекта ContentLoader показан в листинге 3.1. В нем были применены новые решения, которые мы обсудим ниже.

Листинг 3.1. Объект ContentLoader

//1 Объект пространства имен var net=new Object();

net.READY_STATE_UNINITIALIZED=O; net.READY_STATE_LOADING=1 ; net.READY_STATE_LOADED=2; net.READY_STATE_INTERACTIVE=3; net.READY_STATE_COMPLETE=4;

// 2 Конструктор net.ContentLoader=function(url,onload,onerror){

this.url=url; this.req=null ; this.onload=onload;

this.onerror=(onerror) ? onerror : this.defaultError; this.loadXMLDoc(url) ;

}

net.ContentLoader.prototype={

//3 Переименованная функция initXMLHttpRequest loadXMLDoc:function(url){

//4 Реструктуризированная функция loadXML

if (window.XMLHttpRequest){ this.req=new XMLHttpRequest() ;

} else if (window.ActiveXObject){

this.req=new ActiveXObject("Microsoft.XMLHTTP");

}

if (this.reqH try{

var loader=this; this.req.onreadystatechange=function(){ loader.onReadyState.call(loader);

}

Глава 3. Управление кодом А/ах 105

// 5 Реструктуризированная функция sendRequest this.req.open('GET•, url, true); this.req.send(null);

}catch (err){ this.onerror.call(this) ;

}

}

},

// 6 Реструктуризированная функция обратного вызова onReadyState:function(){

var req=this.req;

var ready=req.readyState;

if (ready==net.READY_STATE_COMPLETE){ var httpStatus=req.status;

if (httpStatus==200 || httpStatus==O){ this.onload.call(this);

}else{

this.onerror.call(this);

}

}

},

defaultError:function(){ alert("error fetching data!"

+"\n\nreadyState:"+this.req.readyState +"\nstatus: "+this.req.status

+"\nheaders: "+this .req.getAHResponseHeaders ()) ;

}

}

Первое новшество — это единственная глобальная переменная net 1, которая содержит все необходимые ссылки. При этом вероятность конфликта имен уменьшается, а код, имеющий отношение к сетевым запросам, локализуется в одном месте.

Для нашего объекта предусмотрен конструктор 2, которому передаются три параметра, но только два из них являются обязательными. При установке обработчика ошибок мы проверяем, содержит ли параметр значение null,

ив случае положительного результата проверки предпринимаем действия по умолчанию. Возможность передавать функции переменное число параметров

ипередавать функцию при первом обращении к классу может показаться странной для специалистов, привыкших создавать программы в рамках объектного подхода. Однако JavaScript допускает подобные решения. Свойства данного языка рассмотрены в приложении Б.

Значительную часть кода функций initXMLHttpRequest () 4 и sendRequest () 5 мы поместили в состав объекта и переименовали измененный код. Новое имя призвано отражать более широкую область применения. Функция, объединяющая возможности initXMLHttpRequest()

иsendRequest (), теперь называется loadXMLDoc 3. Для нахождения объекта XMLHttpRequest и инициализации запроса мы используем те же подходы, что

иранее, но это никак не влияет на действия программиста, использующего Данный объект. Функция обратного вызова, onReadyState () 6, в основном

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]