JavaScript. Подробное руководство, 6-е издание, стр. 178

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

)

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

<b>setTimeout()</b>
и
<b>setlnterval(),</b>
для запуска подзадач в фоновом режиме с одновременным обновлением индикатора хода вычислений, предоставляющего обратную связь с пользователем.

Стандарт HTML5 определяет управляемую форму параллельного выполнения - механизм фонового потока выполнения под названием «web worker». Web worker - это фоновый поток выполнения, предназначенный для выполнения продолжительных вычислений и предотвращения блокирования пользовательского интерфейса. Программный код, выполняемый в фоновом потоке web worker, не имеет доступа к содержимому документа, к информации, используемой главным потоком выполнения или другими потоками web worker, и может взаимодействовать с главным потоком и другими фоновыми потоками только посредством асинхронных событий. Благодаря этому параллельное выполнение не оказывает влияния на главный поток, а фоновые потоки не меняют базовую однопоточную модель выполнения JavaScript-программ. Подробнее о фоновых потоках выполнения рассказывается в разделе 22.4.

13.3.4. Последовательность выполнения клиентских сценариев

Мы уже знаем, что выполнение JavaScript-программ начинается с этапа выполнения сценариев и затем переходит к этапу выполнения, управляемому событиями.

Этот раздел более подробно описывает последовательность выполнения JavaScript-программ.

1. Веб-броузер создает объект

<b>Document</b>
и начинает разбор веб-страницы, добавляя в документ объекты
<b>Element</b>
и текстовые узлы в ходе синтаксического анализа HTML-элементов и их текстового содержимого. На этой стадии свойство
<b>document.readyState</b>
получает значение
<b>«loading»</b>
.

2. Когда механизм синтаксического анализа HTML встречает элементы

<b>&lt;script&gt;,</b>
не имеющие атрибута
<b>async</b>
и/или
<b>defer</b>
, он добавляет эти элементы в документ и затем выполняет встроенные или внешние сценарии. Эти сценарии выполняются синхронно, а на время, пока сценарий загружается (если это необходимо) и выполняется, синтаксический анализ документа приостанавливается. Такие сценарии могут использовать метод
<b>document.write()</b>
для вставки текста во входной поток. Этот текст станет частью документа, когда синтаксический анализ продолжится. Синхронные сценарии часто просто определяют функции и регистрируют обработчики событий для последующего использования, но они могут исследовать и изменять дерево документа, доступное на момент их запуска. То есть синхронные сценарии могут видеть собственный элемент
<b>&lt;script&gt;</b>
и содержимое документа перед ним.

3. Когда механизм синтаксического анализа встречает элемент

<b>&lt;script&gt;,</b>
имеющий атрибут
<b>async</b>
, он начинает загрузку сценария и продолжает разбор документа. Сценарий будет выполнен сразу же по окончании его загрузки, но синтаксический анализ документа не приостанавливается на время загрузки сценария. Асинхронные сценарии не должны использовать метод
<b>document.write().</b>
Они могут видеть собственный элемент
<b>&lt;script&gt;,</b>
все элементы документа, предшествующие ему и, возможно, дополнительное содержимое документа.

4. По окончании анализа документа значение свойства

<b>document.readyState</b>
изменяется на «
<b>interactive</b>
».

5. Выполняются все сценарии, имеющие атрибут

<b>defer</b>
, в том порядке, в каком они встречаются в документе. В этот момент также могут выполняться асинхронные сценарии. Отложенные сценарии имеют доступ к полному дереву документа и не должны использовать метод
<b>document.write()</b>
.

6. Броузер возбуждает событие

<b>«DOMContentLoaded»</b>
в объекте
<b>Document</b>
. Это событие отмечает переход от этапа синхронного выполнения сценариев к управляемому событиями асинхронному этапу выполнения программы. Следует, однако, отметить, в этот период также могут выполняться асинхронные сценарии, которые не были еще выполнены.

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

<b>document.readyState</b>
получит значение
<b>«complete»</b>
и веб-броузер возбудит событие
<b>«load»</b>
в объекте
<b>Window</b>
.

8. С этого момента будут асинхронно вызываться обработчики событий в ответ на действия пользователя, сетевые операции, истечение таймера и т. д.

Это идеализированная последовательность выполнения, и не все броузеры придерживаются ее в точности. Событие

<b>«load»</b>
поддерживается повсеместно: его возбуждают все броузеры, и оно является универсальным инструментом определения момента окончания загрузки документа и его готовности к выполнению операций. Событие
<b>«DOMContentLoaded»</b>
возбуждается перед событием
<b>«load»</b>
и поддерживается всеми текущими броузерами, кроме IE. Свойство
<b>document.readyState</b>
реализовано в большинстве текущих броузеров на момент написания этих строк, но значения, которые получает это свойство, отличаются между броузерами. Атрибут
<b>defer</b>
поддерживается всеми современными версиями IE, но только недавно был реализован в других броузерах. Поддержка атрибута
<b>async</b>
до сих пор не получила широкого распространения, но асинхронное выполнение сценариев с использованием приема, представленного в примере 13.4, поддерживается всеми текущими броузерами. (Однако имейте в виду, что возможность динамической загрузки сценариев с помощью функции, такой как
<b>loadasync(),</b>
размывает границы между этапом загрузки сценариев и этапом выполнения программы, управляемым событиями.)