![]() |
| На главную страницу | |
| Форум | |
1
Для HTTP 1.0 var number = 42;
Помимо предопределённых свойств, Вы можете иметь в клиентском коде информацию,
которая будет становиться свойствами объекта Хотя Вы можете создавать дополнительные свойства объекта
Помните, что период существования объекта Работа с Картами Изображений/Image Maps
Атрибут <A HREF="mapchoice.html"> Страница Объект client
Несколько браузеров-клиентов могут иметь одновременный доступ к приложению JavaScript.
Объект Машина выполнения JavaScript на сервере конструирует
объект
Машина выполнения конструирует и уничтожает объект JavaScript не сохраняет объекты У Вас имеются несколько различных опций: как и где машине
выполнения сохранять свойства объекта
Резюме по объекту Свойства
В объекте client.custID = getNextCustID();
Здесь определяемая в приложении функция После установки customer ID может оказаться неудобным
требовать от пользователя ввода ID на каждой странице приложения.
Однако без использования объекта Из-за использования такой техники для обслуживания свойств
объекта Не присваивайте объект в качестве значения свойства объекта
client.totalNumber = 17;
Затем Вы можете использовать client.totalNumber = parseInt(client.totalNumber) + 1; Аналогично Вы можете создать Булево свойство объекта client.bool = true; if (client.bool == "true")
Заметьте, что условное выражения сравнивает client.bool = (client.bool == "true") ? false : true;
Хотя Вы можете работать непосредственно со свойствами объекта
Как отмечено ранее, Вы не можете сохранять ссылки на другие объекты в объекте if client.id == null
Здесь использована функция Уникальная Ссылка на Объект clientДля некоторых приложений может понадобиться сохранять
информацию, специфическую для пары клиент/приложение, в объектах В этих случаях Вам необходим способ уникально обратиться к паре клиент/приложение.
JavaScript имеет для этого две функции, При каждом вызове
Если Вы используете эту функцию и сохраняете ID в объекте Альтернативой может стать использование функции При использовании этих технологий
Если Вам нужен идентификатор и Вы используете серверную технологию, возможно,
понадобится использовать функцию
Создание Специального Объекта clientКак уже было сказано ранее, свойства предопределённого
объекта В этом разделе приведён пример создания такого объекта. Можете включить этот код как файл JavaScript в Ваше приложение. Затем в начале страницы, на которой нужно использовать этот объект, введите следующий оператор: var customClient = getCustomClient()
(Разумеется, можно использовать другое имя переменной.) Если это первая
страница, запрашивающая данный объект, метод
Этот код сохраняет массив всех специальных объектов Переменная Для удаления всех закончивших работу специальных объектов приложения вызовите следующую функцию: expireCustomClients()
Это всё, что нужно сделать! Если Вы используете этот код, предопределённые
объекты Вы можете специализировать класс путём изменения его методов
// Эта функция создаёт новый специальный объект client или запрашивает существующий. function getCustomClient() var timeout = 600; var customClientLock = getCustomClientLock(); else { customClient = new CustomClient(timeout); if ( deathRow != null ) // Функция для удаления старых специальных объектов client. // Не вызывайте эту функцию явно. // Не вызывайте эту функцию явно. // Конструктор класса CustomClient. Не вызывайте его явно. this.onInit = CustomClientMethod_onInit; client.customClientID = customClientID; customClients[customClientID] = this; // Если нужно специализировать, переопределите следующие две функции. function CustomClientMethod_onDestroy() Объект project
Объект В отличие от предыдущих релизов, в этом релизе машина
выполнения JavaScript не создаёт и не уничтожает объект JavaScript конструирует набор объектов СвойстваУ объекта Хороший пример свойства объекта Помните, что объект Совместное Использование Объекта project
Для каждого приложения имеется только один объект Для поддержания целостности данных Вы обязаны
гарантировать исключительный доступ к свойству объекта Объект server
Объект Машина выполнения JavaScript конструирует новый объект JavaScript конструирует объект СвойстваВ следующей таблице описаны свойства объекта
Таблица 6.2 Свойства объекта
|
| Свойство | Описание | Пример |
|---|---|---|
hostname | www.netscape.com:85 | |
host |
www.netscape.com | |
protocol |
http: | |
port |
85 | |
jsVersion | 3.0 WindowsNT |
Например, Вы можете использовать свойство jsVersion
для обусловливания возможностей на базе серверной платформы (или версии), на
которой приложение работает, как показано здесь:
if (server.jsVersion == "3.0 WindowsNT")
write ("Application is running on a Windows NT server.");
Помимо этих автоматически инициализируемых свойств, Вы можете создавать свойства
для хранения данных, совместно используемых многими приложениями. Свойства могут
иметь любой допустимый в JavaScript тип, включая ссылки на другие JavaScript-объекты.
Если Вы сохраняете ссылку на другой объект в объекте server,
машина выполнения не разрушает объект, на который ссылаются, по окончании
запроса, в ходе которого он (объект server) был создан. Объект остаётся
доступным для последующих запросов.
Как и случае с объектом project, объект server имеет
ограниченный период существования. Когда
web-сервер останавливается, объект server разрушается вместе со
всеми значениями свойств. Поэтому, если у Вас имеются данные приложения, которые
нужно сохранять постоянно, их необходимо сохранять в БД (см. Часть 3, "LiveWire Database Service") или в
файле на сервере (см. "Служба Файловой Системы").
Для всего сервера имеется один объект server. Таким образом, код,
выполняемый в любом запросе, в любом приложении, может иметь доступ к одному и
тому же объекту server. Поскольку сервер является многопоточным,
могут иметься несколько запросов в данный момент времени. Для поддержания целостности данных Вы обязаны
гарантировать исключительный доступ к объекту server при внесении изменений.
Также Вы обязаны гарантировать, что имеется исключительный доступ к свойству объекта
server, когда изменяется значение этого свойства. Неявной
блокировки, как это было в предыдущих релизах, теперь нет; Вы обязаны
запрашивать исключительный доступ. Легче всего сделать это через использование
методов lock и unlock
объекта server. См. раздел "Безопасное
Совместное Использование Объектов с Помощью Блокировки".
Объект client ассоциирован как с определённым приложением, так и с
определённым клиентом. Как было сказано в разделе "Объект client",
машина выполнения создаёт новый объект
client всякий раз при поступлении нового запроса от клиента к
серверу. Однако целью является сохранение свойств объекта client от
одного запроса до следующего. Для этого машине выполнения нужно сохранить
свойства объекта client между запросами.
Есть два основных подхода при работе со свойствами объекта
client: можно работать с ними на стороне клиента или на сервере.
Эти два вида клиентской техники либо сохраняют имена свойств и их значения
непосредственно в куках на клиенте, либо в URLs на генерируемой HTML-странице.
Все три вида серверной техники сохраняют имена свойств и их значения в структуре
данных в памяти сервера, но различаются по используемой для индексирования
структуры этих данных схеме.
Вид техники выбирается, когда Вы используете JavaScript Application Manager
для инсталяции или модификации приложения, как указано в разделе
"Установка Нового Приложения". Это даёт Вам
(или менеджеру сайта) возможность изменять технику обслуживания без
перекомпилирования приложения. Однако поведение Вашего приложения может меняться
в зависимости от действующей техники обслуживания объекта
client, как описано в следующих разделах. Обязательно объясните
Вашему менеджеру сайта, от какого вида техники зависит работа Вашего приложения.
Иначе менеджер может изменить эти установки и нарушить работу Вашего приложения.
Поскольку некоторые виды этой техники сохраняют информацию в структуре данных на сервере или в куки-файле на клиенте, машина выполнения JavaScript дополнительно должна определять, когда избавиться от этих свойств. В разделе "Период Существования Объекта client" рассматривается, как машина выполнения определяет это, и описываются методы, которые можно использовать для изменения этого поведения.
Каждый вид техники имеет свои преимущества и недостатки, и то, что является недостатком в одной ситуации, может оказаться преимуществом в другой. Вам необходимо выбрать вид техники, наиболее подходящей для Вашего приложения. Виды техники описаны более детально в последующих разделах; в этом разделе даётся общее сравнение.
В таблице выполнено общее сравнение клиентской и серверной техники.
На Рисунке 6.3 и на Рисунке 6.4 видно, какая информация хранится при использовании каждого вида техники, где она хранится и передаётся ли по сети. На Рисунке 6.3 дана информация для клиентской техники.

