Как javascript взаимодействует с html
Перейти к содержимому

Как javascript взаимодействует с html

  • автор:

JavaScript

JavaScript — предназначен для написания сценариев для активных HTML-страниц. Язык JavaScript не имеет никакого отношения к языку Java. Java разработан фирмой SUN. JavaScript — фирмой Netscape Communication Corporation. Первоначальное название — LiveScript. После завоевания языком Java всемирной известности LiveScript из коммерческих соображений переименовали в JavaScript.

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

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

Тег <script>

Сценарий JavaScript встраивается в HTML-документ с помощью тега <script>.

Пример

Текст сценария оформляется как комментарий, чтобы не было проблем у посетителей, брaузеры которых не понимают JavaScript. Кроме того к символам, завершающим комментарий добавляется еще два символа «/«, т.к. некоторые браузеры рассматривает строку, состоящую только из символов «—>«, как ошибочную.

В первом примере для объекта с именем document вызывается метод write. В качестве параметра ему передается текстовая строка «Привет!». Строка закрывается символом «;«, которым отделяются друг от друга все операторы JavaScript.

Объект document – это HTML-документ, загруженный в окно брaузера. Метод write записывает в тело HTML-документа строку «Привет!». При этом документ будет выгдядеть так, как будто эта строка находится в нем на месте сценария.

Для указания что скрипт вынесен в отдельный файл используется следующий код:

Для ускорения загрузки страницы можно разрешить браузеру загружать скрипты паралельно с остальным кодом. Для указания паралельной неблокирующей загрузки скриптов используется атрибут async=»async» или defer=»defer» :

В обоих случаях скрипты, помеченные как async или defer, начинают незамедлительно скачиваться, не вызывая при этом остановок парсера, причем оба скрипта поддерживают onload обработчик, позволяющий вызвать те или иные события, когда скрипт будет загружен. Каждый скрипт, помеченный async, будет выполнен в тот момент, когда для это появится возможность после его полной загрузки, но до того как будет выброшено событие о загрузке window. Это означает, что такие скрипты скорее всего будут выполнены не в том порядке, в котором они указаны на странице. А вот наличие defer скриптов гарантирует, что как они указаны, так они и будут загружаться. Их выполнение начнется после завершения работы парсера, но до появления события DOMContentLoaded.

Будьте внимательны и осторожны при неблокирующей загрузке, т.к. использовать функции из такого js-файла можно только после полной загрузки DOM-модели и всех скриптов. Т.к. браузер, если это позволит сервер, будет кешировать загружаемые внешние файлы, то при первом вызове функции будут доступны только после полной загрузки, а при обновлении страницы, т.к. браузер возьмет файл из кеша — сразу. И отлавить такую ошибку будет непросто.

Можно сокращать написание:

Имейте в виду, что JavaScript различает строчные и прописные буквы. Кроме того символ дефиса в JavaScript распознается как минус, т.е. если фон объекта в HTML-документе задается через свойство background-color, то в JavaScript — через backgroundColor.

Пример

Цвет фона объекта меняется с белого на красный при наведении на объект мыши:

Переменные в JavaScript

Имя переменной не должно совпадать с зарезервированными ключевыми словами JavaScript: abstract, boolean, break, byte, case, catch, char, class, const, continue, default, do, double, else, extends, false, final, finally, float, for, function, goto, if, implements, import, in, instanseof, int, interface, long, native, new, null, package, private, protected, public, return, short, static, super, sinchronized, switch, this, throw, throws, transient, true, try, typeof, var, void, wich.

Все переменные в JavaScript объявляются с помощью ключевого слова var. При объявлении тип переменной не указывается. Этот тип присваивается переменной только тогда, когда ей присваивается какое-либо значение.

  • Числа.
  • Логические значения. Могут принимать значение true и false.
  • Строки. Последовательность символов, заключенная в одинарные или в двойные кавычки. Строка, ограниченная одинарными кавычками может содержать двойные кавычки, а строка, ограниченная двойными кавычками, может содержать одинарные кавычки.

Для определения типа переменной можно использовать typeof,

document.write — используется для вывода результата в текущей поток вывода браузера.

Для проверки существования переменной можно использовать одну из следующих конструкций:

В современном javascript лучше писать:

Использовать просто if(var) нельзя, так как доступ к неопределенной переменной вызовет ошибку. В некоторых источниках рекомендуют использовать if(window.var), но так проверять тоже нельзя, т.к. переменная может быть, но иметь значение false.

Число преобразуется в строку автоматически. Например:

В строку можно вставить специальные символы:

\’ Одинарная кавычка
\” Двойная кавычка
\\ Обратная косая черта
\n Переход на новую строку
\r Возврат каретки
\t Табуляция

Для преобразования строк в числа используют специальные функции parseInt и parseFloat.

Пример
Примеры использования простейших преобразований типов:

Конвертирование в даты (new Date(myVar)) и регулярные выражения (new RegExp(myVar)) нужно делать с использованием конструкторов. Для создания регулярных выражений используйте структуру: /регулярное_выражение/флаги .

Операторы языка JavaScript

Операторы JavaScript напоминают общеизвестные операторы языка С++.

Унарные операторы

Изменение знака на противоположный
! Дополнение. Используется для реверсирования значения логических переменных
++ Увеличение значения переменной. Может применяться и как префикс, и как суффикс
Уменьшение значения переменной. Может применяться и как префикс, и как суффикс

Бинарные операторы

Вычитание
+ Сложение
* Умножение
/ Деление
% Остаток от деления

Операторы для работы с отдельными битами

Операторы сдвига

>> Сдвиг вправо
<< Сдвиг влево
>>> Сдвиг вправо с заполнением освобождаемых разрядов нулями

Операторы отношения

> Больше
>= Больше или равно
< Меньше
<= Меньше или равно
== Равно
!= Не равно

В условных операторах также применяются логические операторы: || (ИЛИ) и && (И).

Оператор присваивания и его комбинации

Допускается комбинирование оператора присваивания с другими, как и в языке С.

= Присваивание
+= Сложение или слияние строк (n=n+7; аналог. n+=7;)
–= Вычитание (n=n-7; аналог. n-=7;)
*= Умножение
/= Деление
>>= Сдвиг вправо
<<= Сдвиг влево
>>>= Сдвиг вправо с заполнением освобождаемых разрядов нулями
&= И
|= ИЛИ
^= ИСКЛЮЧАЮЩЕЕ ИЛИ

Условные операторы

В языке JavaScript два условных оператора: if-else и ?:.

Пример оператора if-else
Пример «скрипт приветствия (по времени суток)»
Пример оператора ?:
Пример оператора switch — case:

Операторы цикла

В языке JavaScript три оператора цикла: for, for-in, while.

Пример оператора for
Пример оператора for-in
Пример использования оператора while, continue, break

