# JavaScript и браузер

Браузер – крайне враждебная программная среда

Дуглас Крокфорд, «Язык программирования JavaScript» (видеолекция)

Следующая часть книги расскажет о веб-браузерах. Без них не было бы JavaScript. А если бы и был, никто бы не обратил на него внимания.

Технологии веба с самого начала были децентрализованными – не только технически, но и с точки зрения их эволюции. Различные разработчики браузеров добавляли новую функциональность «по случаю», непродуманно, и часто эта функциональность обретала поддержку в других браузерах и становилась стандартом.

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

## Сети и интернет

Компьютерные сети появились в 1950-х. Если вы проложите кабель между двумя или несколькими компьютерами и разрешите им передавать данные, вы может делать много удивительных вещей. А если связь двух машин в одном здании позволяет делать много разного, то связь компьютеров по всей планете должна позволять ещё больше. Технология, позволяющая это сделать, была создана в 1980-х, и получившаяся сеть зовётся интернетом. И она оправдала ожидания.

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

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

К примеру, простой протокол чата может состоять из одного компьютера, отправляющего биты, представляющие текст «ЧАТ?» на другой, а второго отвечающего текстом «ОК!», для подтверждения того, что он понял протокол. Дальше они могут перейти к отправке друг другу текстов, чтения полученных текстов и вывода их на экран.

Большинство протоколов построено на основе других протоколов. Наш протокол чата из примера рассматривает сеть как потоковое устройство, в которое можно вводить биты и заказывать их приход на конкретный адрес в правильном порядке. А обеспечение этого процесса – само по себе является сложной задачей. Transmission Control Protocol (TCP) – протокол, решающий эту задачу. Все устройства, подключённые к интернету, говорят на нём, и большинство общения в интернете построено на его основе.

Соединение по TCP работает так: один компьютер ждёт, или «слушает», пока другие не начнут с ним говорить. Чтобы можно было слушать разные виды общения в одно и то же время, для каждого из них назначается номер (называемый портом). Большинство протоколов устанавливают порт, используемый по умолчанию. К примеру, если мы отправляем е-мейл по протоколу SMTP, компьютер, через который мы его шлём, должен слушать порт 25.

Тогда другой компьютер может установить соединение, связавшись с компьютером назначения по правильному порту. Если машина назначения доступна, и она слушает этот порт, соединение устанавливается. Слушающий компьютер зовётся сервером, а соединяющийся – клиентом.

Такое соединение работает как двусторонняя труба, по которой текут биты – обе машины могут помещать в неё данные. Когда биты переданы, другая машина может их прочесть. Это удобная модель. Можно сказать, что TCP обеспечивает абстракцию сети.

## Веб

World Wide Web, всемирная паутина (это не то же самое, что весь интернет в целом) – набор протоколов и форматов, позволяющий нам посещать странички через браузер. Web (рус. «паутина») в названии обозначает, что страницы можно легко связать друг с другом, в результате чего образуется гигантская сеть-паутина, по которой движутся пользователи.

Чтобы добавить в Веб содержимое, вам нужно соединить машину с интернетом и заставить её слушать 80 порт, используя протокол передачи гипертекста, Hypertext Transfer Protocol (HTTP). Он позволяет другим компьютерам запрашивать документы по сети.

Каждый документ имеет имя в виде универсального локатора ресурсов, Universal Resource Locator (URL), который выглядит примерно так:

```
http://eloquentjavascript.net/12_browser.html
|     |                      |               |
протокол      сервер               путь
```