На Рисунке 6.4 дана информация для серверной техники.

Имеются некоторые общие для видов (серверной и клиентской) техники вопросы. Для обоих типов техники, использующих куки, браузер обязан поддерживать протокол Netscape cookie protocol. В обоих случаях, когда браузер на клиентской машине закрывается, информация сохраняется в cookie-файле на клиентской машине. В других случаях ограничений нет.
Техника серверных кук создаёт единственную куку для
идентификации соответствующего объекта
client. В противоположность этому, техника клиентских кук создаёт
отдельную куку для каждого свойства объекта client. На технику
клиентских кук, следовательно, скорее повлияет ограничение в 20 кук на приложение.
В технике клиентских кук свойства объекта client высылаются
клиенту, когда высылается первая часть HTML-страницы. Если Вы изменяете позднее
значения свойств объекта client при выполнении действий на странице,
эти изменения не отсылаются клиенту и теряются. Это ограничение не действует для другой техники.
Для обеих техник, использующих кодирование в URL, если Ваше приложение
конструирует URL на этапе выполнения или использует функцию redirect,
необходимо либо вручную присоединять свойства объекта client,
которые должны быть сохранены, либо использовать addClient, чтобы
машина выполнения присоединила эти свойства.
Хотя присоединение свойств не является обязательным для других техник, Вам может
понадобиться сделать это, чтобы изменение техники не нарушило работу Вашего приложения.
Кроме того, при использовании техник кодирования URL, как только браузер
перейдёт на страницу за пределами приложения или даже отправит форму приложению
с использованием метода GET, все свойства объекта
client будут утеряны. Свойства не теряются в такой ситуации для других видов техники.
Ваш выбор техники частично определяется тем, должны ли существовать свойства
объекта client в такой ситуации.
Ваш выбор используемой техники опирается на требования Вашего приложения. Техника клиентских кук не использует дополнительной памяти сервера (как при серверной технике) и высылает информацию только один раз для страницы (в противоположность клиентской технике кодирования URL). Эти факты могут сделать использование техники клиентских кук предпочтительным для больших Internet-приложений. Однако в некоторых случаях другая техника может оказаться более подходящей. Например, серверный IP-адрес работает быстрее, не увеличивая сетевого трафика. Можно использовать это для приложений Вашей Intranet, для которых скорость работы является критичной.
Есть два вида клиентской техники:
Сравнение этих видов техники см. в разделе "Сравнение Видов Техники Обслуживания Объекта сlient".
Когда приложение использует клиентские виды техники,
машина выполнения кодирует свойства объекта client в ответ на
клиентский запрос в шапке/header ответа (для клиентской куки) или в URLs в теле
ответа (для клиентского кодирования URL).
Поскольку реальные имена и значения свойств пересылаются между клиентом и сервером, рестарт сервера не вызывает потери клиентской информации. Однако отправка этой информации вызывает увеличение сетевого трафика.
В технике клиентских кук машина выполнения JavaScript
на сервере использует протокол Netscape cookie protocol для передачи клиенту свойств объекта
client и их значений. Она создаёт по одной куке для каждого
свойства объекта client. Свойства высылаются клиенту один раз в шапке/header ответа
генерируемой HTML-страницы. Netscape cookie protocol описан в книге
Клиентский JavaScript.
Руководство.
Для исключения конфликтов с другими куками, которые Вы
можете создать в Вашем приложении, машина выполнения создаёт имя куки, добавляя
NETSCAPE_LIVEWIRE. перед началом имени свойства объекта client.
Например, если client имеет свойство custID, машина выполнения
создаёт куку под названием NETSCAPE_LIVEWIRE.custID. Когда
информация куки высылается клиенту,
машина выполнения делает всё необходимое кодирование специальных символов в
значении свойства, как описано в книге
Клиентский JavaScript.
Руководство.
Иногда Вашему приложению может понадобиться взаимодействие операторов JavaScript
на сервере и на стороне клиента. Поскольку это вид техники высылает клиенту
свойства объекта client как куки, Вы можете использовать это как
способ облегчить это взаимодействие. См. дополнительно "Взаимодействие
Между Сервером и Клиентом".
При использовании этой техники машина выполнения сохраняет
свойства объекта client, когда она в первый раз очищает внутренний
буфер, содержащий сгенерированную HTML-страницу. Исходя из этого,
для того чтобы предотвратить потерю любой информации, Вы должны как можно раньше
присвоить значения всем свойствам объекта client в скриптах на
каждой странице. В особенности Вы должны гарантировать, что свойства объекта client
будут высылаться перед тем как (1) машина выполнения сгенерирует 64KB
содержимого HTML-страницы (она автоматически очищает буфер вывода в этой точке), (2)
Вы вызовете функцию flush для очистки буфера вывода или (3) Вы
вызовете функцию redirect для изменения клиентских запросов.
Дополнительно см. разделы "Очистка Буфера Вывода" и
"Процессинг Времени Выполнения на Сервере".
По умолчанию, когда Вы используете технику клиентских кук, машина выполнения не
устанавливает явно время окончания срока действия кук. В этом случае куки
заканчивают работать, когда пользователь закрывает браузер. (Это поведение по
умолчанию для всех кук.) Как указано в разделе "Период
Существования Объекта client", Вы можете использовать метод expiration
объекта client для изменения срока окончания действия. Если Вы
используете client.expiration, машина выполнения устанавливает
соответствующий срок окончания работы куки в cookie-файле.
При использовании техники клиентских кук метод client.destroy
уничтожает все значения свойств объекта client, но не влияет на то,
что хранится в cookie-файле на клиентской машине. Не используйте для удаления
кук из cookie-файла или памяти браузера метод
client.destroy; вместо него используйте client.expiration с аргументом 0 секунд.
В целом Netscape-куки имеют нижеследующие ограничения. Эти
ограничения применяются тогда, когда Вы используете куки для хранения свойств объекта client:
client.client, объект
client может хранить максимум 20 свойств. Если Вы хотите
использовать в Вашем приложении также и другие куки, общее их количество всё
равно ограничено числом 20.При использовании техники клиентского кодирования URL
машина выполнения на сервере пересылает клиенту свойства и значения объекта client,
присоединяя их к каждому URL в генерируемой HTML-странице. Соответственно
свойства и их значения пересылаются столько раз, сколько имеется гиперссылок на
генерируемой HTML-странице, что приводит к значительному увеличению сетевого трафика.
Размер строки URL ограничен 4KB. Следовательно, когда Вы используете клиентское кодирование URL, общий размер имён свойств и их значений не может превышать 4KB. Любая информация свыше лимита 4KB будет усекаться.
Если Вы генерируете URLs динамически или используете функцию
redirect, Вы можете добавлять свойства объекта client
или другие свойства к URL. Когда Вы вызываете redirect или генерируете URL, компилятор не
присоединяет автоматически свойства объекта client. Если
присоединение необходимо, используйте функцию addClient. См. раздел
"Присоединение Свойств Объекта client к URL Вручную".
В технике клиентского кодирования URL значения свойств добавляются к URL по мере обработки этих URL. Нужно следить, чтобы Ваши URL имели одинаковые свойства и значения. Например, рассмотрим код:
<SERVER>
...
client.numwrites = 2;
write (addClient(
"<A HREF='page2.htm'>Some link</A>"));
client.numwrites = 3;
write (addClient(
"<A HREF='page3.htm'>Another link</A>"));
...
</SERVER>
Когда машина выполнения обрабатывает первый оператор
write, она использует 2 как значение свойства numwrites,
а при обработке второго оператора write она использует в качестве значения 3.
Итак, если Вы используете метод client.destroy в
середине страницы, только ссылки, шедшие на странице до вызова этого метода
получат значения, присоединённые к URL. Те же, которые идут после вызова этого
метода, не имеют присоединённых значений. Следовательно, значения свойств
объекта client передаются на некоторые страницы, но не на все. Это может быть нежелательно.
Если страница имеет ссылку на URL за пределами Вашего
приложения, Вам не понадобится присоединять клиентский статус. Тогда не
используйте статическую строку в качестве значения HREF.
Вместо этого вычисляйте значение. Это предотвратит автоматическое присоединение
машиной выполнения клиентского статуса к URL. Например, у вас имеется ссылка:
<A HREF="mailto:me@royalairways.com">
Машина выполнения присоединяет свойства объекта client. Чтобы этого
не происходило, используйте очень похожую ссылку:
<A HREF=`"mailto:me@royalairways.com"`>
При этой технике объект client не перестаёт действовать,
поскольку существует только в URL-строке, находящейся на клиенте. Следовательно,
метод client.expiration не производит никаких действий.
При клиентском кодировании URL Вы теряете все свойства
объекта client, когда отправляете форму, используя метод GET,
и когда выполняете доступ к другому приложению. Ещё раз - Вам может быть нужно
или не нужно терять эти свойства, в зависимости от потребностей Вашего приложения.
В отличие от техники клиентских кук, клиентское кодирование URL не требует ни поддержки web-браузером протокола Netscape cookie, ни записи информации на клиентской машине.
Есть три вида серверной техники:
Сравнение разных видов техники см. в разделе "Сравнение Видов Техники Обслуживания Объекта сlient".
При любом виде техники машина выполнения на сервере
сохраняет свойства объекта client и их значения в структуре данных
в памяти сервера. Единая структура данных, сохраняемая в период между
клиентскими запросами, используется для всех приложений, работающих на сервере.
Виды техники различаются только в индексе, используемом для доступа к информации
в этой структуре данных, гарантируя, что каждая пара клиент/приложение получает
соответствующие свойства и значения для объекта client.
Ни одна из этих техник не записывает информацию на жёсткий диск сервера. Только техника серверных кук позволяет записывать информацию на диск клиентской машины при окончании работы браузера.
Поскольку эти виды техники сохраняют информацию
объектов client в памяти сервера в промежутке между клиентскими
запросами, нет или почти нет увеличения сетевого трафика. Имена и значения
свойств никогда не пересылаются клиенту. Кроме того нет ограничения на
количество свойств объекта client и на размер свойства.
Недостатком является, разумеется, то, что эти виды техники используют память сервера в промежутке между клиентскими запросами. Для приложений, используемых большим количеством потребителей, это может иметь важное значение. Конечно, это можно также рассматривать и как преимущество, так как Вы можете сохранять столько информации, сколько необходимо.
Техника с использованием IP-адреса индексирует структуру данных на основе IP-адресов приложения и клиента. Эта простая техника является также и самой быстрой, поскольку вообще не требует отправки информации клиенту. Так как индекс базируется на IP-адресах приложения и клиента, эта техника создаёт отдельный индекс для каждой пары приложение/клиент, работающей на сервере.
Эта техника хорошо работает, когда все клиенты имеют фиксированные IP-адреса. Она работает ненадёжно, если клиент не имеет гарантированно фиксированного IP-адреса, например, если клиент использует протокол Dynamic Host Configuration Protocol (DHCP) или провайдера Internet, который динамически размещает IP-адреса. Эта техника также не работает у клиентов, использующих прокси-сервер, поскольку все пользователи прокси сообщают один и тот же IP-адрес. Поэтому данная техника используется в основном только для приложений Intranet.
Техника серверных кук использует длинное уникальное имя,
генерируемое машиной выполнения для индексации структуры данных на сервере.
Машина выполнения использует протокол Netscape cookie для хранения генерируемого
имени как куки/cookie на клиенте. Она не сохраняет имена и значения свойств как
куки. Поэтому данная техника создаёт одну куку, в то время как клиентская
техника кук создаёт отдельную куку для каждого свойства объекта client.
Сгенерированное имя отсылается клиенту только один раз в
шапке/header HTML-страницы. Вы можете получить доступ к этому имени через
функцию ssjs_getClientID, описанную в разделе
"Уникальное Обращение к Объекту client". Эта техника
использует тот же самый cookie-файл, что и техника клиентских кук; эти виды
техники отличаются тем, что информация сохраняется в cookie-файле. Протокол Netscape cookie protocol описан в книге
Клиентский JavaScript.
Руководство.
Итак, поскольку клиенту отсылается только генерируемое
имя, а не реальные имена и значения свойств, не имеет значения, где на Вашей
странице изменяются свойства объекта client. Это контрастирует с техникой клиентских кук.
По умолчанию машина выполнения устанавливает период
действия серверной структуры данных в 10 минут и не устанавливает срок действия
кук, отправляемых клиенту. Как указано в разделе "Период
Существования Объекта client", Вы можете использовать метод expiratio
объекта client для изменения срока действия и для установки периода
действия куки.
При использовании серверной куки метод client.destroy
уничтожает все значения свойств объекта client.
В общем, Netscape-куки имеют ограничения, перечисленные в разделе "Использование Клиентских Кук". Если Вы используете серверные куки, эти ограничения вряд ли будут достигнуты, так как создаётся только одна кука (содержащая индекс).
Это быстрая техника, не имеющая встроенных ограничений на количество и размер свойств и их значений. Вы больше ограничены тем, сколько пространства будете использовать на Вашем сервере для хранения этой информации.
Техника серверного кодирования URL использует длинное
уникальное имя, генерируемое машиной выполнения для индексации структуры данных
на сервере. В этом случае, вместо того чтобы сделать это генерируемое имя
клиентской кукой, сервер присоединяет имя к каждому URL на генерируемой HTML-странице.
Следовательно, имя высылается столько раз, сколько имеется ссылок на
генерируемой HTML-странице. (Имена и значения свойств не присоединяются к URLs, только генерируемое имя.)
Ещё раз: Вы можете получить доступ к этому генерируемому имени с помощью функции ssjs_getClientID,
описанной в разделе "Уникальное Обращение к Объекту client".
Если Вы генерируете URLs динамически или используете функцию redirect,
Вы можете добавлять свойства к
URL. Поэтому, когда Вы вызываете redirect или генерируете URL,
компилятор не присоединяет индекс автоматически. Если Вы хотите оставить индекс
для свойств объекта client, используйте функцию addClient.
См. также "Присоединение Свойств Объекта client к URL Вручную".
Если Ваша страница имеет ссылку на URL вне Вашего приложения, Вам может и не
понадобиться присоединение клиентского индекса. Тогда не используйте статическую
строку как значение атрибута HREF. Вместо этого вычисляйте это
значение. Это предотвратит автоматическое присоединение машиной выполнения
клиентского индекса к URL. Например, у Вас имеется ссылка:
<A HREF="mailto:me@royalairways.com">
В это случае машина выполнения присоединит индекс объекта client.
Чтобы этого не происходило, используйте очень похожую ссылку:
<A HREF=`"mailto:me@royalairways.com"`>
При серверном кодировании URL вы теряете идентификатор объекта client (и,
соответственно, свойства и их значения)
при отправке формы с методом GET. Вы можете терять или не терять
эти свойств, в зависимости от потребностей Вашего приложения.
После того как клиент получил доступ к приложению, не
гарантируется, будет он далее запрашивать продолжение обработки или продолжит
выполнение до логического конца. В связи с этим объект client не
имеет встроенного механизма окончания строка действия. Этот механизм позволяет
JavaScript периодически "зачищать" старые объекты client, которые
больше не нужны. Каждый раз, при получении сервером запроса на страницу
приложения, JavaScript восстанавливает период существования объекта client.
По умолчанию поведение механизма срока действия
значений варьируется и зависит от вида используемой техники работы с объектом client,
как видно из таблицы.
client
на основе вида используемой техникиПриложение может управлять периодом ожидания JavaScript
перед зачисткой свойств объекта client. Для изменения величины
этого периода используйте метод
expiration, как в следующем примере:
client.expiration(30);
В ответ на это вызов машина выполнения зачищает свойства объекта client
по прошествии 30 секунд. Для серверной техники этот вызов заставит сервер удалить
свойства объекта из структур данных через 30 секунд. Для этих двух видов техники
такой вызов устанавливает окончание срока действия через 30 секунд.
Если объект client перестаёт действовать, когда имеется активный
клиентский запрос с использованием этого объекта,
машина выполнения ждёт окончания этого запроса, прежде чем уничтожить объект client.
Вы обязаны вызывать expiration на каждой
странице, срок окончания действия которой хотите специфицировать. Страницы, не
специфицирующие срок действия, используют поведение по умолчанию.
Приложение может явно уничтожать объект client методом destroy:
client.destroy();
Когда приложение вызывает destroy, JavaScript удаляет все свойства из объекта
client.
Если Вы используете технику клиентских кук для работы с
объектом client, метод destroy уничтожает все значения
свойств объекта client, но не влияет на то, что хранится в
клиентском cookie-файле. Чтобы удалить и значения свойств из этого cookie-файла,
не используйте метод destroy; вместо него используйте expiration с аргументом 0 секунд.
Если Вы используете технику клиентского кодирования URL для работы с объектом
client, метод destroy удаляет все свойства объекта client.
Ссылки на странице до вызова destroy оставляют свойства объекта client
в своих URL, а ссылки, расположенные после вызова метода, не имеют свойств.
Поскольку маловероятно, что Вам понадобится, чтобы только некоторые URL
страницы содержали свойства объекта client, Вы, вероятно, должны
будете вызывать
destroy либо вверху, либо внизу страницы, когда используете работу
с клиентскими URL. См. также "Использование Клиентского Кодирования URL".
При использовании кодирования URL на клиенте или на
сервере для работы с объектом client машина выполнения обычно
должна сохранять соответствующую информацию (имена и значения свойств объекта client
или индекс серверной структуры данных) во всех
URL, высылаемых клиенту, вне зависимости от того, являются ли эти URL как
статический HTML или были сгенерированы операторами серверного JavaScript.
Машина выполнения автоматически присоединяет
соответствующую информацию к гиперссылкам HTML, находящимся вне тэгов SERVER.
Так, например, предположим, что Ваша HTML-страница содержит следующие операторы:
<HTML>
For more information, contact
<A HREF="http://royalairways.com/contact_info.html">
Royal Airways</a>
...
</HTML>
Если приложение использует кодирование URL для объекта client,
машина выполнения автоматически присоединит client -информацию в
конец URL. Вы не должны ничего делать специально для поддержки этого поведения.
Однако ваше приложение может использовать функцию
write для динамической генерации оператора HTML, содержащего URL.
Вы можете также использовать функцию redirect для старта нового
запроса. Когда Вы используете операторы серверного JavaScript
для добавления URL к генерируемой HTML-странице, машина выполнения предполагает,
что Вы специфицировали полный URL для отправки в нужном Вам виде. Она не
присоединяет автоматически клиентскую информацию даже при использовании
кодирования URL для работы с объектом client. Если Вам нужно
присоединить клиентскую информацию,
Вы обязаны сделать это сами.
Вы используете функцию addClient для
добавления вручную соответствующей client -информации. Эта функция
принимает URL и возвращает новый URL
с присоединённой информацией. Например, предположим, что контактный URL
варьируется в зависимости от значения свойства client.contact.
Вместо вышеприведённого HTML Вы можете ввести следующее:
<HTML>
For more information, contact
<server>
if (client.contact == "VIP") {
write ("<A HREF='http://royalairways.com/vip_contact_info.html'>");
write ("Royal Airways VIP Contact</a>");
}
else {
write ("<A HREF='http://royalairways.com/contact_info.html'>");
write ("Royal Airways</a>");
}
</server>
...
</HTML>
Теперь машина выполнения не присоединяет свойства объекта client
к URL. Если Вы используете один из видов техники кодирования URL для работы с
объектом client, может возникнуть проблема. Тогда, если Вы хотите
отправить свойства объекта client с этим URL, используйте такой код:
<HTML>
For more information, contact
<server>
if (client.contact == "VIP") {
write (addClient(
"<A HREF='http://royalairways.com/vip_contact_info.html'>"));
write ("Royal Airways VIP Contact</a>");
}
else {
write (addClient(
"<A HREF='http://royalairways.com/contact_info.html'>"));
write ("Royal Airways</a>");
}
</server>
...
</HTML>
Также всякий раз, когда Вы применяете функцию redirect
для перенаправления клиентского запроса, Вы должны использовать addClient
для присоединения информации, как здесь:
redirect(addClient("mypage.html"));
В противоположность этому, если Ваша страница имеет ссылку на URL вне Вашего
приложения, Вам может не понадобиться присоединение клиентской информации.
Тогда не используйте статическую строку в значении атрибута HREF.
Вместо этого вычисляйте значение. Это предотвратит автоматическое присоединение
машиной выполнения клиентского индекса или свойств к URL. Например, у вас имеется ссылка:
<A HREF="mailto:me@royalairways.com">
В этом случае машина выполнения присоединяет клиентскую информацию. Чтобы этого не было, используйте очень похожую ссылку:
<A HREF=`"mailto:me@royalairways.com"`>
Хотя приложение первоначально инсталировано для
использования техники без кодирования
URL для работы с client, оно может быть позднее модифицировано для использования техники кодирования URL.
Следовательно, если Ваше приложение генерирует динамические URL или использует redirect,
Вам всегда нужно будет использовать addClient.
Рабочая среда для версии 3.x или 4.x Netscape-сервера является многопоточной; то есть она обрабатывает более одного запроса в единицу времени. Поскольку эти запросы могут требовать выполнения JavaScript, то более чем один поток выполнения JavaScript может быть активным в одно и то же время.
Если несколько потоков одновременно пытаются изменить свойство одного и того же объекта JavaScript, они могут привести этот объект в несоответствующее состояние. Участок кода, в котором необходимо выполнять один, и только один, поток выполнения в единицу времени, называется критическим разделом/сritical section.
Один объект server используется совместно
всеми клиентами и всеми приложениями, работающими на сервере. Один объект project
используется всеми клиентами, получающими доступ к одному приложению
на сервере. Кроме того, Ваше приложение может создавать другие объекты, которые
оно предоставляет в совместное пользование клиентским запросам, или оно даже может
совместно с другими приложениями использовать объекты. Для поддержания
целостности данных в этих совместно используемых объектах Вы обязаны получить
исключительный доступ к объекту, прежде чем изменять любое его свойство.
В отличие от предыдущих релизов, неявная блокировка объектов
projectиserverтеперь отсутствует.
Чтобы лучше понять, что происходит, рассмотрим следующий
пример. Предположим, Вы создаёте совместно используемый объект project.orders
для отслеживания заказов пользователей. Вы обновляете
project.orders.count каждый раз при получении нового заказа, используя следующий код:
var x = project.orders.count;
x = x + 1;
project.orders.count = x;
Предположим, что project.orders.count
первоначально установлено в 1 и что поступили два новых заказа в двух разных потоках.
Произойдёт следующее:
project.orders.count в переменной x.x.x.project.orders.count
в 2.project.orders.count изменилось, и также устанавливает 2 в х.Итак, конечное значение project.orders.count
будет 2, хотя корректным должно быть 3.
Чтобы избежать проблем такого рода, Вам нужно получить
исключительный доступ к свойствам совместно используемых объектов перед тем как
записывать в них. Для этих целей Вы можете конструировать Ваши собственные
экземпляры класса
Lock, работающие с любым совместно используемым объектом. Кроме
того, объекты
server и project имеют методы lock и unlock,
которые Вы можете использовать для ограничения доступа к этим объектам.
Представьте lock (замок/блокировку) как именованный флаг, который Вы обязаны устанавливать перед входом в критичный раздел. Если Вы запрашиваете именованный флаг и кто-то уже имеет его, Вы будете ждать, пока этот второй не освободит флаг. В процессе ожидания Вы не сможете изменять то, что не должны изменять. После получения Вами флага кто-либо ещё будет ожидать и не сможет ничего изменить, пока Вы не освободите флаг. Если возникнет ошибка или таймаут закончится до того, как Вы получите флаг, Вы можете снова вернуться в режим ожидания, либо делать что-нибудь другое, как, например, дать Вашим пользователям знать, что приложение очень занято, чтобы выполнить данную операцию сейчас. Вы не должны вмешиваться в процесс ожидания (изменяя совместно используемую информацию)! Рисунок 6.5 иллюстрирует этот процесс.