Кроме этих операторов в организации цикла могут участвовать еще два оператора: break (выход из цикла) и continue (переход на следующий шаг).

Прочие операторы

. Доступ к полю объекта. ( document.write(Buf); )
[ ] Индексирование массива ( dim[i] )
( ) Изменение порядка вычислений или передача параметров функции
, Разделение выражений в многократном вычислении
Пример оператора «запятая»
Неявное преобразование типов

Встроенные функции JavaScript

Функции JavaScript

Все функции JavaScript рекомендуется помещать в контейнер <HEAD>. </HEAD>. Тем самым вы обеспечите их гарантированную доступность при обработке HTML-документа.

Пример

Объекты JavaScript

Язык JavaScript является объектно-ориентированным. Объекты JavaScript представляют собой наборы свойств и методов. Можно сказать, что свойства объектов — это данные, связанные с объектом, а методы — функции для обработки данных объекта.

В языке JavaScript имеется три вида объектов: встроенные объекты, объекты брaузера и объекты, создаваемые программистом.

JavaScript поддерживает следующий набор встроенных объектов: Array, Boolean, Date, Global, Function, Math, Number, String.

Встроенный объект Array. Массивы в JavaScript

Массив в JavaScript является экземпляром встроенного объекта Array. Нумерация элементов в массиве начинается с нуля. Создать массив можно следующими способами:

a1 — массив, в котором нет ни одного элемента.

a2 — массив из трех элементов с неопределенным (undefined) значением.

a3 — массив, заданный списком своих элементов.

Число элементов в массиве можно изменить, просто задав значение соответствующего элемента:

Типы данных элементов массива в JavaScript могут быть различными:

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

Для создания многомерного массива каждому элементу массива нужно присвоить другой массив:

Так можно создать массив, состоящий из трех строк и трех столбцов.

Это все числовые массивы. Также существуют и ассоциативные массивы:

Свойства объекта Array

  • length. Число элементов массива.

Методы объекта Array

  • push( ). добавляюет значение с конца массива
  • pop( ). вынимает значение с конца массива
  • shift( ). добавляюет значение с начала массива
  • unshift ( ). вынимает значение с начала массива. shift/unshift обычно приводят к перенумерации всего массива. shift сдвигает все элементы на единицу влево, а unshift — вправо. Поэтому на больших массивах эти методы работают медленнее, чем push/pop.
  • concat( ). Слияние двух массивов. Через параметр передается имя второго массива: c=a.concat(b);
    Здесь элементы массива b добавляются к элементам массива a . Чтобы преобразовать строку в массив используется метод split объекта String:
  • reverse( ). Меняет порядок элементов массива на обратный.
  • slice(begin[, end]). Возвращает подмассив с индексами begin…end. При этом элемент массива с конечным индексом в результат не войдет. Следует помнить, что индексы отсчитываются от нуля.
  • splice(index, deleteCount[, element1,…, elementN]) Удалить deleteCount элементов, начиная с index, и вставить на их место element1…elementN
  • sort( fn ). Сортирует массив. Если функция не передана, то все элементы сортируются как строки. Вместо 0,6,18,24,25, он сортирует 0,18,24,25,6. Для сотрировки числового массива используйте следущий вариант:
  • toString( ) — преобразует элементы массива в строку, используя в качестве символа-разделителя запятую.
  • indexOf(искомый_элемент, индекс), lastIndexOf(искомый_элемент, индекс) — возвращает индекс элемента, значение которого равно значению, переданному методу в качестве аргумента. Первый аргумент метода указывает значение элемента, индекс которого нужно найти, второй аргумент (необязательный), указывает индекс с которого будет начинаться поиск. Если одинаковых вхождений несколько, выбирается наименьший (первый) индекс. Если элемент с искомым значением не найден, метод вернет -1. Внутри метода для поиска используется строгое сравнение ( === ) lastIndexOf() — ищет с конца.
  • forEach(callback, thisArg) — callback-функция, которую метод forEach() будет вызывать для каждого элемента массива, должна иметь три параметра: первый параметр принимает в качестве аргумента — значение элемента массива, второй — индекс элемента, и третий — сам массив. Однако, если нужно использовать только значения элементов массива, можно написать функцию только с одним параметром. Второй аргумент — thisArg (необязательный) будет передан в качестве значения this
  • filter(callback, thisObject) — возвращает новый массив, который будет содержать только те элементы массива, для которых вызов функции callback возвратит true.
  • map(callback) — возвращает новый массив, который будет состоять из результатов вызова функции callback(item, idx, ar) для каждого элемента массива.
  • every(callback) — возвращает true, если для всех элементов массива указанная функция, используемая для их проверки, вернет true.
  • some(callback) — возвращает true, если во время проверки в указанной функции один или несколько элементов вернут true.
  • reduce(callback, initialValue), reduceRight(callback, initialValue) — применяет указанную функцию (callback) в отношении сразу двух значений в массиве, перебирая элементы слева направо, сохраняя при этом промежуточный результат. Аргументы функции callback: (previousValue, currentItem, index, array)
    previousValue — возвращаемый результат callback функции (он же промежуточный результат)
    currentItem — текущий элемент массива (элементы перебираются по очереди слева-направо)
    index — индекс текущего элемента
    array — обрабатываемый массив
    initialValue (инициализирующее значение) — объект, используемый в качестве первого аргумента первого вызова функции callback. Проще говоря, значение previousValue при первом вызове равно initialValue. Если initialValue нет, то оно равно первому элементу массива, а перебор начинается со второго

delete — Удалить элемент ассоциативного массива,

Для обхода ассоциативного массива используется следующий цикл:

Встроенный объект Date

С помощью методов встроенного объекта Date можно выполнять различные действия с часами компьютера. Для использования большинства методов объекта Date необходимо создать экземпляр этого объекта:

Методы объекта Date

  • getYear. Возвращает год:
    var nYear = today.getYear();
  • getMonth. Возвращает номер месяца:
    var nMonth = today.getMonth(); Имейте в виду, что январь — это 0, февраль — 1 и т.д.
  • getDate. Возвращает значение календарной даты в диапазоне от 1 до 31:
    var nDate = today.getDate();
  • getDay. Возвращает номер дня недели (для воскресенья — 0, для понедельника — 1 и т.д.):
    var nDay = today.getDay();
  • getHours. Возвращает количество часов, прошедших после полуночи:
    var nHours = today.getHours();
  • getMinutes. Возвращает количество минут, прошедших с начала часа:
    var nMinutes = today.getMinutes();
  • getSeconds. Возвращает количество секунд, прошедших с начала минуты:
    var nSeconds = today.getSeconds();
  • getTime. Возвращает количество миллисекунд, прошедших с 00 часов 00 минут 1 января 1970 года:
    var nMillisec = today.getTime();
  • getTimeZoneOffset. Возвращает смещение локального времени относительно времени по Гринвичу в миллисекундах:
    var nOffsetMillisec = today.getTimeZoneOffset();
  • parse. Возвращает количество миллисекунд, прошедших с 00 часов 00 минут 1 января 1970 года по время, указанное в параметре функции. Для вызова этого метода можно просто сослаться на имя класса Date , а создавать объект класса Date не надо:
    var nMS = Date.parse(prm);
    Параметр prm может принимать значения: локальные дата и время («21 Apr 2001 18:00:00»); дата и время по Гринвичу («21 Apr 2001 14:00:00 GMT»); дата и время по Гринвичу cо смещением («21 Apr 2001 18:00:00 GMT+0400») .
  • UTC. Преобразовывает дату, заданную параметрами метода, в количество миллисекунд, прошедших с 00 часов 00 минут 1 января 1970 года. Для вызова этого метода, так же как и метода parse можно просто сослаться на имя класса Date:
    var nMSec = Date.UTC(year, month, date, hours, min, sec, ms);
    Имейте в виду, что январь — это 0, февраль — 1 и т.д.
  • setYear. Устанавливает год в объекте класса Date:
    today.setYear(nYear);
  • setMonth. Устанавливает номер месяца:
    today.setMonth(nMonth);
  • setDate. Устанавливает значение календарной даты в диапазоне от 1 до 31:
    today.setDate(nDate);
  • setDay. Устанавливает номер дня недели (для воскресенья — 0, для понедельника — 1 и т.д.):
    today.setDay(nDay);
  • setHours. Устанавливает количество часов, прошедших после полуночи:
    today.setHours(nHours);
  • setMinutes. Устанавливает количество минут, прошедших с начала часа:
    today.setMinutes(nMinutes);
  • setSeconds. Устанавливает количество секунд, прошедших с начала минуты:
    today.setSeconds(nSeconds);
  • setTime. Устанавливает дату, соответствующую количеству миллисекунд, прошедших с 00 часов 00 минут 1 января 1970 года:
    var nMillisec = today.setTime();
  • toGMTString. Преобразует дату в строку, записанную в стандартном формате времени по Гринвичу:
    «Sat, 21 Apr 2001 14:00:00 GMT»
  • toLocaleString. Преобразует дату в строку, записанную в стандартном формате локального времени:
    «04/16/2001 18:00:00» .

Объекты брaузера

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

Практически в любом сценарии JavaScript необходимы такие объекты, как окно — window и документ — document.

Свойства объекта window

  • name. Имя окна, указанное при его открытии методом open, а также в атрибуте TARGET тега <A> или в атрибуте NAME тега <FORM> .
  • self, window. Синонимы имени окна. Относятся к текущему окну.
  • top. Синоним имени окна. Относится к окну верхнего уровня.
  • parent. Синоним имени окна. Относится к окну, содержащему набор фреймов.
  • frames. Массив всех фреймов данного окна.
  • length. Количество фреймов в родительском окне.
  • status. Текущее сообщение, отображаемое в строке состояния окна брaузера.

Методы объекта window

  • alert. Отображение диалоговой панели Alert с сообщением и кнопкой OK. Через параметр передается сообщение, отображаемое в диалоговой панели. После вызова этого метода выполнение сценария задерживается до тех пор, пока посетитель не нажмет кнопку OK, расположенную в диалоговой панели.
Пример
  • confirm. Отображение диалоговой панели Confirm с кнопками OK и Отмена. В зависимости от того, какая кнопка будет нажата, метод возвращает соответственно значение true или false .
Пример
  • prompt. Отображение диалоговой панели Prompt с полем ввода и кнопками OK и Отмена. В зависимости от того, какая кнопка будет нажата, метод возвращает соответственно введенную строку или значение null . Метод имеет два параметра. Первый — сообщение над полем ввода. Второй (необязательный) — начальное значение строки ввода.
Пример
  • open. Открытие окна. Метод имеет три параметра. Первый задает URL HTML-документа, предназначенного для загрузки в новое окно. Второй определяет имя окна для использования в атрибуте TARGET тега <A> или в атрибуте NAME тега <FORM>. Третий (необязательный) задает в виде текстовой строки параметры, определяющие внешний вид открываемого окна.
Пример
  • close. Закрытие созданного или основного окна:
    newWindow.close();
    Текущее окно брaузера можно закрыть одним из следующих способов:
    window.close(); self.close();
  • setTimeout. Установка таймера. Применяется для ограничения времени ввода пароля, создания бегущих строк и всевозможных анимационных эффектов. Метод имеет два параметра. Первый задает выражение JavaScript, которое запускается по прошествии времени, указанного вторым параметром в миллисекундах. Заданное выражение запускается один раз.
Пример
  • clearTimeout. Сброс таймера. Для останова таймера метод setTimeout нужно вызвать с возвратом идентификатора, т.е.
    idTimer=setTimeout(«change()», 2000);
    а затем этот идентификатор передать методу clearTimeout в качестве параметра:
    clearTimeout(idTimer);
  • setInterval(prm1,prm2). Установка периодического таймера. Метод имеет два параметра. задает выражение JavaScript, которое периодически запускается по прошествии времени, указанного вторым параметром в миллисекундах.
  • clearInterval(prm). Сброс таймера, установленного методом setInterval. Для сброса таймера метод setInterval нужно вызвать с возвратом идентификатора, т.е. idTimer=setInterval(”change()”, 2000); а затем этот идентификатор передать методу clearTimeout в качестве параметра: clearInterval(idTimer);
Пример
  • blur( ). При вызове метода окно теряет фокус.
  • focus( ). При вызове метода окно получает фокус.
  • MoveTo(x,y). Перемещает окно в точку с координатами.
  • MoveBy(x,y). Перемещает окно на x пикселей по горизонтали вправо и на y пикселей вниз.
  • ResizeTo(x,y). Изменяет размер окна на указанные.
  • ResizeBy(x,y). Увеличивает или уменьшает размер окна на заданное количество пикселей.
  • print( ). Печать документа. Вызывает окно выбора параметров печати.
  • scroll(x,y), ScrollTo(x,y). Прокручивает окно так, что точка с кординатами x,y становится левой верхней точкой окна.
  • ScrollBy(x,y). Прокручивает окно на x,y пикселей.
  • stop( ). Прекращает загрузку документа в окно браузера.

Свойства объекта document

  • URL. Полный URL документа.
  • location. Полный URL документа.
  • referrer. URL вызывающего документа.
  • title. Заголовок документа, определенный тегом <TITLE> .
  • bgColor. Цвет фона документа.
  • fgColor. Цвет текста.
  • linkColor. Цвет cсылок.
  • alinkColor. Цвет выбранных cсылок.
  • vlinkColor. Цвет посещенных cсылок.
  • links. Массив всех cсылок в документе.
  • anchors. Массив локальных меток. Применяется для организации ссылок внутри документа.
  • applets. Массив аплетов Java.
  • forms. Массив форм в виде объектов.
  • images. Массив растровых изображений.
  • embeds. Массив объектов plug-in.
  • lastModified. Дата последнего изменения документа.
  • cookie. Значение cookie для текущего документа.