Первая часть говорит нам, что URL использует протокол HTTP (в отличие от, скажем, зашифрованного HTTP, который записывается как https://). Затем идёт часть, определяющая, с какого сервера мы запрашиваем документ. Последняя – строка пути, определяющая конкретный документ или ресурс.

У каждой машины, присоединённой к интернету, есть свой адрес IP, который выглядит как 37.187.37.82. Его иногда можно использовать вместо имени сервера в URL. Но цифры сложнее запоминать и печатать, чем имена – поэтому обычно вы регистрируете доменное имя, которое указывает на конкретную машину (или набор машин). Я зарегистрировал eloquentjavascript.net, указывающий на IP-адрес машины, которую я контролирую, поэтому можно использовать этот адрес для предоставления веб-страниц.

Если вы введёте указанный URL в адресную строку браузера, он попробует запросить и показать документ, находящийся по этому URL. Во-первых, браузеру надо выяснить, куда ссылается домен eloquentjavascript.net. Затем, используя протокол HTTP, он соединяется с сервером по этому адресу, и спрашивает его ресурс по имени /12\_browser.html

В главе 17 мы подробнее рассмотрим протокол HTTP.

## HTML

HTML, или язык разметки гипертекста, Hypertext Markup Language – формат документа, использующийся для веб-страниц. HTML содержит текст и теги, придающие тексту структуру, описывающие такие вещи, как ссылки, параграфы и заголовки.

Простой HTML документ может выглядеть так:

```markup
<!doctype html>
<html>
  <head>
    <title>Моя домашняя страничка</title>
  </head>
  <body>
    <h1> Моя домашняя страничка </h1>
    <p>Привет, я Марийн и это моя домашняя страничка.</p>
    <p>А ещё я книжку написал! Читайте её
      <a href="http://eloquentjavascript.net">здесь</a>.</p>
  </body>
</html>
```

Теги, окружённые угловыми скобками < и >, описывают информацию о структуре документа. Всё остальное – просто текст.

Документ начинается с \<!doctype html>, и это говорит браузеру, что его надо интерпретировать как современный HTML, в отличие от разных диалектов прошлого.

У HTML документов есть заголовок и тело. Заголовок содержит информацию о документе, а тело – сам документ. В нашем случае мы объявили, что название страницы будет «Моя домашняя страничка», затем описали документ, содержащий заголовок (`<h1>`, то есть heading 1, заголовок 1. Есть ещё `<h2>` – `<h6>`, заголовки разных размеров) и два параграфа.

У тегов может быть несколько форм. Элемент вроде тела, параграфа и ссылки начинается открывающим тегом `<p>` и заканчивается закрывающим `</p>`. Некоторые открывающие теги, типа ссылки `<a>`, содержат дополнительную информацию в виде имя=”значение”. Она называется «атрибутами». В нашем случае адрес ссылки задан как `href="http://eloquentjavascript.net"`, где href означает «гипертекстовая ссылка», “hypertext reference”.

Некоторые теги ничего не окружают, и их не надо закрывать. Пример – тег картинки

```markup
<img src="http://example.com/image.jpg">
```

Чтобы включать в текст документа угловые скобки, нужно пользоваться специальной записью, так как в HTML они имеют особое значение. Открывающая скобка (она же знак «меньше») записывается как `&lt;` («less than», «меньше, чем»), закрывающая — `&gt;` («greater that», «больше, чем»). В HTML амперсанд &, за которым идёт слово и точка с запятой, зовётся сущностью и заменяется символом, который кодируется этой последовательностью.

Это похоже на обратные слэши, используемые в строках JavaScript. Из-за специального значения амперсанда его самого в текст можно включать в виде `&amp;`. В атрибуте, заключаемом в двойные кавычки, символ кавычек записывается как `&quot;`.

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

Следующий документ будет обработан так же, как и предыдущий.

```markup
<!doctype html>

<title>Моя домашняя страничка</title>

<h1> Моя домашняя страничка </h1>
<p>Привет, я Марийн и это моя домашняя страничка.
<p>А ещё я книжку написал! Читайте её
<a href=http://eloquentjavascript.net>here</a>.
```

Отсутствуют теги `<html>`, `<head>` и `<body>`. Браузер знает, что `<title>` должен быть в `<head>`, а `<h1>` — в `<body>`. Кроме того, параграфы не закрыты, поскольку открытие нового параграфа или конец документа означают их принудительное закрытие. Также адрес не заключён в кавычки.

В этой книге мы опустим теги `<html>`, `<head>` и `<body>` для краткости. Но я буду закрывать теги, и заключать атрибуты в кавычки.

Также обычно я буду опускать doctype. Я не советую делать это вам – браузеры иногда могут творить странные вещи, когда вы их опускаете. Считайте, что они присутствуют в примерах по умолчанию.

## HTML и JavaScript

В контексте нашей книги самый главный тег HTML — `<script>`. Он позволяет включать в документ программу на JavaScript.

```markup
<h1>Внимание, тест.</h1>
<script>alert("Привет!");</script>
```

Такой скрипт запустится сразу, как только браузер встретит тег `<script>` при разборе HTML. На странице появится диалог-предупреждение.

Включать большие программы в HTML непрактично. У тега `<script>` есть атрибут src, чтобы запрашивать файл со скриптом (текст, содержащий программу на JavaScript) с адреса URL.

```markup
<h1>Внимание, тест.</h1>
<script src="code/hello.js"></script>
```

В файле code/hello.js содержится та же простая программа «alert('Привет!');». Когда страница ссылается на другой URL и включает его в себя, браузер подгружает этот файл и включает их в страницу.

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

Некоторые атрибуты тоже могут содержать программу JavaScript. У тега (на странице он выглядит как кнопка) есть атрибут onClick, и его содержимое будет запущено, когда по кнопке щёлкают мышкой.

```markup
<button onclick="alert('Бабах!');">НЕ ЖМИ</button>
```

Заметьте, что я использовал одинарные кавычки для строки в атрибуте onclick, поскольку двойные кавычки уже используются в самом атрибуте. Можно было бы использовать `&quot;`, но это бы затруднило чтение.

## Песочница

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

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

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

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

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

## Совместимость и браузерные войны

На ранних стадиях развития Веба браузер по имени Mosaic занимал большую часть рынка. Через несколько лет баланс сместился в сторону Netscape, который затем был сильно потеснён браузером Internet Explorer от Microsoft. В любой момент превосходства одного из браузеров его разработчики позволяли себе в одностороннем порядке изобретать новые свойства веба. Так как большинство людей использовали один и тот же браузер, сайты просто начинали использовать эти свойства, не обращая внимания на остальные браузеры.

Это были тёмные века совместимости, которые иногда называли «войнами браузеров». Веб-разработчики сталкивались с двумя или тремя несовместимыми платформами. Кроме того, браузеры около 2003 года были полны ошибок, причём у каждого они были свои. Жизнь людей, создававших веб-страницы, была тяжёлой.

Mozilla Firefox, некоммерческое ответвление Netscape, бросил вызов гегемонии Internet Explorer в конце 2000-х. Так как Microsoft особо не стремилась к конкуренции, Firefox отобрал солидную часть рынка. Примерно в это время Google представил свой браузер Chrome, а Apple – Safari. Это привело к появлению четырёх основных игроков вместо одного.

У новых игроков были более серьёзные намерения по отношению к стандартам и больше инженерного опыта, что привело к лучшей совместимости и меньшему количеству багов. Microsoft, видя сжатие своей части рынка, приняла эти стандарты. Если вы начинаете изучать веб-разработку сегодня – вам повезло. Последние версии основных браузеров работают одинаково и в них мало ошибок.

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