В терминах программирования замок/lock представлен
экземпляром класса Lock. Вы можете использовать экземпляр класса Lock
для получения исключительного доступа к любому совместно используемому объекту.
Обычно Вы создаёте экземпляры Lock на начальной странице Вашего
приложения (по причинам, которые будет изложены позднее).
На других страницах, перед критичным для совместно используемого объекта разделом (например,
перед разделом, который запрашивает и изменяет значение свойства), Вы вызываете
метод lock экземпляра Lock. Если этот метод возвращает true,
Вы получаете замок и можете продолжать. В конце критичного раздела Вы вызываете
метод unlock Lock -экземпляра.
Когда клиентский запрос в одиночном потоке выполнения
вызывает метод lock, любой другой запрос, вызывающий метод lock
для того же Lock -экземпляра, ожидает, пока первый поток не вызовет метод unlock,
пока не закончится таймаут или пока не возникнет ошибка. Это верно независимо от
того, находится второй запрос в другом потоке для того же клиента или в потоке для другого клиента.
Если все потоки вызывают метод lock перед попыткой изменения
совместно используемого объекта, то лишь один поток в единицу времени может войти в критичный раздел.
Использование замков находится всецело под управлением разработчика и требует кооперации. Машина выполнения не заставляет Вас ни вызывать
lock, ни учитывать блокировку, полученную кем-либо другим. Если Вы не спрашиваете, Вы можете изменять всё что захотите. Поэтому очень важно выработать привычку всегда вызыватьlockиunlockпри входе и выходе из критичного раздела кода и проверять return-значение методаlock, чтобы гарантировать, что блокировка получена. Можно представлять это в терминах флага: если Вы не запрашиваете флаг, вы не будете находиться в режиме ожидания. Если Вы не находитесь в режиме ожидания, Вы можете изменять то, что изменять нельзя.
Вы можете создать столько замков, сколько Вам необходимо. Один и тот же замок может использоваться для управления доступом к нескольким объектам, либо каждый объект (или даже каждое свойство) может иметь собственный замок.
Замок/lock сам по себе является просто объектом JavaScript;
Вы можете сохранить ссылку на него в любом другом объекте JavaScript. Таким
образом, например, обычной практикой является конструирование экземпляра Lock
и сохранение его в объекте project.
ПРИМЕЧАНИЕ:
Поскольку использование замка блокирует доступ других пользователей к именованному флагу, потенциально задерживая выполнение их задач, хорошей практикой станет использование замков в течение возможно более короткого периода.
Следующий код показывает, как отследить заказы
потребителей в совместно используемом объекте project.orders,
рассмотренном ранее, и как обновлять
project.orders.count каждый раз при получении нового заказа.
Включите в начальную страницу приложения такой код:
// Создать новый Lock и сохранить в project.
project.ordersLock = new Lock();
if (! project.ordersLock.isValid()) {
// Невозможно создать Lock. Перенаправить на страницу обработки ошибок.
redirect ("sysfailure.htm");
}
Этот код создаёт экземпляр класса Lock и проверяет (вызовом метода isValid),
не возвращено ли что-нибудь неправильное при его создании. Очень редко Ваш
экземпляр Lock конструируется неправильно. Это случается только
тогда, когда машина выполнения запущена вне системных ресурсов при создании объекта.
Вы обычно создаёте экземпляры Lock на
начальной странице, поэтому Вам не нужно получать замок перед созданием
экземпляров Lock. Начальная страница запускается только один раз -
при старте приложения на сервере. Поэтому Вам гарантируется, что создаётся только один экземпляр каждого замка.
Если, однако, Ваше приложение создаёт замок на какой-либо иной странице,
множественные запросы могут вызывать эту страницу в это время. Один запрос может
проверять наличие замка и не обнаружить его, в то время как другой запрос
создаёт замок, а третий запрос создаёт второй замок. Тем временем первый запрос
вызывает метод lock своего объекта. Затем второй запрос вызывает
метод lock своего объекта. Оба запроса теперь "думают", что они
имеют безопасный доступ к критичному разделу кода и продолжают свою работу, нарушая работу другого.
После получения верного замка Ваше приложение может продолжать работу. На странице, требующей доступа к критичному разделу, можете ввести такой код:
// Начало критичного раздела -- получить замок.
if ( project.ordersLock.lock() ) {
var x = project.orders.count;
x = x + 1;
project.orders.count = x;
// Конец критичного раздела -- освободить замок.
project.ordersLock.unlock();
}
else
redirect("combacklater.htm");
Этот код запрашивает замок. Если замок получен (то есть, если метод lock возвратил
true), выполняется вход в критичный раздел, вносятся изменения и, наконец, замок освобождается.
Если метод lock возвращает false, то данный код не
получает замка. В этом случае приложение перенаправляет на страницу, которая
сообщает, что приложение в данный момент не может выполнить запрос.
Каждый из объектов project и server
имеет методы lock и unlock. Вы можете использовать эти методы для
получения исключительного доступа к свойствам этих объектов.
В этих методах ничего нового нет.
Вам также необходима кооперация с другими участками кода. Вы можете представлять
эти методы как имеющие флаги: один флаг с именем "project", а другой - флаг с
именем "server." Если другой раздел кода не вызывает
project.lock, первый может изменять любые свойства объекта project.
В отличие от метода lock класса Lock,
Вы не можете специфицировать таймаут для метода lock объектов project
и server. То есть, когда Вы вызываете project.lock,
система ожидает бесконечно долго освобождения замка. Если Вы хотите ожидать
только в течение определённого периода, используйте экземпляр класса Lock.
В примере использованы методы
lock и unlock для получения исключительного доступа к
объекту project для модификации свойства ID потребителя:
project.lock()
project.next_id = 1 + project.next_id;
client.id = project.next_id;
project.unlock();
Вы используете замки для защиты критичных участков кода. На практике это означает, что один запрос ожидает, пока другой выполняет критичный код. Вы обязаны соблюдать осторожность при использовании замков для защиты критичных разделов. Если один запрос ожидает освобождения замка, полученного другим запросом, а этот второй запрос ожидает освобождения замка, полученного первым запросом, ни один из запросов не сможет продолжить работу. Эта ситуация называется deadlock/тупик/мертвая блокировка.
Рассмотрим предыдущий пример обработки заказов потребителей. Предположим, что приложение разрешает два действия. В одном - пользователь вводит нового потребителя; в другом - пользователь вводит новый заказ. Как часть создания нового потребителя приложение также создаёт новый заказ потребителя. Это действие выполняется на одной странице приложения, давая примерно такой код:
// Создать нового потребителя (customer).
if ( project.customersLock.lock() ) {
var id = project.customers.ID;
id = id + 1;
project.customers.ID = id;
// Стартовать новый заказ (order) для этого нового потребителя.
if ( project.ordersLock.lock() ) {
var c = project.orders.count;
c = c + 1;
project.orders.count = c;
project.ordersLock.unlock();
}
project.customersLock.unlock();
}
Во втором типе действия пользователь вводит новый заказ потребителя. Как часть процесса ввода нового заказа: если потребитель ещё не является зарегистрированным потребителем, приложение создаёт нового потребителя. Это действие выполняется на другой странице приложения, где может быть примерно такой код:
// Стартовать новый заказ.
if ( project.ordersLock.lock() ) {
var c = project.orders.count;
c = c + 1;
project.orders.count = c;
if (...код определения неизвестного потребителя...) {
// Создать нового потребителя.
// Этот внутренний замок может вызвать проблемы!
if ( project.customersLock.lock() ) {
var id = project.customers.ID;
id = id + 1;
project.customers.ID = id;
project.customersLock.unlock();
}
}
project.ordersLock.unlock();
}
Заметьте, что каждый из этих фрагментов кода пытается получить второй замок, уже
получив один. Это может вызвать проблемы. Предположим, что один поток начинает
создание нового потребителя; он получает замок
customersLock. В это же самое время другой поток начинает создание
нового заказа; он получает замок ordersLock. Теперь первый поток
запрашивает замок ordersLock. Поскольку второй поток уже получил
этот замок, первый поток должен ждать. Предположим, однако, что второй поток
теперь запрашивает замок customersLock. Первый поток уже имеет этот
замок, поэтому второй поток должен ждать. Теперь потоки ждут друг друга.
Поскольку никто их них не специфицировал таймаут, оба они будут ждать бесконечно.
В данном случае проблему можно легко устранить. Поскольку значения ID потребителя и номер заказа не зависят один от другого, нет никакого смысла вкладывать замки друг в друга. Вы можете избежать возможных тупиков, переписав оба фрагмента кода. Перепишите первый фрагмент так:
// Создать нового потребителя.
if ( project.customersLock.lock() ) {
var id = project.customers.ID;
id = id + 1;
project.customers.ID = id;
project.customersLock.unlock();
}
// Стартовать новый заказ для этого нового потребителя.
if ( project.ordersLock.lock() ) {
var c = project.orders.count;
c = c + 1;
project.orders.count = c;
project.ordersLock.unlock();
}
Второй фрагмент будет примерно таким:
// Стартовать новый заказ.
if ( project.ordersLock.lock() ) {
var c = project.orders.count;
c = c + 1;
project.orders.count = c;
project.ordersLock.unlock();
}
if (...код для определения неизвестного потребителя...) {
// Создать нового потребителя.
if ( project.customersLock.lock() ) {
var id = project.customers.ID;
id = id + 1;
project.customers.ID = id;
project.customersLock.unlock();
}
}
Хотя это и надуманная ситуация, тупики это совершенно реальная проблема, и они могут произойти во многих случаях. Для этого даже не понадобится более одного замка или более одного запроса. Рассмотрим код, в котором две функции запрашивают один и тот же замок:
function fn1 () {
if ( project.lock() ) {
// ... какие-то действия ...
project.unlock();
}
}
function fn2 () {
if ( project.lock() ) {
// ... какие-то другие действия ...
project.unlock();
}
}
Сам по себе этот код не содержит проблем. Позднее слегка измените его, чтобы fn1
вызывала fn2, уже имея замок, как показано далее:
function fn1 () {
if ( project.lock() ) {
// ... какие-то действия ...
fn2();
project.unlock();
}
}
Вот вы и получили тупик/deadlock. Это, конечно, немного смешно, когда единственный запрос ожидает от самого себя освобождения флага!
Дата последнего обновления: 29 сентября 1999 г.
© Copyright © 1999 Sun Microsystems, Inc. Некоторая часть Copyright © 1999 Netscape Communications Corp. Все Права Зарезервированы.
| Содержание сайта (выборка) |
| Apache |
| Протоколы TCP/IP (принципы, протоколы и архитектура) |
| PHP, PELR, JSP |
| PHP |
| JavaServer Pages (JSP) |
| Базы данных |
| Основы mysql |
| СУБД INFORMIX |
| СУБД POSTGRES |
| Основы проектирования реляционных баз данных |
| Паскаль, C, C++, C# |
| GCC (примеры) |
| FAQ Валентинa Озеровa DELPHI |
| C |