Пример

Объект document может содержать в себе другие объекты, доступные как свойства:

  • anchor. Локальная метка, определенная тегом <A> .
  • form. Форма, определенная тегом <FORM> .
  • history. Список посещенных URL.
  • link. Текст или изображение, играющие роль гипертекстовой ссылки, созданной тегом <A> , в котором дополнительно заданы обработчики событий onClick и onMouseOver .

Методы объекта document

  • сlear. Удаление содержимого документа из окна просмотра.
  • write. Запись в документ произвольной HTML-конструкции.
  • writeln. Аналогичен write, но с добавлением символа перевода строки в конец строки.
  • open. Открытие выходного потока для записи в HTML-документ данных типа MIME при помощи методов write и writeln.
  • close. Закрытие потока данных, открытого методом open. В окне будут отображены все изменения содержимого документа, сделанные сценарием после открытия потока.
  • getElementById(a) Получить объект по его ID
  • getElementsByTagName(tag) Получить массив объектов по имени тега

Ссылки в документе

Для каждой ссылки, размещенной в HTML-документе, создается отдельный объект. Все такие объекты находятся в объекте document как элементы массива links . Анализируя эти элементы, сценарий JavaScript может определить свойства каждой ссылки в HTML-документе:

  • length. Количество ссылок в HTML-документе, т.е. количество элементов в массиве links .
  • hash. Имя локальной ссылки, если она определена в URL.
  • host. Имя узла и порт, указанные в URL.
  • hostname. Имя узла и доменное имя узла сети. Если доменное имя недоступно, вместо него указывается адрес IP.
  • href. Полный URL.
  • pathname. Путь к объекту, указанный в URL.
  • port. Номер порта, использумого для передачи данных с сервером, указанным в ссылке.
  • protocol. Строка названия протокола передачи данных (включающая символ «двоеточие»), указанного в ссылке.
  • search. Строка запроса, указанная в URL после символа «?».
  • target. Имя окна, куда будет загружен документ при выполнении ссылки. Это может быть имя существующего окна фрейма, определенного тегом <FRAMESET> , или одно из зарезервированных имен — _top, _parent, _self, _blank.
Пример

Объект navigator

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

Изменение содержимого страницы

Одной из часто встречающихся при разработке веб-приложений задач, является возможность добавления или удаления элементов страницы. Свойство innerHTML для любого элемента веб-страницы возвращает строку, содержащую HTML-код, заключенный между открывающим и закрывающим тегами элемента. Свойство outerHTML — аналогичное свойству innerHTML, но содержит весь HTML-код, включая внешние открывающий и закрывающий теги элемента. innerHTML может использоваться для замены содержимого элемента после формирования страницы в отличие от document.write:

Аналогично можно изменять содержимое страницы используя DOM-модель html-документа:

  • appendChild — добавляет детёныша внутрь объекта
  • createTextNode — создает текстовый элемент
  • createElement — создает тег

Cookie

Cookie — это свойство HTML-документа. Представляет собой набор строковых параметров, каждый из которых имеет имя и значение. Сценарий JavaScript может создавать cookie для HTML-документа, определяя в нем произвольное количество параметров и задавая для них произвольные значения. После создания такой набор параметров становится принадлежностью данного конкретного HTML-документа и может быть проанализирован, изменен или удален сценарием JavaScript.

Создание cookie

В сценарии JavaScript cookie создается с помощью свойства document.cookie. Пары имя-значение не могут содержать пробелов, запятых и точек с запятыми. Поэтому все эти символы должны быть заменены на соответствующие escape-последовательности. JavaScript имеет две функции, обрабатывающие escape-последовательности: encodeURIComponent и decodeURIComponent.

Пара имя-значение является единственным необходимым параметром при создании cookie. Указание только пары имя-значение создает cookie, который сохраняется только на протяжении текущего сеанса брaузера. При создании cookie можно задать дату его автоматического удаления. В этой паре надо указать имя expires и значение в стандартном формате времени по Гринвичу (GMT). Простейшим способом преобразования в формат GMT является использование одного из методов встроенного класса Date: toGMTString. Кроме этого, создавая cookie, можно указать также путь (path), домен (domain) и информацию безопасности(secure). Извлечь эту информацию нельзя.

Удаление cookie

Самый простой способ удаления cookie — установить для него такое время автоматического удаления, которое уже прошло.

Практическое применение cookie

  • Индивидуальная настройки параметров Web-страниц.
  • Хранение товара, выбранного посетителем виртуального магазина. Можно выбрать товары на разных страницах, а потом сделать общий заказ.
  • Хранение текущего состояния сетевой игры.
Пример

Данные cookie позволяют собирать определенную статистическую информацию о посетителе, поэтому некоторые пользователи могут настраивать брaузеры на ограничение или полное отключение возможности работы с cookie.

Перехват и обработка событий

Старая схема перехвата события не подразумевала, что у события может быть несколько обработчиков:

Новая схема перехвата и обработки событий:

Вызов метода addEventListener() со строкой «click» в первом аргументе никак не влияет на значение свойства onclick. Во фрагменте, приведенном выше, щелчок на кнопке приведет к выводу двух диалоговых окон alert(). Но важнее то, что метод addEventListener() можно вызвать несколько раз и зарегистрировать с его помощью несколько функций-обработчиков для одного и того же типа события в том же самом объекте. При появлении события в объекте будут вызваны все обработчики, зарегистрированные для этого типа события, в порядке их регистрации.

Многократный вызов метода addEventListener() для одного и того же объекта с теми же самыми аргументами не дает никакого эффекта — функция-обработчик регистрируется только один раз и повторные вызовы не влияют на порядок вызова обработчиков.

Парным к методу addEventListener() является метод removeEventListener(), который принимает те же три аргумента, но не добавляет, а удаляет функцию-обработчик из объекта. Это часто бывает удобно, когда необходимо зарегистрировать временный обработчик события, а затем удалить его в какой-то момент.

Internet Explorer версии ниже IE9 не поддерживает методы addEventListener() и removeEventListener()

При вызове обработчика событий ему передается объект события в виде единственного аргумента. Свойства объекта события содержат дополнительную информацию о событии. Свойство type, например, определяет тип возникшего события. В IE версии 8 и ниже обработчикам событий, зарегистрированным установкой свойства, объект события при вызове не передается. Вместо этого объект события сохраняется в глобальной переменной window.event. Для переносимости обработчики событий можно оформлять, как показано ниже, чтобы они использовали переменную window.event при вызове без аргумента:

Объект события передается обработчикам событий, зарегистрированным с помощью метода attachEvent(), но они также могут использовать переменную window.event

Для отмены возникшего события и прекращения его всплытия используйте:

Name already in use

Код JavaScript на стороне клиента необходим для того, чтобы превратить статические HTML-документы в интерактивные веб-приложения. Содержимое окна браузера представлено объектом Document . Объект Document — это центральная часть большой библиотеки API-функций, называемой DOM (Document Object Model) и предназначенной для программного манипулирования содержимым документов.

  1. Нарисовать с помощью JS шахматную доску 10х10 на Canvas с бело-синими клетками
  2. При помощи JS сгенерировать таблицу, содержащую буквы русского алфавита
  3. Сгенерировать с помощью JS шахматную доску 8х8 при помощи таблицы с бело-зелёными клетками
  4. По нажатии на кнопку сгенерировать с помощью JS таблицу 10х10, заполненную числами от 1 до 100
  5. Сгенерировать с помощью JS шахматное поле 8х8 на div элементах

DOM (Document Object Model)

Согласно DOM-модели, документ является иерархией.

DOM

Объектная Модель Документа (DOM) – это программный интерфейс (API) для HTML и XML документов. DOM предоставляет структурированное представление документа и определяет то, как эта структура может быть доступна из программ, которые могут изменять содержимое, стиль и структуру документа. Представление DOM состоит из структурированной группы узлов и объектов, которые имеют свойства и методы. По существу, DOM соединяет веб-страницу с языками описания сценариев либо языками программирования.

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

Дерево DOM для кода, представленного выше, будет выглядеть следующим образом:

DOM Example

Корневым элементом иерархии является html . У него есть два потомка. Первый — head , второй — body . И так далее, каждый вложенный тег является потомком тега выше.

Теги образуют узлы-элементы (element node). Текст представлен текстовыми узлами (text node). И то и другое — равноправные узлы дерева DOM.

Без DOM язык JavaScript не имел бы никакой модели или представления о веб-странице, HTML-документе и их элементах. Каждый элемент в документе — весь документ в целом, заголовок, таблицы внутри документа, заголовки таблицы, текст внутри ячеек таблицы — это части объектной документной модели для этого документа, поэтому все они могут быть доступны и могут изменяться с помощью DOM и скриптового языка наподобие JavaScript.

Объект window представляет собой окно [браузера], содержащее DOM документ.

Для манипуляций с DOM используется объект document . Используя document , можно получать нужный элемент дерева и менять его содержание.

document.documentElement — самый верхний тег. В случае корректной HTML-страницы, это будет <html> .

document.body — тег <body> .

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

Все дочерние элементы, включая текстовые находятся в массиве childNodes .

Свойства firstChild и lastChild показывают на первый и последний дочерние элементы и равны null , если детей нет.

Свойство parentNode указывает на родителя. Например, для <body> таким элементом является <html> .

Свойства previousSibling и nextSibling указывают на левого и правого братьев узла.

У DOM-элементов есть масса свойств. Некоторые из них можно читать и устанавливать, другие — только читать.

  • tagName — имя тега в верхнем регистре, только для чтения;
  • style — Это свойство управляет стилем. Оно аналогично установке стиля в CSS. Есть общее правило замены — если CSS-атрибут имеет дефисы, то для установки style нужно заменить их на верхний регистр букв. Например, для установки свойства z-index в 1000, нужно поставить: element.style.zIndex = 1000 ;
  • innerHTML — содержит весь HTML-код внутри узла, и его можно менять. Свойство innerHTML применяется, в основном, для динамического изменения содержания страницы;
  • className — задает класс элемента. Оно полностью аналогично html-атрибуту class ;
  • onclick , onkeypress , onfocus — функции-обработчики соответствующих событий. Например, можно присвоить обработчик события onclick .

Выбор элементов документа

Обычно программа на JavaScript на стороне клиента решает свои задачи путем манипулирования одним или несколькими элементами документа. В модели DOM есть ряд способов выбора элемента:

  • по идентификатору (атрибут id );
  • по имени (атрибут name );
  • по имени тега;
  • по классу или классам CSS (атрибут class );
  • по соответствию заданому селектору CSS.

Выбор элемента по идентификатору

Каждый элемент HTML имеет атрибут id . Значение атрибута должно быть уникальным во всём документе. Выбрать элемент на основе уникального значения id можно с помощью метода getElementById() объекта Document .

Выбор элементов по имени

Атрибут name изначально был предназначен для присвоения имён элементам форм. Значение атрибута name используется при передаче данных формы на сервер. Как и атрибут id , атрибут name используется для присвоения имени элементу. Однако в отличие от id , значение атрибута name не обязательно должно быть уникальным. Кроме того, в отличие от атрибута id , атрибут name допустим только в подмножестве элементов HTML, в которое входят формы, элементы форм и элементы <iframe> и <img> .

Метод getElementsByName() возвращает объект NodeList , который работает как массив объектов Element , доступный только для чтения.

Также элементы можно выбирать по имени посредством свойств объекта Document , имеющих соответствующие имена. Например на основе кода HTML приведенного выше:

Выбор элементов по имени тега

Выбирать элементы можно также по их типу, имени тега (иногда пишут «по имени дескриптора») с помощью метода getElementsByTagName() объекта Document . Например, получить массивоподобный объект, содержащий все объекты Element всех элементов <span> , присутствующих в документе:

Метод getElementsByTagName() возвращает объект HTMLCollection . Элементы объекта HTMLCollection расположены в том же порядке, что и в документе. Например, первый элемент <p> можно получить следующим образом:

Метод getElementsByTagName() определен не только в классе Document , но и в классе Element . Это значит, что он может выбирать только элементы, являющиеся потомками элемента, через который вызван метод. Например, найти все элементы <span> , находящиеся в пермом элементе <p> :

Выбор элементов по классам CSS

Метод getElementsByClassName() возвращает массивоподобный (итерируемый) объект всех дочерних элементов, соответствующих всем из указанных имён классов.

Как и getElementsByTagName() , метод getElementsByClassName() можно вызывать либо через документ, либо через элемент.

Метод getElementsByClassName() возвращает текущую HTMLCollection найденных элементов. Будут возвращены толкько те элементы, в атрибуте class которых содержатся все имена классов, заданные при вызове метода.

Выбор элементов по селекторам CSS

С помощью метода querySelectorAll() объекта Document можно выбрать элементы, соответствующие селектору CSS, и возвращает объект NodeList , представляющий все элементы документа, соответствующие селектору. Но в отличие от описанных выше методов выбора элементов, метод querySelectorAll() возвращает не динамический объект NodeList , а статический. Это означает, что полученный таким образом объект NodeList содержит элементы, соответствующие селектору на момент вызова и не обновляемые при изменении документа.

Основные интерфейсы в DOM

  • document.createElement(name) — создает элемент c тем тегом, что указан в аргументе name .
  • parentNode.appendChild(node) — добавляет узел в конец списка дочерних элементов указанного родительского узла.
  • element.innerHTML — устанавливает или получает HTML разметку дочерних элементов.
  • element.style.left — используется для получения и установки инлайновых стилей
  • element.setAttribute(name, value) — добавляет новый атрибут или изменяет значение существующего атрибута у выбранного элемента.
  • element.getAttribute(attributeName) — возвращает значение указанного атрибута элемента.
  • EventTarget.addEventListener(type, listener) — регистрирует определенный обработчик события для EventTarget (Element, Document, Window или др.).
  • window.onload = functionRef — вызыает функцию functionRef, когда страница загрузится.
  • window.dump — выводит сообщение в консоль.
  • window.scrollTo — прокрутка документа до указанных координат.

Пример создания нового содержимого

Первый способ создания динамического содержимого

Формируем строку и выводим ее в контейнер при помощи свойства innerHTML.

Второй способ создания динамического содержимого

Более сложный пример:

Присваивание обработчиков событий элементам

При помощи метода getElementsByClassName() получаем коллекцию найденных элементов (объект HTMLCollection ) Используя свойство length и метод item() получаем доступ к индивидуальным элементам коллекции.

Метод querySelectorAll() возвращает NodeList , т.е. список всех найденных узлов. NodeList имеет метод forEach(func) , который выполняет указанную функцию func один раз для каждого элемента NodeList .

Использование JavaScript на веб-страницах

Клиентский JavaScript-код может встраиваться в HTML-документы четырьмя способами:

встроенные сценарии между парой тегов <script> и </script>;

из внешнего файла, заданного атрибутом src тега <script>;

в обработчик события, заданный в качестве значения HTML-атрибута, такого как onclick или onmouseover;

как тело URL-адреса, использующего специальный спецификатор псевдопротокола JavaScript:.

В следующих далее подразделах описываются все четыре способа встраивания программного кода на языке JavaScript. Следует отметить, что HTML-атрибуты обработчиков событий и адреса URL с псевдопротоколом javascript: редко используются в современной практике программирования на языке JavaScript (они были более распространены на раннем этапе развития Всемирной паутины).

Встроенные сценарии (в тегах <script> без атрибута src) также стали реже использоваться по сравнению с прошлым. Согласно философии программирования, известной как ненавязчивый JavaScript (unobtrusive JavaScript), содержимое (разметка HTML) и поведение (программный код на языке JavaScript) должны быть максимально отделены друг от друга. Следуя этой философии программирования, сценарии на языке JavaScript лучше встраивать в HTML-документы с помощью элементов <script>, имеющих атрибут src.

Элемент <script>

Клиентские JavaScript-сценарии могут встраиваться в HTML-файлы между тегами <script> и </script>:

В языке разметки XHTML содержимое тега <script> обрабатывается наравне с содержимым любого другого тега. Если JavaScript-код содержит символы поддерживает атрибут src, который определяет URL-адрес файла, содержащего JavaScript-код. Используется он следующим образом:

Файл JavaScript-кода обычно имеет расширение .js и содержит JavaScript-код в «чистом виде» без тегов <script> или любого другого HTML-кода.

Тег <script> с атрибутом src ведет себя точно так, как если бы содержимое указанного файла JavaScript-кода находилось непосредственно между тегами <script> и </script>. Обратите внимание, что закрывающий тег </script> обязателен, даже когда указан атрибут src и между тегами отсутствует JavaScript-код. В разметке XHTML в подобных случаях можно использовать единственный тег <script/>.

При использовании атрибута src любое содержимое между открывающим и закрывающим тегами <script> игнорируется. При желании в качестве содержимого в тег <script> можно вставлять описание включаемого программного кода или информацию об авторском праве. Однако следует заметить, что инструменты проверки соответствия разметки требованиям стандарта HTML5 будут выдавать предупреждения, если между тегами <script src=»»> и </script> будет находиться какой-либо текст, не являющийся пробельными символами или комментариями на языке JavaScript.

Использование тега с атрибутом src дает ряд преимуществ:

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

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

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

Атрибут src принимает в качестве значения произвольный URL-адрес, поэтому JavaScript-программа или веб-страница с одного веб-сервера может воспользоваться кодом (например, из библиотеки подпрограмм), предоставляемым другими веб-серверами. Многие рекламодатели в Интернете используют этот факт.

Возможность загружать сценарии с других сайтов еще больше увеличивает выгоды, получаемые от кэширования: компания Google продвигает использование стандартных, хорошо известных URL-адресов для часто используемых клиентских библиотек, что позволяет браузерам хранить в кэше единственную копию, совместно используемую многими сайтами в Веб. Привязка сценариев JavaScript к серверам компании Google может существенно уменьшить время запуска веб-страниц, поскольку библиотека наверняка уже будет храниться в кэше браузера пользователя, но при этом вы должны доверять стороннему программному коду, который может оказаться критически важным для вашего сайта. За дополнительной информацией обращайтесь по адресу: code.google.com/apis/ajaxlibs/.

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

Таким образом, политика общего происхождения в данном случае неприменима: JavaScript-код может взаимодействовать с документами, в которые он встраивается, даже если этот код получен из другого источника, нежели сам документ. Включая сценарий в свою веб-страницу с помощью атрибута src, вы предоставляете автору сценария (или веб-мастеру домена, откуда загружается сценарий) полный контроль над своей веб-страницей.

Обработчики событий в HTML

JavaScript-код, расположенный в теге <script>, исполняется один раз, когда содержащий его HTML-файл считывается в веб-браузер. Для обеспечения интерактивности программы на языке JavaScript должны определять обработчики событий — JavaScript-функции, которые регистрируются в веб-браузере и автоматически вызываются веб-браузером в ответ на определенные события (такие как ввод данных пользователем).

JavaScript-код может регистрировать обработчики событий, присваивая функции свойствам объектов Element (таким как onclick или onmouseover), представляющих HTML-элементы в документе.

Свойства обработчиков событий, такие как onclick, отражают HTML-атрибуты с теми же именами, что позволяет определять обработчики событий, помещая JavaScript-код в HTML-атрибуты. Например:

Обратите внимание на атрибут onClick. JavaScript-код, являющийся значением этого атрибута, будет выполняться всякий раз, когда пользователь будет щелкать на кнопке.

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

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

JavaScript в URL

Еще один способ выполнения JavaScript-кода на стороне клиента — включение этого кода в URL-адресе вслед за спецификатором псевдопротокола javascript:. Этот специальный тип протокола обозначает, что тело URL-адреса представляет собою произвольный JavaScript-код, который должен быть выполнен интерпретатором JavaScript. Он интерпретируется как единственная строка, и потому инструкции в ней должны быть отделены друг от друга точками с запятой, а для комментариев следует использовать комбинации символов /* */, а не //.

«Ресурсом», который определяется URL-адресом javascript:, является значение, возвращаемое этим программным кодом, преобразованное в строку. Если программный код возвращает значение undefined, считается, что ресурс не имеет содержимого.

URL вида javascript: можно использовать везде, где допускается указывать обычные URL: в атрибуте href тега <a>, в атрибуте action тега <form> и даже как аргумент метода, такого как window.open(). Например, адрес URL с программным кодом на языке JavaScript в гиперссылке может иметь такой вид:

Некоторые браузеры (такие как Firefox) выполняют программный код в URL и используют возвращаемое значение в качестве содержимого нового отображаемого документа. Точно так же, как при переходе по ссылке http:, браузер стирает текущий документ и отображает новое содержимое. Значение, возвращаемое примером выше, не содержит HTML-теги, но если бы они имелись, браузер мог бы отобразить их точно так же, как любой другой HTML-документ, загруженный в браузер.

Другие браузеры (такие как Chrome и Safari) не позволяют URL-адресам, как в примере выше, затирать содержимое документа — они просто игнорируют возвращаемое значение. Однако они поддерживают URL-адреса вида:

Когда загружается такой URL-адрес, браузер выполняет JavaScript-код, но, т.к. он не имеет возвращаемого значения (метод alert() возвращает значение undefined), такие браузеры, как Firefox, не затирают текущий отображаемый документ. (В данном случае URL-адрес javascript: служит той же цели, что и обработчик события onclick. Ссылку выше лучше было бы выразить как обработчик события onclick элемента <button> — элемент <a> в целом должен использоваться только для гиперссылок, которые загружают новые документы.)

Если необходимо гарантировать, что URL-адрес javascript: не затрет документ, можно с помощью оператора void обеспечить принудительный возврат значения undefined:

Без оператора void в этом URL-адресе значение, возвращаемое методом Window.open(), было бы преобразовано в строку и (в некоторых браузерах) текущий документ был бы затерт новым документом.

Подобно HTML-атрибутам обработчиков событий, URL-адреса javascript: являются пережитком раннего периода развития Веб и не должны использоваться в современных HTML-страницах. URL-адреса javascript: могут сослужить полезную службу, если использовать их вне контекста HTML-документов. Если потребуется проверить работу небольшого фрагмента JavaScript-кода, можно ввести URL-адрес javascript: непосредственно в адресную строку браузера. Другое узаконенное применение URL-адресов javascript: — создание закладок в браузерах.

Как работают браузеры. Часть 2: парсинг и выполнение JS

В прошлой статье мы обсудили навигацию и получение данных. Сегодня поговорим о HTML- и CSS-парсинге и выполнении JavaScript.

1. HTML-Парсинг

Мы видели, как после первоначального запроса к серверу браузер получает ответ c HTML-ресурсами страницы, к которой мы пытаемся получить доступ. Это первая порция данных. Теперь задача браузера – начать парсинг данных.

Парсинг

��Анализ и преобразование программы во внутренний формат, который может запустить среда выполнения.

Другими словами, это получение HTML/CSS-кода и преобразование его в то, с чем браузер может работать. Парсинг выполняется движком браузера (не путать с движком JavaScript).

Браузерные движки

Движок браузера — основной компонент каждого крупного браузера. Его основная роль — объединить структуру (HTML) и стиль (CSS), чтобы отобразить страницу на экране. Он также отвечает за выяснение того, какие фрагменты кода интерактивны. Не думайте о нем как об отдельном ПО. Скорее, это часть более крупного ПО — в нашем случае, браузера.

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

Gecko. Разработан компанией Mozilla для браузера Firefox. Кроме него, сейчас движок Gecko используют ещё в Tor и Waterfox. Написан на C++ и Rust.

WebKit. В основном его разработала компания Apple для Safari. На нем также работают браузеры GNOME Web (Epiphany) и Otter. Интересно, что все браузеры на iOS, включая Firefox и Chrome, работают на WebKit. Он написан на C++.

Blink, часть Chromium. Разрабатывает компания Google на основе кода WebKit для браузера Chrome. На нем также работают браузеры Edge, Brave, Silk, Vivaldi, Opera и большинство других проектов браузеров, некоторые через QtWebEngine. Написан на C++.

С этим понятно. Теперь посмотрим, что произойдет после получения первого HTML-документа с сервера. Предположим, документ выглядит так:

Даже если HTML-код страницы запроса больше исходного пакета 14 КБ, браузер начнет парсинг и попытается отобразить результат на основе имеющихся данных.

HTML-парсинг включает два этапа: токенизацию и построение DOM-дерева. Document Object Model – объектная модель документа.

Токенизация

��Лексический анализ, который преобразует некоторые входные данные в токены — базовые компоненты исходного кода. Представьте, что английский текст разделяется на слова. В этом примере слова будут токенами.

В результате токенизации получается серия из нуля или более следующих токенов: DOCTYPE, начальный тег (<tag>), конечный тег (</tag>), самозакрывающийся тег (<tag/>), имена атрибутов, значения, комментарии, символы, конец файла или текстовое содержимое элемента.

Построение DOM

После создания первого токена начинается создание древовидной структуры (объектной модели документа) на основе ранее проанализированных токенов.

��DOM-дерево описывает содержимое документа HTML. Элемент <html> — первый тег и корневой узел дерева документа. Дерево отражает отношения и иерархии между различными тегами.

Теги делятся на родительские узлы и дочерние — теги, вложенные в другие теги. Чем больше узлов, тем больше времени потребуется для построения DOM-дерева. Ниже показано DOM-дерево для примера HTML-документа, полученного с сервера:

Это упрощенная схема, и в реальности DOM сложнее. О его важности мы поговорим чуть позже.

Данная стадия построения многозадачная. Пока один токен обрабатывается, токенизатор продолжает работу над следующими. От байтов до создания DOM процесс выглядит примерно так:

Парсер обрабатывает строку за строкой сверху вниз. Когда он наталкивается на неблокирующие ресурсы (например, изображения), браузер запрашивает их с сервера и продолжает парсинг. Если наталкивается на блокирующие, останавливает выполнение, пока они все не загрузятся. Это могут быть таблицы стилей CSS, файлы JavaScript, добавленные в раздел <head> HTML, или шрифты, добавленные из CDN. Поэтому если работаете с JavaScript, рекомендуется добавить теги <script> в конце HTML-файла или, если хотите сохранить их в теге <head> , добавьте к ним атрибут defer или async . async разрешает асинхронность сразу после загрузки скрипта, а defer разрешает выполнение только после анализа всего документа.

Предварительные загрузчики и ускорение страницы

В браузерах Internet Explorer, WebKit и Mozilla предварительные загрузчики появились в 2008 году как способ работы с блокирующими ресурсами, особенно скриптами. Выше мы разобрали, что при столкновении с тегом скрипта HTML-парсинг прекращается, пока не загрузится и не запустится скрипт.

С предварительным загрузчиком схема выглядит так: когда браузер застревает на скрипте, второй более легкий парсер сканирует HTML на необходимые ресурсы — таблицы стилей, скрипты и т.д. Затем предварительный загрузчик извлекает ресурсы в фоновом режиме, чтобы к моменту, когда основной HTML-парсер достигнет их, их уже можно было загрузить. Если эти ресурсы уже кэшированы, этап пропускается.

2. CSS-Парсинг

Теперь проанализируем CSS (во внешних CSS-файлах и в элементах стиля) и построим CSSOM-дерево (объектная модель CSS).

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

Токенизация и построение CSSOM

Как и HTML, CSS-парсинг начинается с токенизации. Парсер берет байты и преобразует их в символы, затем в токены, узлы и, наконец, они связываются в CSSOM. Браузер производит селекторное согласование, чтобы каждый набор стилей соответствовал всем элементам на странице.

Браузер начинает с общего правила, применимого к узлу. Например: если узел — дочерний по отношению к элементу body, то он наследует все стили body. Затем браузер рекурсивно уточняет вычисляемые стили, применяя более конкретные правила. Вот почему правила стиля называют каскадными.

Для примера возьмем такой CSS:

CSSOM для данного кода примерно такой:

Обратите внимание, что в схеме у вложенных элементов как унаследованные, так и собственные стили.

унаследованные — от родительского, например: h1 наследует цвет от body , а section наследует размер шрифта от body

собственные стили могут переписывать правила, унаследованные от родительского элемента, например: p переписывает цвет и размер шрифта, унаследованный от div

Итак, у нас может быть несколько источников CSS, и они могут содержать правила, применимые к одному и тому же узлу. Поэтому браузер должен решить, какое будет применяться. Именно тогда в игру вступает специфичность.

Представьте, что вы в аэропорту ищете друга Ваню. Если хотите найти его по имени, можно крикнуть: «Ваня!». Скорее всего, в аэропорту будет несколько Вань, и они все откликнутся. Лучше позвать друга полным именем. Если крикнуть «Ваня Иванов», шансов найти друга будет больше.

Аналогично возьмем такой элемент…

… и такие стили CSS:

Как думаете, какое правило применится в браузере?

Ответ – второе, так как сочетания селекторов для всех тегов-якорей <a /> внутри абзаца более специфичны, чем просто селектор всех тегов-якорей. Если хотите поиграть со специфичностью, используйте калькулятор специфичности.

Правила CSS читаются справа налево, то есть если у нас есть такое: section p < color: blue; >, браузер сначала ищет все теги p на странице, а затем смотрит, есть ли у этих тегов p родительский тег section . В таком случае применяется правило CSS.

Во время CSS-парсинга и создания CSSOM загружаются другие ресурсы, включая файлы JavaScript. Это происходит благодаря предварительному загрузчику, о котором мы говорили выше.

3. Выполнение JavaScript

Итак, после получения файла JavaScript с сервера код интерпретируется, компилируется, анализируется и выполняется. Код JS преобразуется в то, с чем компьютер может работать, и это задача движка JavaScript. В зависимости от браузера движки JS называются и работают по-разному.

Движки JavaScript

�� Движок JavaScript (иногда его называют движком ECMAScript) — часть программного обеспечения, которая выполняет код JavaScript в браузере, и не только. Например, движок V8 — основной компонент среды Node.js.

Движки JavaScript, как правило — продукт деятельности разработчиков веб-браузеров. Мы говорили, что самые популярные браузеры — Chrome, Safari, Edge и Firefox. У каждого из них свой движок JavaScript:

V8. Высокопроизводительный движок JavaScript компании Google. Он написан на C++ и используется, в частности, в браузере Chrome и платформе Node.js. Реализует стандарты ECMA-262, ECMA-402 и WebAssembly.

JavaScriptCore. Встроенный движок JavaScript для WebKit, на котором работает Safari, Mail и другие приложения на macOS. В настоящее время он реализует спецификацию ECMA-262.

Chakra. Движок JavaScript, разработанный компанией Microsoft для браузера Microsoft Edge и других приложений Windows. Он реализует ECMA-262 версии 5.1 и частично поддерживает версию 6.

SpiderMonkey. Движок JavaScript и WebAssembly компании Mozilla. Он написан на C++, JavaScript и Rust и используется в Firefox, Servo и других проектах.

В начале движки JavaScript были простыми интерпретаторами. Современные браузеры проводят так называемую компиляцию Just-In-Time (JIT), сочетание компиляции и интерпретации.

Компиляция

�� Процесс, когда часть ПО, называемая компилятором, берет код на языке высокого уровня и сразу преобразует его в машинный.

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

Интерпретация

Такой тип исполнения кода используется в старых версиях JS.

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

Компиляция Just-In-Time

Такой тип исполнения кода используется в новейших версиях JavaScript.

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

Очень важный аспект JIT-компиляции — преобразование исходного кода в инструкции машинного кода работающей машины. Полученный машинный код оптимизируется для архитектуры ЦП работающей машины.

Если говорить совсем упрощенно, эти три процесса сводятся к следующему:

Компилятор преобразует код

Интерпретатор запускает код

Компилятор JIT преобразует во время выполнения кода

Сегодняшняя грань между терминами компиляция и интерпретация сильно стерлась. Если хотите узнать больше, для начала прочитайте статью на Mozilla Hacks (EN).

Обратите внимание, что я упомянул разные версии стандарта JavaScript. Браузеры, не поддерживающие новые версии языка, интерпретируют код, в то время как поддерживающие используют JIT для выполнения кода: движки V8, Chakra JavaScriptCore и SpiderMonkey. Хотя JavaScript — интерпретируемый язык и ему не нужна компиляция, большинство браузеров используют JIT-компиляцию для запуска кода, а не чистую интерпретацию.

Как обрабатывается код JavaScript

Когда код JavaScript принимает код, сначала проводится его анализ. Код считывается и одновременно преобразуется в структуру данных под названием абстрактное синтаксическое дерево AST. Код разделяется на фрагменты, имеющие отношение к языку. Например, ключевые слова function или const . Затем все эти фрагменты построят абстрактное синтаксическое дерево.

Допустим, у нас есть файл с программой, которая выполняет только одно действие — определяет переменную:

В этом случае абстрактное синтаксическое дерево будет выглядеть так (используется @babel/parser-7.16.12:

Если хотите преобразовать JavaScript в абстрактное синтаксическое дерево самостоятельно, используйте AST explorer. AST, полученный после записи переменной, на самом деле намного больше: в нём больше узлов, которые скрыты на снимке экрана.

После построения AST переводится в машинный код и выполняется сразу, так как современный JavaScript использует JIT-компиляцию.

Движок JavaScript выполняет этот код с использованием стека вызовов.

��Стек вызовов — механизм, с помощью которого интерпретатор JavaScript определяет, какая функция выполняется в настоящее время, какие функции вызываются из этой функции и т.д.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *