aboutsummaryrefslogtreecommitdiff
path: root/files/ru/learn/javascript/client-side_web_apis
diff options
context:
space:
mode:
Diffstat (limited to 'files/ru/learn/javascript/client-side_web_apis')
-rw-r--r--files/ru/learn/javascript/client-side_web_apis/client-side_storage/index.html794
-rw-r--r--files/ru/learn/javascript/client-side_web_apis/fetching_data/index.html379
-rw-r--r--files/ru/learn/javascript/client-side_web_apis/index.html53
-rw-r--r--files/ru/learn/javascript/client-side_web_apis/introduction/index.html277
-rw-r--r--files/ru/learn/javascript/client-side_web_apis/manipulating_documents/index.html321
-rw-r--r--files/ru/learn/javascript/client-side_web_apis/third_party_apis/index.html482
6 files changed, 2306 insertions, 0 deletions
diff --git a/files/ru/learn/javascript/client-side_web_apis/client-side_storage/index.html b/files/ru/learn/javascript/client-side_web_apis/client-side_storage/index.html
new file mode 100644
index 0000000000..114e7821a1
--- /dev/null
+++ b/files/ru/learn/javascript/client-side_web_apis/client-side_storage/index.html
@@ -0,0 +1,794 @@
+---
+title: Client-side storage
+slug: Learn/JavaScript/Client-side_web_APIs/Client-side_storage
+translation_of: Learn/JavaScript/Client-side_web_APIs/Client-side_storage
+---
+<p>{{LearnSidebar}}</p>
+
+<div>{{PreviousMenu("Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</div>
+
+<div></div>
+
+<p class="summary">Современные веб-браузеры поддерживают несколько способов хранения данных из веб-сайтов на компьютере пользователя - с разрешения пользователя - чтобы потом получать их, когда это необходимо. Это позволяет долгосрочно хранить данные, сохранять сайты или документы для использования без подключения к сети, сохранять пользовательские настройки для вашего сайта и многое другое. В этой статье объясняются основы того, как это все работает.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Что нужно знать:</th>
+ <td>JavaScript basics (see <a href="/en-US/docs/Learn/JavaScript/First_steps">first steps</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">building blocks</a>, <a href="/en-US/docs/Learn/JavaScript/Objects">JavaScript objects</a>), the <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">basics of Client-side APIs</a></td>
+ </tr>
+ <tr>
+ <th scope="row">Цель статьи:</th>
+ <td>To learn how to use client-side storage APIs to store application data.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Хранение_данных_на_стороне_клиента">Хранение данных на стороне клиента?</h2>
+
+<p>Ранее, мы говорили о разнице между <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview#Static_sites">статическими</a> и <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview#Dynamic_sites">динамическими сайтами</a>. Большинство современных веб-сайтов являются динамическими - они хранят данные на сервере, используя какую-то базу данных (серверное хранилище), а затем запускают код <a href="/en-US/docs/Learn/Server-side">на стороне сервера</a> чтобы извлечь необходимые данные, вставить их в шаблоны статических страниц и передать полученный HTML-код клиенту для отображения в браузере пользователя.</p>
+
+<p>Хранилище на стороне клиента работает по схожим принципам, но используется по-другому. Оно состоит из API-интерфейсов JavaScript, которые позволяют вам хранить данные на клиенте (то есть на компьютере пользователя), а затем извлекать их при необходимости. Это имеет много разных применений, таких как:</p>
+
+<ul>
+ <li>Персонализация настроек сайта (например, отображение выбранных пользователем виджетов, цветовой схемы или размера шрифта).</li>
+ <li>Сохранение предыдущей активности на сайте (например, сохранение содержимого корзины покупок из предыдущего сеанса, запоминание, был ли пользователь ранее авторизован в системе).</li>
+ <li>Сохранение данных и ресурсов локально, так что сайт будет быстрее (и, возможно, экономичнее) загружаться или использоваться без подключения к сети.</li>
+ <li>Сохранение созданных веб-приложением документов локально для использования в автономном режиме.</li>
+</ul>
+
+<p>Часто, хранилища на сторонах клиента и сервера используются совместно. К примеру, вы должны загрузить из базы данных пакет музыкальных файлов для веб-игры, или музыкальный плеер хранит их в базе данных на стороне клиента, и воспроизводит по мере необходимости.</p>
+
+<p>Пользователь должен будет загрузить музыкальные файлы только один раз - при последующих посещениях они будут извлечены из локальной базы данных.</p>
+
+<div class="note">
+<p><strong>Примечание.</strong> Существуют ограничения на объем данных, которые вы можете хранить с помощью API-интерфейсов на стороне клиента (возможно, как для отдельных API, так и в совокупности). Точный лимит варьируется в зависимости от браузера и, возможно, в зависимости от пользовательских настроек. Смотри <a href="/en-US/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria">Ограничения хранилища браузера и критерии переполнения</a> для большей информации.</p>
+</div>
+
+<h3 id="Старый_подход_куки">Старый подход: куки</h3>
+
+<p>Концепция хранения на стороне клиента существует уже давно. С первых дней Интернета, использовали <a href="/en-US/docs/Web/HTTP/Cookies">cookies</a> для хранения информации, чтобы персонализировать пользовательский опыт на веб-сайтах. Это самая ранняя форма хранилища на стороне клиента, обычно используемая в Интернете.</p>
+
+<p>Из-за этого возраста существует ряд проблем - как технических, так и с точки зрения пользовательского опыта - связанных с файлами cookie. Эти проблемы настолько значительны, что при первом посещении сайта людям, живущим в Европе, показываются сообщения, информирующие их о том, будут ли они использовать файлы cookie для хранения данных о них. Это связано с частью законодательства Европейского Союза, известного как  <a href="/en-US/docs/Web/HTTP/Cookies#EU_cookie_directive">EU Cookie directive</a>.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15734/cookies-notice.png" style="display: block; margin: 0 auto;"></p>
+
+<p>По этим причинам мы не будем учить вас, как использовать куки в этой статье. Они устарели, у них множество <a href="/en-US/docs/Web/HTTP/Cookies#Security">проблем с безопастностью</a>, и неспособны хранить сложные данные. При этом существуют лучшие, более современные, способы хранения более широкого спектра данных на компьютере пользователя.</p>
+
+<p>Единственным преимуществом файлов cookie является то, что они поддерживаются очень старыми браузерами, поэтому, если ваш проект требует, чтобы вы поддерживали устаревшие браузеры (например, Internet Explorer 8 или более ранние версии), файлы cookie могут по-прежнему быть полезными, но для большинства проектов вы не нужно больше прибегать к ним.</p>
+
+<div class="note">
+<p>Почему по-прежнему создаются новые сайты с использованием файлов cookie? Это происходит главным образом из-за привычек разработчиков, использования старых библиотек, которые всё ещё используют куки-файлы, и наличия множества веб-сайтов, предоставляющих устаревшие справочные и учебные материалы для обучения хранению данных.</p>
+</div>
+
+<h3 id="Новый_подход_Web_Storage_и_IndexedDB">Новый подход: Web Storage и IndexedDB</h3>
+
+<p>Современные браузеры имеют гораздо более простые и эффективные API для хранения данных на стороне клиента, чем при использовании файлов cookie.</p>
+
+<ul>
+ <li>The <a href="/en-US/docs/Web/API/Web_Storage_API">Web Storage API</a> обеспечивает очень простой синтаксис для хранения и извлечения данных, состоящих из пар 'ключ' : 'значение'. Это полезно, когда вам просто нужно сохранить некоторые простые данные, такие как имя пользователя, вошли ли они в систему, какой цвет использовать для фона экрана и т. д.</li>
+ <li>The <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a> обеспечивает браузер полной базой данных для хранения сложных данных. Это может быть использовано для хранения полных наборов записей клиентов и даже до сложных типов данных, таких как аудио или видео файлы.</li>
+</ul>
+
+<p>Вы узнаете больше об этих API ниже.</p>
+
+<h3 id="Что_нас_ждёт_в_будущем_Cache_API">Что нас ждёт в будущем: Cache API</h3>
+
+<p>Некоторые современные браузеры поддерживают новое {{domxref("Cache")}} API. Этот API предназначен для хранения HTTP-ответов на конкретные запросы и очень полезен для таких вещей, как хранение ресурсов сайта в автономном режиме, чтобы впоследствии сайт можно было использовать без сетевого подключения. Cache обычно используется в сочетании с <a href="/en-US/docs/Web/API/Service_Worker_API">Service Worker API</a>, однако это не обязательно.</p>
+
+<p>Использование Cache и Service Workers - сложная тема, и мы не будем подробно останавливаться на ней в этой статье, хотя приведем простой пример {{anch("Offline asset storage")}} в разделе ниже.</p>
+
+<h2 id="Хранение_простых_данных_—_web_storage">Хранение простых данных — web storage</h2>
+
+<p><a href="/en-US/docs/Web/API/Web_Storage_API">Web Storage API</a> очень легко использовать — вы храните простые пары данных имя/значение (только строки, цифры и т.п.) и получаете их, когда необходимо.</p>
+
+<h3 id="Базовый_синтаксис">Базовый синтаксис</h3>
+
+<p>Посмотрите:</p>
+
+<ol>
+ <li>
+ <p>Во-первых, посмотрите наши <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/index.html">web storage шаблоны</a> на GitHub (откройте в новой вкладке).</p>
+ </li>
+ <li>
+ <p>Откройте консоль инструментов JavaScript разработчика вашего браузера.</p>
+ </li>
+ <li>
+ <p>Все данные вашего веб-хранилища содержатся в двух объектоподобных структурах внутри браузера: {{domxref("Window.sessionStorage", "sessionStorage")}} и {{domxref("Window.localStorage", "localStorage")}}. Первый сохраняет данные до тех пор, пока браузер открыт (данные теряются при закрытии браузера), а второй сохраняет данные даже после того, как браузер закрыт, а затем снова открыт. Мы будем использовать второй в этой статье, так как он, как правило, более полезен.</p>
+
+ <p>{{domxref("Storage.setItem()")}} метод позволяет сохранить элемент данных в хранилище - он принимает два параметра: имя элемента и его значение. Попробуйте ввести это в свою консоль JavaScript (измените значение на свое собственное имя, если хотите!):</p>
+
+ <pre class="brush: js notranslate">localStorage.setItem('name','Chris');</pre>
+ </li>
+ <li>
+ <p>{{domxref("Storage.getItem()")}} метод принимает один параметр - имя элемента данных, который вы хотите получить - и возвращает значение элемента. Теперь введите эти строки в вашу консоль JavaScript:</p>
+
+ <pre class="brush: js notranslate">var myName = localStorage.getItem('name');
+myName</pre>
+
+ <p>После ввода во второй строке вы должны увидеть, что переменная <code>myName</code> теперь содержит значение элемента данных <code>name</code>.</p>
+ </li>
+ <li>
+ <p>{{domxref("Storage.removeItem()")}} метод принимает один параметр - имя элемента данных, который вы хотите удалить, - и удаляет этот элемент из веб-хранилища. Введите следующие строки в вашу консоль JavaScript:</p>
+
+ <pre class="brush: js notranslate">localStorage.removeItem('name');
+var myName = localStorage.getItem('name');
+myName</pre>
+
+ <p>Третья строка должна теперь возвращать ноль - элемент <code>name</code> больше не существует в веб-хранилище.</p>
+ </li>
+</ol>
+
+<h3 id="Данные_сохраняются!">Данные сохраняются!</h3>
+
+<p>Одной из ключевых особенностей веб-хранилища является то, что данные сохраняются между загрузками страниц (и даже в случае закрытия браузера, в случае <code>localStorage</code>). Давайте посмотрим на это в действии.</p>
+
+<ol>
+ <li>
+ <p>Снова откройте пустой шаблон нашего веб-хранилища, но на этот раз в другом браузере, отличном от того, в котором вы открыли этот учебник! Так будет удобнее.</p>
+ </li>
+ <li>
+ <p>Введите эти строки в консоль JavaScript браузера:</p>
+
+ <pre class="brush: js notranslate">localStorage.setItem('name','Chris');
+var myName = localStorage.getItem('name');
+myName</pre>
+
+ <p>Вы должны увидеть возвращенное имя элемента.</p>
+ </li>
+ <li>
+ <p>Теперь закройте браузер и откройте его снова.</p>
+ </li>
+ <li>
+ <p>Введите следующий код:</p>
+
+ <pre class="brush: js notranslate">var myName = localStorage.getItem('name');
+myName</pre>
+
+ <p>Вы должны увидеть, что значение всё ещё доступно, даже после закрытия / открытия браузера.</p>
+ </li>
+</ol>
+
+<h3 id="Для_каждого_домена_отдельное_хранилище">Для каждого домена отдельное хранилище</h3>
+
+<p>Существуют отдельные хранилища данных для каждого домена (каждый отдельный веб-адрес загружается в браузер). Вы увидите, что если вы загрузите два веб-сайта (например, google.com и amazon.com) и попытаетесь сохранить элемент на одном веб-сайте, он не будет доступен для другого веб-сайта.</p>
+
+<p>Это имеет смысл - вы можете представить себе проблемы безопасности, которые могут возникнуть, если веб-сайты смогут видеть данные друг друга!</p>
+
+<h3 id="Более_развернутый_пример">Более развернутый пример</h3>
+
+<p>Давайте применим эти новые знания, написав простой рабочий пример, чтобы дать вам представление о том, как можно использовать веб-хранилище. Наш пример позволит вам ввести имя, после чего страница обновится, чтобы дать вам персональное приветствие. Это состояние также будет сохраняться при перезагрузке страницы / браузера, поскольку имя хранится в веб-хранилище.</p>
+
+<p>Вы можете найти пример HTML на <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/web-storage/personal-greeting.html">personal-greeting.html</a> — он содержит простой веб-сайт с заголовком, контентом и нижним колонтитулом, а также форму для ввода вашего имени.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15735/web-storage-demo.png" style="display: block; margin: 0 auto;"></p>
+
+<p>Давайте создадим пример, чтобы вы могли понять, как он работает.</p>
+
+<ol>
+ <li>
+ <p>Во-первых, сделайте локальную копию нашего  <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/web-storage/personal-greeting.html">personal-greeting.html</a> файла в новом каталоге на вашем компьютере.</p>
+ </li>
+ <li>
+ <p>Далее обратите внимание, как наш HTML ссылается на файл JavaScript с именем <code>index.js</code> (см. строку 40). Нам нужно создать его, и записать в него наш код JavaScript. Создайте файл <code>index.js</code> в том же каталоге, что и ваш HTML-файл.</p>
+ </li>
+ <li>
+ <p>Мы начнем с создания ссылок на все функции HTML, которыми мы должны манипулировать в этом примере - мы создадим их все как константы, поскольку эти ссылки не нужно изменять в жизненном цикле приложения. Добавьте следующие строки в ваш файл JavaScript:</p>
+
+ <pre class="brush: js notranslate">// create needed constants
+const rememberDiv = document.querySelector('.remember');
+const forgetDiv = document.querySelector('.forget');
+const form = document.querySelector('form');
+const nameInput = document.querySelector('#entername');
+const submitBtn = document.querySelector('#submitname');
+const forgetBtn = document.querySelector('#forgetname');
+
+const h1 = document.querySelector('h1');
+const personalGreeting = document.querySelector('.personal-greeting');</pre>
+ </li>
+ <li>
+ <p>Далее нам нужно включить небольшой прослушиватель событий, чтобы форма фактически не отправляла себя при нажатии кнопки отправки, так как это не то поведение, которое нам нужно. Добавьте этот фрагмент ниже вашего предыдущего кода:</p>
+
+ <pre class="brush: js notranslate">// Stop the form from submitting when a button is pressed
+form.addEventListener('submit', function(e) {
+ e.preventDefault();
+});</pre>
+ </li>
+ <li>
+ <p>Теперь нам нужно добавить прослушиватель событий, функция-обработчик которого будет запускаться при нажатии кнопки «Say hello». В комментариях подробно объясняется, что делает каждый бит, но в сущности здесь мы берем имя, которое пользователь ввел в поле ввода текста, и сохраняем его в веб-хранилище с помощью <code>setItem()</code>, затем запускаем функцию <code>nameDisplayCheck()</code>, которая будет обрабатывать обновление фактического текста сайта. Добавьте это в конец: </p>
+
+ <pre class="brush: js notranslate">// run function when the 'Say hello' button is clicked
+submitBtn.addEventListener('click', function() {
+ // store the entered name in web storage
+ localStorage.setItem('name', nameInput.value);
+ // run nameDisplayCheck() to sort out displaying the
+ // personalized greetings and updating the form display
+ nameDisplayCheck();
+});</pre>
+ </li>
+ <li>
+ <p>На этом этапе нам также необходим прослушиватель событий для запуска функции при нажатии кнопки «Forget» — она будет отображена только после того как кнопка «Say hello» будет нажата (две формы состояния для переключения между ними). В этой функции мы удаляем переменную <code>name</code> из веб-хранилища используя <code>removeItem()</code>, затем снова запускаем <code>nameDisplayCheck()</code> для обновления. Добавьте этот код в конец:</p>
+
+ <pre class="brush: js notranslate">// run function when the 'Forget' button is clicked
+forgetBtn.addEventListener('click', function() {
+ // Remove the stored name from web storage
+ localStorage.removeItem('name');
+ // run nameDisplayCheck() to sort out displaying the
+ // generic greeting again and updating the form display
+ nameDisplayCheck();
+});</pre>
+ </li>
+ <li>
+ <p>Самое время для определения самой функции <code>nameDisplayCheck()</code>. Здесь мы проверяем была ли переменная <code>name</code> сохранена в веб-хранилище с помощью <code>localStorage.getItem('name')</code> в качестве условия. Если переменная <code>name</code> была сохранена, то вызов вернёт - <code>true</code>; если же нет, то - <code>false</code>. Если <code>true</code>, мы показываем персональное приветствие, отображаем кнопку «Forget», и скрываем кнопку «Say hello». Если же <code>false</code>, мы отображаем общее приветствие и делаем обратное. Опять же, добавьте следующий код в конец:</p>
+
+ <pre class="brush: js notranslate">// define the nameDisplayCheck() function
+function nameDisplayCheck() {
+ // check whether the 'name' data item is stored in web Storage
+ if(localStorage.getItem('name')) {
+ // If it is, display personalized greeting
+ let name = localStorage.getItem('name');
+ h1.textContent = 'Welcome, ' + name;
+ personalGreeting.textContent = 'Welcome to our website, ' + name + '! We hope you have fun while you are here.';
+ // hide the 'remember' part of the form and show the 'forget' part
+ forgetDiv.style.display = 'block';
+ rememberDiv.style.display = 'none';
+ } else {
+ // if not, display generic greeting
+ h1.textContent = 'Welcome to our website ';
+ personalGreeting.textContent = 'Welcome to our website. We hope you have fun while you are here.';
+ // hide the 'forget' part of the form and show the 'remember' part
+ forgetDiv.style.display = 'none';
+ rememberDiv.style.display = 'block';
+ }
+}</pre>
+ </li>
+ <li>
+ <p>Последнее но не менее важное, нам необходимо запускать функцию <code>nameDisplayCheck()</code> при каждой загрузке страницы. Если мы не сделаем этого, персональное приветствие не будет сохранятся после перезагрузки страницы. Добавьте следующий фрагмент в конец вашего кода:</p>
+
+ <pre class="brush: js notranslate">document.body.onload = nameDisplayCheck;</pre>
+ </li>
+</ol>
+
+<p>Ваш пример закончен — отличная работа! Всё что теперь осталось это сохранить ваш код и протестировать вашу HTML страницу в браузере. Вы можете посмотреть нашу <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/personal-greeting.html">завершённую версию работающую здесь</a>.</p>
+
+<div class="note">
+<p>Есть и другой, немного более комплексный пример описываемый в <a href="/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API">Using the Web Storage API</a>.</p>
+</div>
+
+<h2 id="Храним_более_сложную_информацию_в_IndexedDB">Храним более сложную информацию в IndexedDB</h2>
+
+<p><a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a> (иногда сокращают до IDB) это полная база данных, доступная в браузере, в которой вы можете хранить сложные связанные данные, типы которых не ограничиваются простыми значениями, такими как строки или числа.</p>
+
+<p>Вы можете сохранить видео, фото, и почти все остальные файлы с IndexedDB. </p>
+
+<p dir="ltr" id="tw-target-text">Однако это обходится дорого: IndexedDB гораздо сложнее в использовании, чем Web Storage API.</p>
+
+<p dir="ltr" id="tw-target-text">В этом разделе мы действительно только коснемся того, на что он способен, но мы дадим вам достаточно, чтобы начать.</p>
+
+<h3 dir="ltr" id="Работа_с_примером_хранения_заметок">Работа с примером хранения заметок</h3>
+
+<p>Here we'll run you through an example that allows you to store notes in your browser and view and delete them whenever you like, getting you to build it up for yourself and explaining the most fundamental parts of IDB as we go along.</p>
+
+<p>The app looks something like this:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15744/idb-demo.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<p>Each note has a title and some body text, each individually editable. The JavaScript code we'll go through below has detailed comments to help you understand what's going on.</p>
+
+<h3 id="Предустановка">Предустановка</h3>
+
+<ol>
+ <li>First of all, make local copies of our <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index.html">index.html</a></code>, <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/style.css">style.css</a></code>, and <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index-start.js">index-start.js</a></code> files into a new directory on your local machine.</li>
+ <li>Have a look at the files. You'll see that the HTML is pretty simple: a web site with a header and footer, as well as a main content area that contains a place to display notes, and a form for entering new notes into the database. The CSS provides some simple styling to make it clearer what is going on. The JavaScript file contains five declared constants containing references to the {{htmlelement("ul")}} element the notes will be displayed in, the title and body {{htmlelement("input")}} elements, the {{htmlelement("form")}} itself, and the {{htmlelement("button")}}.</li>
+ <li>Rename your JavaScript file to <code>index.js</code>. You are now ready to start adding code to it.</li>
+</ol>
+
+<h3 id="Настраиваем_базу_данных">Настраиваем базу данных</h3>
+
+<p>Now let's look at what we have to do in the first place, to actually set up a database.</p>
+
+<ol>
+ <li>
+ <p>Below the constant declarations, add the following lines:</p>
+
+ <pre class="brush: js notranslate">// Create an instance of a db object for us to store the open database in
+let db;</pre>
+
+ <p>Here we are declaring a variable called <code>db</code> — this will later be used to store an object representing our database. We will use this in a few places, so we've declared it globally here to make things easier.</p>
+ </li>
+ <li>
+ <p>Next, add the following to the bottom of your code:</p>
+
+ <pre class="brush: js notranslate">window.onload = function() {
+
+};</pre>
+
+ <p>We will write all of our subsequent code inside this <code>window.onload</code> event handler function, called when the window's {{event("load")}} event fires, to make sure we don't try to use IndexedDB functionality before the app has completely finished loading (it could fail if we don't).</p>
+ </li>
+ <li>
+ <p>Inside the <code>window.onload</code> handler, add the following:</p>
+
+ <pre class="brush: js notranslate">// Open our database; it is created if it doesn't already exist
+// (see onupgradeneeded below)
+let request = window.indexedDB.open('notes', 1);</pre>
+
+ <p>This line creates a <code>request</code> to open version <code>1</code> of a database called <code>notes</code>. If this doesn't already exist, it will be created for you by subsequent code. You will see this request pattern used very often throughout IndexedDB. Database operations take time. You don't want to hang the browser while you wait for the results, so database operations are {{Glossary("asynchronous")}}, meaning that instead of happening immediately, they will happen at some point in the future, and you get notified when they're done.</p>
+
+ <p>To handle this in IndexedDB, you create a request object (which can be called anything you like — we called it <code>request</code> so it is obvious what it is for). You then use event handlers to run code when the request completes, fails, etc., which you'll see in use below.</p>
+
+ <div class="note">
+ <p><strong>Note</strong>: The version number is important. If you want to upgrade your database (for example, by changing the table structure), you have to run your code again with an increased version number, different schema specified inside the <code>onupgradeneeded</code> handler (see below), etc. We won't cover upgrading databases in this simple tutorial.</p>
+ </div>
+ </li>
+ <li>
+ <p>Now add the following event handlers just below your previous addition — again inside the <code>window.onload</code> handler:</p>
+
+ <pre class="brush: js notranslate">// onerror handler signifies that the database didn't open successfully
+request.onerror = function() {
+ console.log('Database failed to open');
+};
+
+// onsuccess handler signifies that the database opened successfully
+request.onsuccess = function() {
+ console.log('Database opened successfully');
+
+ // Store the opened database object in the db variable. This is used a lot below
+ db = request.result;
+
+ // Run the displayData() function to display the notes already in the IDB
+ displayData();
+};</pre>
+
+ <p>The {{domxref("IDBRequest.onerror", "request.onerror")}} handler will run if the system comes back saying that the request failed. This allows you to respond to this problem. In our simple example, we just print a message to the JavaScript console.</p>
+
+ <p>The {{domxref("IDBRequest.onsuccess", "request.onsuccess")}} handler on the other hand will run if the request returns successfully, meaning the database was successfully opened. If this is the case, an object representing the opened database becomes available in the {{domxref("IDBRequest.result", "request.result")}} property, allowing us to manipulate the database. We store this in the <code>db</code> variable we created earlier for later use. We also run a custom function called <code>displayData()</code>, which displays the data in the database inside the {{HTMLElement("ul")}}. We run it now so that the notes already in the database are displayed as soon as the page loads. You'll see this defined later on.</p>
+ </li>
+ <li>
+ <p>Finally for this section, we'll add probably the most important event handler for setting up the database: {{domxref("IDBOpenDBRequest.onupgradeneeded", "request.onupdateneeded")}}. This handler runs if the database has not already been set up, or if the database is opened with a bigger version number than the existing stored database (when performing an upgrade). Add the following code, below your previous handler:</p>
+
+ <pre class="brush: js notranslate">// Setup the database tables if this has not already been done
+request.onupgradeneeded = function(e) {
+ // Grab a reference to the opened database
+ let db = e.target.result;
+
+ // Create an objectStore to store our notes in (basically like a single table)
+ // including a auto-incrementing key
+ let objectStore = db.createObjectStore('notes', { keyPath: 'id', autoIncrement:true });
+
+ // Define what data items the objectStore will contain
+ objectStore.createIndex('title', 'title', { unique: false });
+ objectStore.createIndex('body', 'body', { unique: false });
+
+ console.log('Database setup complete');
+};</pre>
+
+ <p>This is where we define the schema (structure) of our database; that is, the set of columns (or fields) it contains. Here we first grab a reference to the existing database from <code>e.target.result</code> (the event target's <code>result</code> property), which is the <code>request</code> object. This is equivalent to the line <code>db = request.result;</code> inside the <code>onsuccess</code> handler, but we need to do this separately here because the <code>onupgradeneeded</code> handler (if needed) will run before the <code>onsuccess</code> handler, meaning that the <code>db</code> value wouldn't be available if we didn't do this.</p>
+
+ <p>We then use {{domxref("IDBDatabase.createObjectStore()")}} to create a new object store inside our opened database. This is equivalent to a single table in a conventional database system. We've given it the name notes, and also specified an <code>autoIncrement</code> key field called <code>id</code> — in each new record this will automatically be given an incremented value — the developer doesn't need to set this explicitly. Being the key, the <code>id</code> field will be used to uniquely identify records, such as when deleting or displaying a record.</p>
+
+ <p>We also create two other indexes (fields) using the {{domxref("IDBObjectStore.createIndex()")}} method: <code>title</code> (which will contain a title for each note), and <code>body</code> (which will contain the body text of the note).</p>
+ </li>
+</ol>
+
+<p>So with this simple database schema set up, when we start adding records to the database each one will be represented as an object along these lines:</p>
+
+<pre class="brush: js notranslate"><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-object"><span class="objectLeftBrace">{
+ </span><span class="nodeName">title</span><span class="objectEqual">: </span><span class="objectBox objectBox-string">"Buy milk"</span>,
+ <span class="nodeName">body</span><span class="objectEqual">: </span><span class="objectBox objectBox-string">"Need both cows milk and soya."</span>,
+ <span class="nodeName">id</span><span class="objectEqual">: </span><span class="objectBox objectBox-number">8</span></span></span></span></span><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-object"><span class="objectRightBrace">
+}</span></span></span></span></span></pre>
+
+<h3 id="Добавляем_данные_в_базу_данных">Добавляем данные в базу данных</h3>
+
+<p>Now let's look at how we can add records to the database. This will be done using the form on our page.</p>
+
+<p>Below your previous event handler (but still inside the <code>window.onload</code> handler), add the following line, which sets up an <code>onsubmit</code> handler that runs a function called <code>addData()</code> when the form is submitted (when the submit {{htmlelement("button")}} is pressed leading to a successful form submission):</p>
+
+<pre class="brush: js notranslate">// Create an onsubmit handler so that when the form is submitted the addData() function is run
+form.onsubmit = addData;</pre>
+
+<p>Now let's define the <code>addData()</code> function. Add this below your previous line:</p>
+
+<pre class="brush: js notranslate">// Define the addData() function
+function addData(e) {
+ // prevent default - we don't want the form to submit in the conventional way
+ e.preventDefault();
+
+ // grab the values entered into the form fields and store them in an object ready for being inserted into the DB
+ let newItem = { title: titleInput.value, body: bodyInput.value };
+
+ // open a read/write db transaction, ready for adding the data
+ let transaction = db.transaction(['notes'], 'readwrite');
+
+ // call an object store that's already been added to the database
+ let objectStore = transaction.objectStore('notes');
+
+ // Make a request to add our newItem object to the object store
+ var request = objectStore.add(newItem);
+ request.onsuccess = function() {
+ // Clear the form, ready for adding the next entry
+ titleInput.value = '';
+ bodyInput.value = '';
+ };
+
+ // Report on the success of the transaction completing, when everything is done
+ transaction.oncomplete = function() {
+ console.log('Transaction completed: database modification finished.');
+
+ // update the display of data to show the newly added item, by running displayData() again.
+ displayData();
+ };
+
+ transaction.onerror = function() {
+ console.log('Transaction not opened due to error');
+ };
+}</pre>
+
+<p>This is quite complex; breaking it down, we:</p>
+
+<ul>
+ <li>Run {{domxref("Event.preventDefault()")}} on the event object to stop the form actually submitting in the conventional manner (this would cause a page refresh and spoil the experience).</li>
+ <li>Create an object representing a record to enter into the database, populating it with values from the form inputs. note that we don't have to explicitly include an <code>id</code> value — as we expained early, this is auto-populated.</li>
+ <li>Open a <code>readwrite</code> transaction against the <code>notes</code> object store using the {{domxref("IDBDatabase.transaction()")}} method. This transaction object allows us to access the object store so we can do something to it, e.g. add a new record.</li>
+ <li>Access the object store using the {{domxref("IDBTransaction.objectStore")}} property, saving it in the <code>objectStore</code> variable.</li>
+ <li>Add the new record to the database using {{domxref("IDBObjectStore.add()")}}. This creates a request object, in the same fashion as we've seen before.</li>
+ <li>Add a bunch of event handlers to the <code>request</code> and the <code>transaction</code> to run code at critical points in the lifecycle. Once the request has succeeded, we clear the form inputs ready for entering the next note. Once the transaction has completed, we run the <code>displayData()</code> function again to update the display of notes on the page.</li>
+</ul>
+
+<h3 id="Отображаем_данные">Отображаем данные</h3>
+
+<p>We've referenced <code>displayData()</code> twice in our code already, so we'd probably better define it. Add this to your code, below the previous function definition:</p>
+
+<pre class="brush: js notranslate">// Define the displayData() function
+function displayData() {
+ // Here we empty the contents of the list element each time the display is updated
+ // If you ddn't do this, you'd get duplicates listed each time a new note is added
+ while (list.firstChild) {
+ list.removeChild(list.firstChild);
+ }
+
+ // Open our object store and then get a cursor - which iterates through all the
+ // different data items in the store
+ let objectStore = db.transaction('notes').objectStore('notes');
+ objectStore.openCursor().onsuccess = function(e) {
+ // Get a reference to the cursor
+ let cursor = e.target.result;
+
+ // If there is still another data item to iterate through, keep running this code
+ if(cursor) {
+ // Create a list item, h3, and p to put each data item inside when displaying it
+ // structure the HTML fragment, and append it inside the list
+ let listItem = document.createElement('li');
+ let h3 = document.createElement('h3');
+ let para = document.createElement('p');
+
+ listItem.appendChild(h3);
+ listItem.appendChild(para);
+ list.appendChild(listItem);
+
+ // Put the data from the cursor inside the h3 and para
+ h3.textContent = cursor.value.title;
+ para.textContent = cursor.value.body;
+
+ // Store the ID of the data item inside an attribute on the listItem, so we know
+ // which item it corresponds to. This will be useful later when we want to delete items
+ listItem.setAttribute('data-note-id', cursor.value.id);
+
+ // Create a button and place it inside each listItem
+ let deleteBtn = document.createElement('button');
+ listItem.appendChild(deleteBtn);
+ deleteBtn.textContent = 'Delete';
+
+ // Set an event handler so that when the button is clicked, the deleteItem()
+ // function is run
+ deleteBtn.onclick = function(e) {
+ deleteItem(e);
+ };
+
+ // Iterate to the next item in the cursor
+ cursor.continue();
+ } else {
+ // Again, if list item is empty, display a 'No notes stored' message
+ if(!list.firstChild) {
+ let listItem = document.createElement('li');
+ listItem.textContent = 'No notes stored.'
+ list.appendChild(listItem);
+ }
+ // if there are no more cursor items to iterate through, say so
+ console.log('Notes all displayed');
+ }
+ };
+}</pre>
+
+<p>Again, let's break this down:</p>
+
+<ul>
+ <li>First we empty out the {{htmlelement("ul")}} element's content, before then filling it with the updated content. If you didn't do this, you'd end up with a huge list of duplicated content being added to with each update.</li>
+ <li>Next, we get a reference to the <code>notes</code> object store using {{domxref("IDBDatabase.transaction()")}} and {{domxref("IDBTransaction.objectStore")}} like we did in <code>addData()</code>, except here we are chaining them together in one line.</li>
+ <li>The next step is to use {{domxref("IDBObjectStore.openCursor()")}} method to open a request for a cursor — this is a construct that can be used to iterate over the records in an object store. We chain an <code>onsuccess</code> handler on to the end of this line to make the code more concise — when the cursor is successfully returned, the handler is run.</li>
+ <li>We get a reference to the cursor itself (an {{domxref("IDBCursor")}} object) using let <code>cursor = e.target.result</code>.</li>
+ <li>Next, we check to see if the cursor contains a record from the datastore (<code>if(cursor){ ... }</code>) — if so, we create a DOM fragment, populate it with the data from the record, and insert it into the page (inside the <code>&lt;ul&gt;</code> element). We also include a delete button that, when clicked, will delete that note by running the <code>deleteItem()</code> function, which we will look at in the next section.</li>
+ <li>At the end of the <code>if</code> block, we use the {{domxref("IDBCursor.continue()")}} method to advance the cursor to the next record in the datastore, and run the content of the <code>if</code> block again. If there is another record to iterate to, this causes it to be inserted into the page, and then <code>continue()</code> is run again, and so on.</li>
+ <li>When there are no more records to iterate over, <code>cursor</code> will return <code>undefined</code>, and therefore the <code>else</code> block will run instead of the <code>if</code> block. This block checks whether any notes were inserted into the <code>&lt;ul&gt;</code> — if not, it inserts a message to say no note was stored.</li>
+</ul>
+
+<h3 id="Удаляем_данные">Удаляем данные</h3>
+
+<p>As stated above, when a note's delete button is pressed, the note is deleted. This is achieved by the <code>deleteItem()</code> function, which looks like so:</p>
+
+<pre class="brush: js notranslate">// Define the deleteItem() function
+function deleteItem(e) {
+ // retrieve the name of the task we want to delete. We need
+ // to convert it to a number before trying it use it with IDB; IDB key
+ // values are type-sensitive.
+ let noteId = Number(e.target.parentNode.getAttribute('data-note-id'));
+
+ // open a database transaction and delete the task, finding it using the id we retrieved above
+ let transaction = db.transaction(['notes'], 'readwrite');
+ let objectStore = transaction.objectStore('notes');
+ let request = objectStore.delete(noteId);
+
+ // report that the data item has been deleted
+ transaction.oncomplete = function() {
+ // delete the parent of the button
+ // which is the list item, so it is no longer displayed
+ e.target.parentNode.parentNode.removeChild(e.target.parentNode);
+ console.log('Note ' + noteId + ' deleted.');
+
+ // Again, if list item is empty, display a 'No notes stored' message
+ if(!list.firstChild) {
+ let listItem = document.createElement('li');
+ listItem.textContent = 'No notes stored.';
+ list.appendChild(listItem);
+ }
+ };
+}</pre>
+
+<ul>
+ <li>The first part of this could use some explaining — we retrieve the ID of the record to be deleted using <code>Number(e.target.parentNode.getAttribute('data-note-id'))</code> — recall that the ID of the record was saved in a <code>data-note-id</code> attribute on the <code>&lt;li&gt;</code> when it was first displayed. We do however need to pass the attribute through the global built-in <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number">Number()</a> object, as it is currently a string, and otherwise won't be recognized by the database.</li>
+ <li>We then get a reference to the object store using the same pattern we've seen previously, and use the {{domxref("IDBObjectStore.delete()")}} method to delete the record from the database, passing it the ID.</li>
+ <li>When the database transaction is complete, we delete the note's <code>&lt;li&gt;</code> from the DOM, and again do the check to see if the <code>&lt;ul&gt;</code> is now empty, inserting a note as appropriate.</li>
+</ul>
+
+<p>So that's it! Your example should now work.</p>
+
+<p>If you are having trouble with it, feel free to <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/notes/">check it against our live example</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index.js">source code</a> also).</p>
+
+<h3 id="Храним_сложные_данные_через_IndexedDB">Храним сложные данные через IndexedDB</h3>
+
+<p>As we mentioned above, IndexedDB can be used to store more than just simple text strings. You can store just about anything you want, including complex objects such as video or image blobs. And it isn't much more difficult to achieve than any other type of data.</p>
+
+<p>To demonstrate how to do it, we've written another example called <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/client-side-storage/indexeddb/video-store">IndexedDB video store</a> (see it <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/video-store/">running live here also</a>). When you first run the example, it downloads all the videos from the network, stores them in an IndexedDB database, and then displays the videos in the UI inside {{htmlelement("video")}} elements. The second time you run it, it finds the videos in the database and gets them from there instead befoire displaying them — this makes subsequent loads much quicker and less bandwidth-hungry.</p>
+
+<p>Let's walk through the most interesting parts of the example. We won't look at it all — a lot of it is similar to the previous example, and the code is well-commented.</p>
+
+<ol>
+ <li>
+ <p>For this simple example, we've stored the names of the videos to fetch in an array of objects:</p>
+
+ <pre class="brush: js notranslate">const videos = [
+ { 'name' : 'crystal' },
+ { 'name' : 'elf' },
+ { 'name' : 'frog' },
+ { 'name' : 'monster' },
+ { 'name' : 'pig' },
+ { 'name' : 'rabbit' }
+];</pre>
+ </li>
+ <li>
+ <p>To start with, once the database is successfully opened we run an <code>init()</code> function. This loops through the different video names, trying to load a record identified by each name from the <code>videos</code> database.</p>
+
+ <p>If each video is found in the database (easily checked by seeing whether <code>request.result</code> evaluates to <code>true</code> — if the record is not present, it will be <code>undefined</code>), its video files (stored as blobs) and the video name are passed straight to the <code>displayVideo()</code> function to place them in the UI. If not, the video name is passed to the <code>fetchVideoFromNetwork()</code> function to ... you guessed it — fetch the video from the network.</p>
+
+ <pre class="brush: js notranslate">function init() {
+ // Loop through the video names one by one
+ for(let i = 0; i &lt; videos.length; i++) {
+ // Open transaction, get object store, and get() each video by name
+ let objectStore = db.transaction('videos').objectStore('videos');
+ let request = objectStore.get(videos[i].name);
+ request.onsuccess = function() {
+ // If the result exists in the database (is not undefined)
+ if(request.result) {
+ // Grab the videos from IDB and display them using displayVideo()
+ console.log('taking videos from IDB');
+ displayVideo(request.result.mp4, request.result.webm, request.result.name);
+ } else {
+ // Fetch the videos from the network
+ fetchVideoFromNetwork(videos[i]);
+ }
+ };
+ }
+}</pre>
+ </li>
+ <li>
+ <p>The following snippet is taken from inside <code>fetchVideoFromNetwork()</code> — here we fetch MP4 and WebM versions of the video using two separate {{domxref("fetch()", "WindowOrWorkerGlobalScope.fetch()")}} requests. We then use the {{domxref("blob()", "Body.blob()")}} method to extract each response's body as a blob, giving us an object representation of the videos that can be stored and displayed later on.</p>
+
+ <p>We have a problem here though — these two requests are both asynchronous, but we only want to try to display or store the video when both promises have fulfilled. Fortunately there is a built-in method that handles such a problem — {{jsxref("Promise.all()")}}. This takes one argument — references to all the individual promises you want to check for fulfillment placed in an array — and is itself promise-based.</p>
+
+ <p>When all those promises have fulfilled, the <code>all()</code> promise fulfills with an array containing all the individual fulfillment values. Inside the <code>all()</code> block, you can see that we then call the <code>displayVideo()</code> function like we did before to display the videos in the UI, then we also call the <code>storeVideo()</code> function to store those videos inside the database.</p>
+
+ <pre class="brush: js notranslate">let mp4Blob = fetch('videos/' + video.name + '.mp4').then(response =&gt;
+ response.blob()
+);
+let webmBlob = fetch('videos/' + video.name + '.webm').then(response =&gt;
+ response.blob()
+);;
+
+// Only run the next code when both promises have fulfilled
+Promise.all([mp4Blob, webmBlob]).then(function(values) {
+ // display the video fetched from the network with displayVideo()
+ displayVideo(values[0], values[1], video.name);
+ // store it in the IDB using storeVideo()
+ storeVideo(values[0], values[1], video.name);
+});</pre>
+ </li>
+ <li>
+ <p>Let's look at <code>storeVideo()</code> first. This is very similar to the pattern you saw in the previous example for adding data to the database — we open a <code>readwrite</code> transaction and get an object store reference our <code>videos</code>, create an object representing the record to add to the database, then simply add it using {{domxref("IDBObjectStore.add()")}}.</p>
+
+ <pre class="brush: js notranslate">function storeVideo(mp4Blob, webmBlob, name) {
+ // Open transaction, get object store; make it a readwrite so we can write to the IDB
+ let objectStore = db.transaction(['videos'], 'readwrite').objectStore('videos');
+ // Create a record to add to the IDB
+ let record = {
+ mp4 : mp4Blob,
+ webm : webmBlob,
+ name : name
+ }
+
+ // Add the record to the IDB using add()
+ let request = objectStore.add(record);
+
+ ...
+
+};</pre>
+ </li>
+ <li>
+ <p>Last but not least, we have <code>displayVideo()</code>, which creates the DOM elements needed to insert the video in the UI and then appends them to the page. The most interesting parts of this are those shown below — to actually display our video blobs in a <code>&lt;video&gt;</code> element, we need to create object URLs (internal URLs that point to the video blobs stored in memory) using the {{domxref("URL.createObjectURL()")}} method. Once that is done, we can set the object URLs to be the vaues of our {{htmlelement("source")}} element's <code>src</code> attributes, and it works fine.</p>
+
+ <pre class="brush: js notranslate">function displayVideo(mp4Blob, webmBlob, title) {
+ // Create object URLs out of the blobs
+ let mp4URL = URL.createObjectURL(mp4Blob);
+ let webmURL = URL.createObjectURL(webmBlob);
+
+ ...
+
+ let video = document.createElement('video');
+ video.controls = true;
+ let source1 = document.createElement('source');
+ source1.src = mp4URL;
+ source1.type = 'video/mp4';
+ let source2 = document.createElement('source');
+ source2.src = webmURL;
+ source2.type = 'video/webm';
+
+ ...
+}</pre>
+ </li>
+</ol>
+
+<h2 id="Оффлайн_хранение_данных">Оффлайн хранение данных</h2>
+
+<p>Пример ниже показывает, как создать приложение, которое будет хранить данные большого объема в хранилище IndexedDB, избегая необходимости скачивать их повторно. Это важное улучшение пользовательского опыта, но есть одно замечание — основной HTML, CSS, и файлы JavaScript все еще нужно загружать каждый раз при запросе сайта, это значит, что данный пример не будет работать при отсутствии сетевого соединения.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15759/ff-offline.png" style="border-style: solid; border-width: 1px; display: block; height: 307px; margin: 0px auto; width: 765px;"></p>
+
+<p>Это тот случай, когда <a href="/en-US/docs/Web/API/Service_Worker_API">Service workers</a> и <a href="/en-US/docs/Web/API/Cache">Cache API</a> приходят на помощь.</p>
+
+<p>Сервис-воркер это файл JavaScript, который регистрируется на конкретном источнике (веб-сайте или части сайта на конкретном домене) при обращении браузером. После регистрации, он может управлять страницами на этом источнике. Воркер находится между загруженной страницей и сетевым соединением, перехватывая сетевые запросы источника.</p>
+
+<p>Когда worker перехватывает запрос, он может делать многие вещи (смотри <a href="/en-US/docs/Web/API/Service_Worker_API#Other_use_case_ideas">идеи для использования сервис-воркеров</a>), но классический пример это сохранение сетевых ответов и затем доступ к ним при запросе, вместо запросов по сети. В результате, это позволяет сделать веб-сайт полностью работающим в офлайне.</p>
+
+<p><a href="/en-US/docs/Web/API/Cache">Cache API</a> это еще один механизм хранения данных на клиенте с небольшим отличием — он разработан для хранения HTTP ответов, и прекрасно работает с сервис-воркерами.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Service workers и Cache доступны в большинстве современных браузеров. В момент написания статьи, Safari еще не имел реализации, но скоро должна быть.</p>
+</div>
+
+<h3 id="Пример_сервис_воркера">Пример сервис воркера</h3>
+
+<p>Давайте взглянем на пример, чтобы дать вам немного мыслей о том, что из этого может выйти. Мы создали другую версию примера хранения видео, который использовался в предыдущей секции — эта функциональность идентична, за исключением того, что этот пример также сохраняет HTML, CSS, и JavaScript в Cache API посредством сервис-воркеров, что позволяет приложению работать полностью в офлайне!</p>
+
+<p>Смотри пример <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/">хранилище видео с IndexedDB и сервис-воркером</a>, и его <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/client-side-storage/cache-sw/video-store-offline">исходный код</a>.</p>
+
+<h4 id="Регистрируем_сервис_воркер">Регистрируем сервис воркер</h4>
+
+<p>Первое, что нужно заметить, это дополнительный кусок кода, расположенный в основном JavaScript файле (см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js">index.js</a>). Первое,что мы делаем, это проверка на то, что <code>serviceWorker</code> доступен в объекте {{domxref("Navigator")}}. Если этот так, тогда мы знаем, что как минимум, базовые функции сервис-воркера доступны. Внутри проверки мы используем метод {{domxref("ServiceWorkerContainer.register()")}} для регистрации сервис-воркера, находящегося в файле <code>sw.js</code> на текущем источнике, таким образом, он может управлять страницами в текущей или внутренних директориях. Когда обещание выполнится, сервис-воркер считается зарегистрированным.</p>
+
+<pre class="brush: js notranslate"> // Регистрация сервис-воркера для обеспечения оффлайн доступности сайта
+
+ if('serviceWorker' in navigator) {
+ navigator.serviceWorker
+ .register('/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js')
+ .then(function() { console.log('Service Worker зарегистрирован'); });
+ }</pre>
+
+<div class="note">
+<p><strong>Примечание</strong>: Путь к файлу <code>sw.js</code> указан относительно корня сайта, а не JavaScript файла, содержащего основной код. Полный путь - <code>https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code>. Корень -  <code>https://mdn.github.io</code>, и следовательно указываемый путь должен быть <code>/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code>. Если вы хотите использовать данный пример на своем сервере, вы также должны изменить путь к скрипту. Это довольно запутанно, но обязано так работать по причинам безопасности.</p>
+</div>
+
+<h4 id="Устанавливаем_сервис_воркер">Устанавливаем сервис воркер</h4>
+
+<p>В следующий раз, когда страница с сервис-воркером будет запрошена (например когда страница будет перезагружена), сервис-воркер запустится на этой странице и начнет контролировать её. Когда это произойдет, событие <code>install</code> будет вызвано в сервис-воркере; вы можете написать код внутри сервис-воркера, который будет вызван в процессе установки.</p>
+
+<p>Давайте взглянем на файл сервис-воркера <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js">sw.js</a>. Вы можете видеть, что слушатель события <code>install</code> зарегистрирован на <code>self</code>. Ключевое слово <code>self</code> это способ ссылки на глобальную область видимости сервис-воркера из файла с сервис-воркером.</p>
+
+<p>Внутри обработчика <code>install</code> мы используем метод {{domxref("ExtendableEvent.waitUntil()")}}, доступном в объекте события, чтобы сигнализировать, что работа продолжается, и браузер не должен завершать установку, пока все задачи внутри блока не будут выполнены.</p>
+
+<p>Здесь мы видим Cache API в действии. Мы используем метод {{domxref("CacheStorage.open()")}} для открытия нового объекта кэша, в котором ответы могут быть сохранены (похоже на объект хранилища IndexedDB). Обещание выполнится с объектом {{domxref("Cache")}}, представляющим собой кэш <code>video-store</code> . Затем мы используем метод {{domxref("Cache.addAll()")}} для получения ресурсов и добавления ответов в кэш.</p>
+
+<pre class="brush: js notranslate">self.addEventListener('install', function(e) {
+ e.waitUntil(
+ caches.open('video-store').then(function(cache) {
+ return cache.addAll([
+ '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/',
+ '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.html',
+ '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js',
+ '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/style.css'
+ ]);
+ })
+ );
+});</pre>
+
+<p>На этом установка завершена.</p>
+
+<h4 id="Отвечаем_на_последующие_запросы">Отвечаем на последующие запросы</h4>
+
+<p>Когда сервис-воркер зарегистрирован и установлен на странице HTML и сопутствующие ресурсы добавлены в кэш, все практически готово. Нужно сделать еще одну вещь - написать код для ответа на дальнейшие сетевые запросы.</p>
+
+<p>Это то, что делает вторая часть кода файла <code>sw.js</code>. Мы добавили еще один слушатель к сервис-воркеру в глобальной области видимости, который запускает функцию-обработчик при событии <code>fetch</code>. Это происходит всякий раз, когда браузер делает запрос ресурса в директорию, где зарегистрирован сервис-воркер.</p>
+
+<p>Внутри обработчика, мы сначала выводим в консоль URL запрашиваемого ресурса. Затем отдаем особый ответ на запрос, используя метод {{domxref("FetchEvent.respondWith()")}}.</p>
+
+<p>Внутри блока мы используем {{domxref("CacheStorage.match()")}} чтобы проверить, можно ли найти соответствующий запрос (т.е. совпадение по URL) в кэше. Обещание возвращает найденный ответ или <code>undefined</code>, если ничего не нашлось.</p>
+
+<p>Если совпадение нашлось, то просто возвращаем его как особый ответ. В противном случае, используем <a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a> для запроса ресурса из сети.</p>
+
+<pre class="brush: js notranslate">self.addEventListener('fetch', function(e) {
+ console.log(e.request.url);
+ e.respondWith(
+ caches.match(e.request).then(function(response) {
+ return response || fetch(e.request);
+ })
+ );
+});</pre>
+
+<p>На этом все для нашего простого сервис-воркера. Используя подобный метод, вы можете сделать гораздо больше вещей — для получения доп. информации смотрите <a href="https://serviceworke.rs/">рецепты использования сервис-воркеров</a>. Спасибо Paul Kinlan за его статью <a href="https://developers.google.com/web/fundamentals/codelabs/offline/">Adding a Service Worker and Offline into your Web App</a>, которая вдохновила на написание данного примера.</p>
+
+<h4 id="Тестируем_наш_пример_оффлайн">Тестируем наш пример оффлайн</h4>
+
+<p>Для тестирования <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/">примера</a>, вам нужно загрузить его несколько раз, чтобы быть уверенным, что сервис-воркер точно установлен. Когда это сделано, вы можете:</p>
+
+<ul>
+ <li>отключиться от сетевого соединения.</li>
+ <li>нажмите <em>Файл &gt; Перейти в офлайн, </em>если вы используете<em> </em>Firefox.</li>
+ <li>перейдите в инструменты разработчика, выберите <em>Application &gt; Service Workers</em>, нажмите галочку <em>Offline</em>, если используете Chrome.</li>
+</ul>
+
+<p>Если обновите страницу с примером снова, вы увидите, что все работает как обычно. Все данные хранятся в офлайн хранилище — ресурсы страницы в кэше, а видео в базе данных IndexedDB.</p>
+
+<h2 id="Итого">Итого</h2>
+
+<p>Это всё, пока что. Мы надеемся наш краткий обзор <code>client-side storage</code> окажется полезным для вас.</p>
+
+<h2 id="Также_стоит_почитать">Также стоит почитать</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/API/Web_Storage_API">Web storage API</a></li>
+ <li><a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a></li>
+ <li><a href="/en-US/docs/Web/HTTP/Cookies">Cookies</a></li>
+ <li><a href="/en-US/docs/Web/API/Service_Worker_API">Service worker API</a></li>
+</ul>
+
+<p>{{PreviousMenu("Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</p>
+
+<h2 id="В_этом_модуле">В этом модуле</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li>
+</ul>
diff --git a/files/ru/learn/javascript/client-side_web_apis/fetching_data/index.html b/files/ru/learn/javascript/client-side_web_apis/fetching_data/index.html
new file mode 100644
index 0000000000..63d9010aab
--- /dev/null
+++ b/files/ru/learn/javascript/client-side_web_apis/fetching_data/index.html
@@ -0,0 +1,379 @@
+---
+title: Получение данных с сервера
+slug: Learn/JavaScript/Client-side_web_APIs/Fetching_data
+tags:
+ - AJAX
+ - API
+ - Fetch
+ - JavaScript
+ - XHR
+ - Новичку
+translation_of: Learn/JavaScript/Client-side_web_APIs/Fetching_data
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs/Third_party_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</div>
+
+<p class="summary"><span lang="ru">Другой очень распространенной задачей в современных веб-сайтах и ​​приложениях является получение отдельных элементов данных с сервера для обновления разделов веб-страницы без необходимости загрузки всей новой страницы. Эта, казалось бы, небольшая деталь оказала огромное влияние на производительность и поведение сайтов, поэтому в этой статье мы объясним концепцию и рассмотрим технологии, которые делают это возможным, например XMLHttpRequest и API Fetch.</span></p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Необходимые условия:</th>
+ <td>Основы JavaScript (см. <a href="/en-US/docs/Learn/JavaScript/First_steps">первые шаги</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">структурные элементы</a>, <a href="/en-US/docs/Learn/JavaScript/Objects">объекты JavaScript</a>), <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">основы клиентских API</a></td>
+ </tr>
+ <tr>
+ <th scope="row">Задача:</th>
+ <td>Узнать, как извлекать данные с сервера и использовать их для обновления содержимого веб-страницы.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="В_чем_проблема">В чем проблема?</h2>
+
+<p>Первоначальная загрузка страницы в Интернете была простой - вы отправляли запрос на сервер  web-сайта, и если всё работает, как и должно, то вся необходимая информация о странице будет загружена и отображена на вашем компьютере.</p>
+
+<p><img alt="A basic representation of a web site architecture" src="https://mdn.mozillademos.org/files/6475/web-site-architechture@2x.png" style="display: block; height: 134px; margin: 0px auto; width: 484px;"></p>
+
+<p>Проблема с этой моделью заключается в том, что всякий раз, когда вы хотите обновить любую часть страницы, например, чтобы отобразить новый набор продуктов или загрузить новую страницу, вам нужно снова загрузить всю страницу. Это очень расточительно и приводит к плохому пользовательскому опыту, особенно по мере того, как страницы становятся все более сложными.</p>
+
+<h3 id="Появление_Ajax">Появление Ajax</h3>
+
+<p>Это привело к созданию технологий, позволяющих веб-страницам запрашивать небольшие фрагменты данных (например, <a href="https://developer.mozilla.org/en-US/docs/Web/HTML">HTML</a>, {{glossary("XML")}}, <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON">JSON</a> или обычный текст) и отображать их только при необходимости, помогая решать проблему, описанную выше.</p>
+
+<p>Это достигается с помощью таких API, как {{domxref("XMLHttpRequest")}} или - более новой - <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>. Эти технологии позволяют веб-страницам напрямую обрабатывать запросы <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP">HTTP</a> для определенных ресурсов, доступных на сервере, и форматировать результирующие данные по мере необходимости перед их отображением.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Вначале эта общая техника была известна как Асинхронный JavaScript и XML (Ajax), поскольку она, как правило, использовала {{domxref("XMLHttpRequest")}} для запроса данных XML. В наши дни это обычно не так (вы, скорее всего, будете использовать <code>XMLHttpRequest</code> или Fetch для запроса JSON), но результат все тот же, и термин «Ajax» по-прежнему часто используется для описания этой техники.</p>
+</div>
+
+<p><img alt="A simple modern architecture for web sites" src="https://mdn.mozillademos.org/files/6477/moderne-web-site-architechture@2x.png" style="display: block; height: 235px; margin: 0px auto; width: 559px;"></p>
+
+<p>Модель Ajax предполагает использование веб-API в качестве прокси для более разумного запроса данных, а не просто для того, чтобы браузер перезагружал всю страницу. Давайте подумаем о значении этого:</p>
+
+<ol>
+ <li>Перейдите на один из ваших любимых сайтов, богатых информацией, таких как Amazon, YouTube, CNN и т.д., и загрузите его.</li>
+ <li>Теперь найдите что-нибудь, например, новый продукт. Основной контент изменится, но большая часть информации, подобной заголовку, нижнему колонтитулу, навигационному меню и т. д., останется неизменной.</li>
+</ol>
+
+<p>Это действительно хорошо, потому что:</p>
+
+<ul>
+ <li>Обновления страницы намного быстрее, и вам не нужно ждать перезагрузки страницы, а это означает, что сайт работает быстрее и воспринимается более отзывчивым.</li>
+ <li>Меньше данных загружается при каждом обновлении, что означает меньшее потребление пропускной способности. Это не может быть такой большой проблемой на рабочем столе в широкополосном подключении, но это серьезная проблема на мобильных устройствах и в развивающихся странах, которые не имеют повсеместного быстрого интернет-сервиса.</li>
+</ul>
+
+<p>Чтобы ускорить работу, некоторые сайты также сохраняют необходимые файлы и данные на компьютере пользователя при первом обращении к сайту, а это означает, что при последующих посещениях они используют локальные версии вместо загрузки свежих копий,  как при первой загрузке страницы. Содержимое загружается с сервера только при его обновлении.</p>
+
+<p><img alt="A basic web app data flow architecture" src="https://mdn.mozillademos.org/files/6479/web-app-architecture@2x.png" style="display: block; height: 383px; margin: 0px auto; width: 562px;"></p>
+
+<h2 id="Основной_запрос_Ajax">Основной запрос Ajax</h2>
+
+<p>Давайте посмотрим, как обрабатывается такой запрос, используя как {{domxref ("XMLHttpRequest")}}, так и <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch</a>. В этих примерах мы будем запрашивать данные из нескольких текстовых файлов и использовать их для заполнения области содержимого.</p>
+
+<p>Этот набор файлов будет действовать как наша поддельная база данных; в реальном приложении мы с большей вероятностью будем использовать серверный язык, такой как PHP, Python или Node, чтобы запрашивать наши данные из базы данных. Здесь, однако, мы хотим сохранить его простым и сосредоточиться на стороне клиента.</p>
+
+<h3 id="XMLHttpRequest">XMLHttpRequest</h3>
+
+<p><code>XMLHttpRequest</code> (который часто сокращается до XHR) является довольно старой технологией сейчас - он был изобретен Microsoft в конце 1990-х годов и уже довольно долго стандартизирован в браузерах.</p>
+
+<ol>
+ <li>
+ <p>Чтобы начать этот пример, создайте локальную копию <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/ajax-start.html">ajax-start.html</a> и четырех текстовых файлов - <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse1.txt">verse1.txt</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse2.txt">verse2.txt</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse3.txt">verse3.txt</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse4.txt">verse4.txt</a> - в новом каталоге на вашем компьютере. В этом примере мы загрузим другое стихотворение (который вы вполне можете распознать) через XHR, когда он будет выбран в выпадающем меню.</p>
+ </li>
+ <li>
+ <p>Внутри элемента {{htmlelement("script")}} добавьте следующий код. В нем хранится ссылка на элементы {{htmlelement("select")}} и {{htmlelement("pre")}} в переменных и определяется {{domxref ("GlobalEventHandlers.onchange", "onchange")}} обработчика событий, так что, когда значение select изменяется, его значение передается вызываемой функции <code>updateDisplay()</code> в качестве параметра.</p>
+
+ <pre class="brush: js">var verseChoose = document.querySelector('select');
+var poemDisplay = document.querySelector('pre');
+
+verseChoose.onchange = function() {
+ var verse = verseChoose.value;
+ updateDisplay(verse);
+};</pre>
+ </li>
+ <li>
+ <p>Давайте определим нашу функцию <code>updateDisplay()</code>. Прежде всего, поставьте следующее ниже своего предыдущего блока кода - это пустая оболочка функции:</p>
+
+ <pre class="brush: js">function updateDisplay(verse) {
+
+};</pre>
+ </li>
+ <li>
+ <p>Мы начнем нашу функцию с создания относительного URL-адреса, указывающего на текстовый файл, который мы хотим загрузить и который понадобится нам позже. Значение элемента {{htmlelement("select")}} в любой момент совпадает с текстом внутри выбранного {{htmlelement("option")}} (если вы не укажете другое значение в атрибуте value) - например, «Verse 1». Соответствующий текстовый файл стиха является «verse1.txt» и находится в том же каталоге, что и файл HTML, поэтому будет использоваться только имя файла.</p>
+
+ <p>Тем не менее, веб-серверы, как правило, чувствительны к регистру, и имя файла не имеет символа "пробела". Чтобы преобразовать «Verse 1» в «verse1.txt», нам нужно преобразовать V в нижний регистр, удалить пробел и добавить .txt в конец. Это можно сделать с помощью {{jsxref("String.replace", "replace ()")}}, {{jsxref("String.toLowerCase", "toLowerCase ()")}} и простой <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Strings#Concatenating_strings">конкатенации строк</a>. Добавьте следующие строки внутри функции <code>updateDisplay()</code>:</p>
+
+ <pre class="brush: js">verse = verse.replace(" ", "");
+verse = verse.toLowerCase();
+var url = verse + '.txt';</pre>
+ </li>
+ <li>
+ <p>Чтобы начать создание запроса XHR, вам нужно создать новый объект запроса, используя конструктор {{domxref("XMLHttpRequest()")}}. Вы можете назвать этот объект так, как вам нравится, но мы будем называть его <code>request</code> (запросом), чтобы все было просто. Добавьте следующие ниже строки:</p>
+
+ <pre class="brush: js">var request = new XMLHttpRequest();</pre>
+ </li>
+ <li>
+ <p>Затем вам нужно использовать метод {{domxref("XMLHttpRequest.open", "open()")}}, чтобы указать, какой <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods">HTTP request method</a> использовать для запроса ресурса из сети и какой его URL-адрес. Мы просто используем метод <code><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET">GET</a></code> здесь и задаем URL как нашу переменную <code>url</code>. Добавьте это ниже вашей предыдущей строки:</p>
+
+ <pre class="brush: js">request.open('GET', url);</pre>
+ </li>
+ <li>
+ <p>Затем мы зададим тип ожидаемого ответа, который определяется как свойство {{domxref("XMLHttpRequest.responseType", "responseType")}} - как <code>text</code>. Здесь это не является абсолютно необходимым - XHR возвращает текст по умолчанию - но это хорошая идея, чтобы привыкнуть к настройке этого, если вы хотите получить другие типы данных в будущем. Добавьте следующее:</p>
+
+ <pre class="brush: js">request.responseType = 'text';</pre>
+ </li>
+ <li>
+ <p>Получение ресурса из сети - это {{glossary("asynchronous")}} операция, означающая, что вам нужно дождаться завершения этой операции (например, ресурс возвращается из сети), прежде чем вы сможете сделать что-либо с этим ответом, иначе будет выброшена ошибка. XHR позволяет вам обрабатывать это, используя обработчик события {{domxref("XMLHttpRequest.onload", "onload")}} - он запускается при возникновении события {{event("load")}} (когда ответ вернулся). Когда это произойдет, данные ответа будут доступны в свойстве <code>response</code> (ответ) объекта запроса XHR.</p>
+
+ <p>Добавьте следующее ниже вашего последнего дополнения. Вы увидите, что внутри обработчика события <code>onload</code> мы устанавливаем textContent <code>poemDisplay</code> (элемент {{htmlelement("pre")}}) в значение {{domxref("XMLHttpRequest.response", "request. response ")}}.</p>
+
+ <pre class="brush: js">request.onload = function() {
+ poemDisplay.textContent = request.response;
+};</pre>
+ </li>
+ <li>
+ <p>Вышеприведенная конфигурация запроса XHR  фактически не будет выполняться до тех пор, пока мы не вызовем метод {{domxref("XMLHttpRequest.send", "send()")}}. Добавьте следующее ниже вашего предыдущего дополнения для вызова функции:</p>
+
+ <pre class="brush: js">request.send();</pre>
+ </li>
+ <li>
+ <p>Одна из проблем с примером заключается в том, что он не покажет ни одного стихотворения, когда он впервые загружается. Чтобы исправить это, добавьте следующие две строки внизу вашего кода (чуть выше закрывающего тега <code>&lt;/script&gt;</code>), чтобы загрузить стих 1 по умолчанию и убедитесь, что элемент {{htmlelement("select")}} всегда показывает правильное значение:</p>
+
+ <pre class="brush: js">updateDisplay('Verse 1');
+verseChoose.value = 'Verse 1';</pre>
+ </li>
+</ol>
+
+<h3 id="Обслуживание_вашего_примера_с_сервера">Обслуживание вашего примера с сервера</h3>
+
+<p>Некоторые браузеры (включая Chrome) не будут запускать запросы XHR, если вы просто запускаете пример из локального файла. Это связано с ограничениями безопасности (для получения дополнительной информации о безопасности в Интернете, ознакомьтесь с <a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a>).</p>
+
+<p>Чтобы обойти это, нам нужно протестировать пример, запустив его через локальный веб-сервер. Чтобы узнать, как это сделать, прочитайте <a href="/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">Как настроить локальный тестовый сервер?</a></p>
+
+<h3 id="Fetch">Fetch</h3>
+
+<p>API-интерфейс Fetch - это, в основном, современная замена XHR - недавно он был представлен в браузерах для упрощения асинхронных HTTP-запросов в JavaScript, как для разработчиков, так и для других API, которые строятся поверх Fetch.</p>
+
+<p>Давайте преобразуем последний пример, чтобы использовать Fetch!</p>
+
+<ol>
+ <li>
+ <p>Сделайте копию своего предыдущего готового каталога примеров. (Если вы не работали над предыдущим упражнением, создайте новый каталог и внутри него создайте копии <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/xhr-basic.html">xhr-basic.html</a> и четырех текстовых файлов — <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse1.txt">verse1.txt</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse2.txt">verse2.txt</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse3.txt">verse3.txt</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse4.txt">verse4.txt</a>.)</p>
+ </li>
+ <li>
+ <p>Внутри функции <code>updateDisplay()</code> найдите код XHR:</p>
+
+ <pre class="brush: js">var request = new XMLHttpRequest();
+request.open('GET', url);
+request.responseType = 'text';
+
+request.onload = function() {
+ poemDisplay.textContent = request.response;
+};
+
+request.send();</pre>
+ </li>
+ <li>
+ <p>Замените весь XHR-код следующим:</p>
+
+ <pre class="brush: js">fetch(url).then(function(response) {
+ response.text().then(function(text) {
+ poemDisplay.textContent = text;
+ });
+});</pre>
+ </li>
+ <li>
+ <p>Загрузите пример в свой браузер (запустите его через веб-сервер), и он должен работать так же, как и версия XHR, при условии, что вы используете современный браузер.</p>
+ </li>
+</ol>
+
+<h4 id="Итак_что_происходит_в_коде_Fetch">Итак, что происходит в коде Fetch?</h4>
+
+<p>Прежде всего, мы вызываем метод {{domxref("WorkerOrWindowGlobalScope.fetch()", "fetch()")}}, передавая ему URL-адрес ресурса, который мы хотим получить. Это современный эквивалент {{domxref("XMLHttpRequest.open", "request.open()")}} в XHR, плюс вам не нужен эквивалент <code>.send()</code>.</p>
+
+<p>После этого вы можете увидеть метод {{jsxref("Promise.then", ".then()")}}, прикреплённый в конец <code>fetch()</code> - этот метод является частью {{jsxref("Promise","Promises")}} - современная функция JavaScript для выполнения асинхронных операций. <code>fetch()</code> возвращает обещание, которое разрешает ответ, отправленный обратно с сервера, - мы используем <code>.then()</code> для запуска некоторого последующего кода после того, как обещание будет разрешено, что является функцией, которую мы определили внутри нее. Это эквивалент обработчика события <code>onload</code> в XHR-версии.</p>
+
+<p>Эта функция автоматически передает ответ от сервера в качестве параметра, когда обещает <code>fetch()</code>. Внутри функции мы берем ответ и запускаем его метод {{domxref("Body.text", "text()")}}, который в основном возвращает ответ как необработанный текст. Это эквивалент <code>request.responseType = 'text'</code> в версии XHR.</p>
+
+<p>Вы увидите, что <code>text()</code>также возвращает обещание, поэтому мы привязываем к нему другой <code>.then()</code>, внутри которого мы определяем функцию для получения необработанного текста, который обещает решение <code>text()</code>.</p>
+
+<p>Внутри функции внутреннего обещания мы делаем то же самое, что и в версии XHR, - устанавливаем текстовое содержимое {{htmlelement("pre")}} в текстовое значение.</p>
+
+<h3 id="Помимо_обещаний">Помимо обещаний</h3>
+
+<p>Обещания немного запутывают первый раз, когда вы их встречаете, но не беспокойтесь об этом слишком долго. Через некоторое время вы привыкнете к ним, особенно, когда вы узнаете больше о современных JavaScript-API. Большинство из них в большей степени основаны на обещаниях.</p>
+
+<p>Давайте посмотрим на структуру обещаний сверху, чтобы увидеть, можем ли мы еще немного понять это:</p>
+
+<pre class="brush: js">fetch(url).then(function(response) {
+ response.text().then(function(text) {
+ poemDisplay.textContent = text;
+ });
+});</pre>
+
+<p>В первой строке говорится: «Получить ресурс, расположенный по адресу url» <code>(fetch(url)</code>) и «затем запустить указанную функцию, когда обещание будет разрешено» (<code>.then(function() { ... })</code>). «Resolve» означает «завершить выполнение указанной операции в какой-то момент в будущем». Указанная операция в этом случае заключается в извлечении ресурса с указанного URL (с использованием HTTP-запроса) и возврата ответа для нас, чтобы что-то сделать.</p>
+
+<p>Фактически, функция, переданная в <code>then()</code>, представляет собой кусок кода, который не запускается немедленно - вместо этого он будет работать в какой-то момент в будущем, когда ответ будет возвращен. Обратите внимание, что вы также можете сохранить свое обещание в переменной и цепочку {{jsxref("Promise.then", ".then()")}} вместо этого. Ниже код будет делать то же самое:</p>
+
+<pre class="brush: js">var myFetch = fetch(url);
+
+myFetch.then(function(response) {
+ response.text().then(function(text) {
+ poemDisplay.textContent = text;
+ });
+});</pre>
+
+<p>Поскольку метод <code>fetch()</code> возвращает обещание, которое разрешает HTTP-ответ, любая функция, которую вы определяете внутри <code>.then()</code>, прикованная к концу, будет автоматически передаваться как параметр. Вы можете вызвать параметр, который вам нравится - приведенный ниже пример будет работать:</p>
+
+<pre class="brush: js">fetch(url).then(function(dogBiscuits) {
+ dogBiscuits.text().then(function(text) {
+ poemDisplay.textContent = text;
+ });
+});</pre>
+
+<p>Но имеет смысл называть параметр тем, что описывает его содержимое!</p>
+
+<p>Теперь давайте сосредоточимся только на функции:</p>
+
+<pre class="brush: js">function(response) {
+ response.text().then(function(text) {
+ poemDisplay.textContent = text;
+ });
+}</pre>
+
+<p>Объект ответа имеет метод {{domxref("Body.text", "text()")}}, который берет необработанные данные, содержащиеся в теле ответа, и превращает его в обычный текст, который является форматом, который мы хотим в нем А также возвращает обещание (которое разрешает полученную текстовую строку), поэтому здесь мы используем другой {{jsxref("Promise.then", ".then()")}}, внутри которого мы определяем другую функцию, которая диктует что мы хотим сделать с этой текстовой строкой. Мы просто устанавливаем свойство <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent">textContent</a></code> элемента {{htmlelement("pre")}} нашего стихотворения равным текстовой строке, так что это получается довольно просто.</p>
+
+<p>Также стоит отметить, что вы можете напрямую связывать несколько блоков обещаний (<code>.then()</code>, но есть и другие типы) на конце друг друга, передавая результат каждого блока следующему блоку по мере продвижения по цепочке , Это делает обещания очень мощными.</p>
+
+<p>Следующий блок делает то же самое, что и наш оригинальный пример, но написан в другом стиле:</p>
+
+<pre class="brush: js">fetch(url).then(function(response) {
+ return response.text()
+}).then(function(text) {
+ poemDisplay.textContent = text;
+});</pre>
+
+<p>Многие разработчики любят этот стиль больше, поскольку он более плоский и, возможно, легче читать для более длинных цепочек обещаний - каждое последующее обещание приходит после предыдущего, а не внутри предыдущего (что может стать громоздким). Единственное отличие состоит в том, что мы должны были включить оператор <code><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">return</a></code> перед <code>response.text()</code>, чтобы заставить его передать результат в следующую ссылку в цепочке.</p>
+
+<h3 id="Какой_механизм_следует_использовать">Какой механизм следует использовать?</h3>
+
+<p>Это действительно зависит от того, над каким проектом вы работаете. XHR существует уже давно и имеет отличную кросс-браузерную поддержку. Fetch and Promises, с другой стороны, являются более поздним дополнением к веб-платформе, хотя они хорошо поддерживаются в браузере, за исключением Internet Explorer и Safari (которые на момент написания Fetch были доступны в своем предварительный просмотр технологии).</p>
+
+<p>Если вам необходимо поддерживать старые браузеры, тогда может быть предпочтительным решение XHR. Если, однако, вы работаете над более прогрессивным проектом и не так обеспокоены старыми браузерами, то Fetch может быть хорошим выбором.</p>
+
+<p>Вам действительно нужно учиться - Fetch станет более популярным, так как Internet Explorer отказывается от использования (IE больше не разрабатывается, в пользу нового браузера Microsoft Edge), но вам может понадобиться XHR еще некоторое время.</p>
+
+<h2 id="Более_сложный_пример">Более сложный пример</h2>
+
+<p>Чтобы завершить статью, мы рассмотрим несколько более сложный пример, который показывает более интересные применения Fetch. Мы создали образец сайта под названием The Can Store - это вымышленный супермаркет, который продает только консервы. Вы можете найти этот пример <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/">в прямом эфире на GitHub</a> и <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/fetching-data/can-store">посмотреть исходный код</a>.</p>
+
+<p><img alt="A fake ecommerce site showing search options in the left hand column, and product search results in the right hand column." src="https://mdn.mozillademos.org/files/14779/can-store.png" style="display: block; margin: 0 auto;"></p>
+
+<p>По умолчанию на сайте отображаются все продукты, но вы можете использовать элементы управления формы в столбце слева, чтобы отфильтровать их по категориям, поисковому запросу или и тому и другому.</p>
+
+<p>Существует довольно много сложного кода, который включает фильтрацию продуктов по категориям и поисковым запросам, манипулирование строками, чтобы данные отображались правильно в пользовательском интерфейсе и т.д. Мы не будем обсуждать все это в статье, но вы можете найти обширные комментарии в коде (см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store/can-script.js">can-script.js</a>).</p>
+
+<p>Однако мы объясним код Fetch.</p>
+
+<p>Первый блок, который использует Fetch, можно найти в начале JavaScript:</p>
+
+<pre class="brush: js">fetch('products.json').then(function(response) {
+ if(response.ok) {
+ response.json().then(function(json) {
+ products = json;
+ initialize();
+ });
+ } else {
+ console.log('Network request for products.json failed with response ' + response.status + ': ' + response.statusText);
+ }
+});</pre>
+
+<p>Это похоже на то, что мы видели раньше, за исключением того, что второе обещание находится в условном выражении. В этом случае мы проверяем, был ли возвращенный ответ успешным - свойство {{domxref("response.ok")}} содержит логическое значение, которое <code>true</code>, если ответ был в порядке (например, <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200">200 meaning "OK"</a>) или <code>false</code>, если он не увенчался успехом.</p>
+
+<p>Если ответ был успешным, мы выполняем второе обещание - на этот раз мы используем {{domxref("Body.json", "json()")}}, а не {{domxref("Body.text", "text()")}}, так как мы хотим вернуть наш ответ как структурированные данные JSON, а не обычный текст.</p>
+
+<p>Если ответ не увенчался успехом, мы выводим сообщение об ошибке в консоль, в котором сообщается о сбое сетевого запроса, который сообщает о статусе сети и описательном сообщении ответа (содержащемся в {{domxref("response.status")}} и {{domxref("response.statusText")}}, соответственно). Конечно, полный веб-сайт будет обрабатывать эту ошибку более грациозно, отображая сообщение на экране пользователя и, возможно, предлагая варианты для исправления ситуации.</p>
+
+<p>Вы можете проверить сам случай отказа:</p>
+
+<ol>
+ <li>Создание локальной копии файлов примеров (загрузка и распаковка <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store/can-store.zip?raw=true">the can-store ZIP file</a>)</li>
+ <li>Запустите код через веб-сервер (как описано выше, в {{anch("Serving your example from a server")}})</li>
+ <li>Измените путь к извлеченному файлу, например, «product.json» (т.е. убедитесь, что он написан неправильно)</li>
+ <li>Теперь загрузите индексный файл в свой браузер (например, через <code>localhost:8000</code>) и посмотрите в консоли разработчика браузера. Вы увидите сообщение в строке «Запрос сети для продуктов.json не удалось с ответом 404: Файл не найден»</li>
+</ol>
+
+<p>Второй блок Fetch можно найти внутри функции <code>fetchBlob()</code>:</p>
+
+<pre class="brush: js">fetch(url).then(function(response) {
+ if(response.ok) {
+ response.blob().then(function(blob) {
+ objectURL = URL.createObjectURL(blob);
+ showProduct(objectURL, product);
+ });
+ } else {
+ console.log('Network request for "' + product.name + '" image failed with response ' + response.status + ': ' + response.statusText);
+ }
+});</pre>
+
+<p>Это работает во многом так же, как и предыдущий, за исключением того, что вместо использования {{domxref("Body.json", "json()")}} мы используем {{domxref("Body.blob", "blob()")}} - в этом случае мы хотим вернуть наш ответ в виде файла изображения, а формат данных, который мы используем для этого - <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a> - этот термин является аббревиатурой от« Binary Large Object »и может в основном использоваться для представляют собой большие файловые объекты, такие как изображения или видеофайлы.</p>
+
+<p>После того как мы успешно получили наш blob, мы создаем URL-адрес объекта, используя {{domxref("URL.createObjectURL()", "createObjectURL()")}}. Это возвращает временный внутренний URL-адрес, указывающий на объект, указанный в браузере. Они не очень читаемы, но вы можете видеть, как выглядит, открывая приложение Can Store, Ctrl-/щелкнуть правой кнопкой мыши по изображению и выбрать опцию «Просмотр изображения» (которая может немного отличаться в зависимости от того, какой браузер вы ). URL-адрес объекта будет отображаться внутри адресной строки и должен выглядеть примерно так:</p>
+
+<pre>blob:http://localhost:7800/9b75250e-5279-e249-884f-d03eb1fd84f4</pre>
+
+<h3 id="Вызов_XHR_версия_the_Can_Store">Вызов: XHR версия the Can Store</h3>
+
+<p>Мы хотели бы, чтобы вы решили преобразовать версию приложения Fetch для использования XHR в качестве полезной части практики. Возьмите <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store/can-store.zip?raw=true">копию ZIP файла</a> и попробуйте изменить JavaScript, если это необходимо.</p>
+
+<p>Некоторые полезные советы:</p>
+
+<ul>
+ <li>Вы можете найти полезный справочный материал {{domxref("XMLHttpRequest")}}.</li>
+ <li>Вам в основном нужно использовать тот же шаблон, что и раньше, в примере <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/xhr-basic.html">XHR-basic.html</a>.</li>
+ <li>Однако вам нужно будет добавить обработку ошибок, которые мы показали вам в версии Fetch Can Store:
+ <ul>
+ <li>Ответ найден в <code>request.response</code> после того, как событие <code>load</code> запущено, а не в обещании <code>then()</code>.</li>
+ <li>О наилучшем эквиваленте Fetch's <code>response.ok</code> в XHR следует проверить, является ли {{domxref("XMLHttpRequest.status","request.status")}} равным 200 или если {{domxref("XMLHttpRequest.readyState","request.readyState")}} равно 4.</li>
+ <li>Свойства для получения статуса и сообщения состояния одинаковы, но они находятся на объекте <code>request</code> (XHR), а не в объекте <code>response</code>.</li>
+ </ul>
+ </li>
+</ul>
+
+<div class="note">
+<p><strong>Примечание</strong>: Если у вас есть проблемы с этим, не стесняйтесь сравнить свой код с готовой версией на GitHub (<a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store-xhr/can-script.js">см. исходник здесь</a>, а также <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store-xhr/">см. это в действии</a>).</p>
+</div>
+
+<h2 id="Резюме">Резюме</h2>
+
+<p>Это завершает нашу статью по извлечению данных с сервера. К этому моменту вы должны иметь представление о том, как начать работать как с XHR, так и с Fetch.</p>
+
+<h2 id="Смотрите_также">Смотрите также</h2>
+
+<p>Однако в этой статье обсуждается много разных тем, которые только поцарапали поверхность. Для получения более подробной информации по этим темам, попробуйте следующие статьи:</p>
+
+<ul>
+ <li><a href="/en-US/docs/AJAX/Getting_Started">Введение в Ajax</a></li>
+ <li><a href="/en-US/docs/Web/API/Fetch_API/Using_Fetch">Применение Fetch</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Работа с JSON данными</a></li>
+ <li><a href="/en-US/docs/Web/HTTP/Overview">Обзор HTTP</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side">Программирование веб-сайта на стороне сервера</a></li>
+</ul>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs/Third_party_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</div>
+
+<div>
+<h2 id="В_этом_модуле">В этом модуле</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Введение в web API</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Манипулирование документами</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Получение данных с сервера</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Сторонние API</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Рисование графики</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Видео и аудио API</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Клиентское хранилище</a></li>
+</ul>
+</div>
diff --git a/files/ru/learn/javascript/client-side_web_apis/index.html b/files/ru/learn/javascript/client-side_web_apis/index.html
new file mode 100644
index 0000000000..b5e7493f19
--- /dev/null
+++ b/files/ru/learn/javascript/client-side_web_apis/index.html
@@ -0,0 +1,53 @@
+---
+title: Клиентский веб API
+slug: Learn/JavaScript/Client-side_web_APIs
+tags:
+ - API
+ - Articles
+ - Beginner
+ - CodingScripting
+ - DOM
+ - Graphics
+ - JavaScript
+ - Landing
+ - Learn
+ - Media
+ - Module
+ - NeedsTranslation
+ - TopicStub
+ - WebAPI
+ - data
+translation_of: Learn/JavaScript/Client-side_web_APIs
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">При написании клиентского JavaScript для приложений или веб-сайтов Вам не приходится слишком сильно углубляться, пока Вы не начнете использовать API — интерфейсы управления различными аспектами браузера или операционной системы на которой этот сайт работает, или же с данными с других веб-сайтов или сервисов. В этом модуле мы рассмотрим что API из себя представляет и как использовать самые распространенные из них, с которыми Вы можете столкнуться в разработке.</p>
+
+<h2 id="Прежде_чем_начать">Прежде чем начать</h2>
+
+<p>Убедитесь, что вы прочли и хорошо разбираетесь в следующих модулях (<a href="https://wiki.developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8">Первые шаги</a>, <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks">Структурные элементы</a>, и <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects">Введение в объекты</a>). Эти модули включали в себя простое использование API, так как зачастую без них сложно писать примеры клиентского кода JavaScript. В данном модуле мы предполагаем, что вы хорошо знакомы с основами JavaScript, и немного подробнее рассмотрим общие веб-API.</p>
+
+<p>Естественно знание <a href="/en-US/docs/Learn/HTML">HTML</a> и <a href="/en-US/docs/Learn/CSS">CSS</a> здесь также необходимо.</p>
+
+<div class="note">
+<p><strong>Примечание:</strong> Если вы работаете на устройстве, где у вас нет возможности создавать свои собственные файлы, вы можете проверить большинство примеров кода в онлайн-программах вроде <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p>
+</div>
+
+<h2 id="Руководства">Руководства</h2>
+
+<dl>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Введение в различные web API</a></dt>
+ <dd>Прежде всего, мы начнем изучение API с основ - что это такое, как это работает, как вы используете их в своем коде и как они структурированы? Мы также рассмотрим, что представляют собой различные основные классы API, и как их можно использовать.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Управление документами</a></dt>
+ <dd><span id="result_box" lang="ru"><span>При написании веб-страниц и приложений Вы чаще всего </span></span><span lang="ru"><span>будете управлять каким-либо образом веб-документами. </span></span> <span id="result_box" lang="ru"><span>Обычно это делается с помощью Document Object Model (DOM), набора API-интерфейсов для управления HTML-разметкой и стилями, которые используют объект {{domxref ("Document")}}. </span></span><span id="result_box" lang="ru"><span>В этой статье мы рассмотрим, как использовать DOM, а также некоторые интересные API, которые могут изменить рабочую среду интересными способами.</span></span></dd>
+ <dt><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Получение данных с сервера</a></dt>
+ <dd>Другой очень распространенной задачей в современных веб-сайтах и приложениях является получение отдельных элементов данных с сервера для обновления разделов веб-страницы без необходимости загрузки абсолютно новой страницы. Эта, казалось бы, небольшая деталь оказала огромное влияние на производительность и поведение сайтов, поэтому в этой статье мы объясним концепцию и рассмотрим технологии, которые позволяют это, например {{domxref("XMLHttpRequest")}} и <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>.</dd>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Сторонние API</a></dt>
+ <dd>API, которые мы рассматривали до сих пор, встроены в браузер, но не все API встроены в браузер. Многие крупные веб-сайты и сервисы, такие как Google Maps, Twitter, Facebook, PayPal и т.д. предоставляют API-интерфейсы, позволяющие разработчикам использовать свои данные (например, показывать ваш Twitter-поток в вашем блоге) или сервисы (например, отображение пользовательских карт Google на вашем сайте, или с помощью входа в систему Facebook для входа в систему пользователей). В этой статье рассматривается различие между API браузера и сторонними API и показано типичное использование последнего.</dd>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Рисование графики</a></dt>
+ <dd>В браузере содержатся очень мощные инструменты графического программирования, начиная с языка Scalable Vector Graphics (<a href="https://developer.mozilla.org/en-US/docs/Web/SVG">SVG</a>) и заканчивая API для рисования элементов HTML {{htmlelement("canvas")}} (см. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">The Canvas API</a> и <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">WebGL</a>). В статье содержится введение в Canvas API и дополнительные ресурсы, чтобы вы могли узнать больше.</dd>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Видео и аудио API</a></dt>
+ <dd>HTML5 поставляется с элементами для размещения мультимедийных материалов в документах - {{htmlelement("video")}} и {{htmlelement("audio")}} - которые, в свою очередь, имеют свои собственные API для управления воспроизведением, поиском и т. д. В статье показано, как выполнять общие задачи, такие как создание пользовательских элементов управления воспроизведением.</dd>
+ <dt><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Клиентское хранилище</a></dt>
+ <dd>Современные веб-браузеры имеют ряд различных технологий, которые позволяют хранить данные, связанные с веб-сайтами, и извлекать их, когда это необходимо, что позволяет вам сохранять данные в долгосрочной перспективе, сохранять сайты в автономном режиме и многое другое. В этой статье объясняются самые основы того, как они работают.</dd>
+</dl>
diff --git a/files/ru/learn/javascript/client-side_web_apis/introduction/index.html b/files/ru/learn/javascript/client-side_web_apis/introduction/index.html
new file mode 100644
index 0000000000..bc710c0d37
--- /dev/null
+++ b/files/ru/learn/javascript/client-side_web_apis/introduction/index.html
@@ -0,0 +1,277 @@
+---
+title: Введение в web APIs
+slug: Learn/JavaScript/Client-side_web_APIs/Introduction
+translation_of: Learn/JavaScript/Client-side_web_APIs/Introduction
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs")}}</div>
+
+<p class="summary">Начнём с рассмотрения того что представляют собой API на высоком уровне и выясним, как они работают, как их использовать в своих программах и как они структурированы. Также рассмотрим основные виды API и их применение.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Необходимые знания:</th>
+ <td>Базовая компьютерная грамотность, понимание основ <a href="/en-US/docs/Learn/HTML">HTML</a> и <a href="/en-US/docs/Learn/CSS">CSS</a>,  основы JavaScript (см. <a href="/en-US/docs/Learn/JavaScript/First_steps">первые шаги</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">building blocks</a>, <a href="/en-US/docs/Learn/JavaScript/Objects">объекты JavaScript</a>).</td>
+ </tr>
+ <tr>
+ <th scope="row">Цель:</th>
+ <td>Познакомиться с API, выяснить что они могут делать и как их использовать.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Что_такое_API">Что такое API?</h2>
+
+<p>Интерфейс прикладного программирования (Application Programming Interfaces, APIs) - это готовые конструкции языка программирования, позволяющие разработчику строить сложный функционал с меньшими усилиями. Они "скрывают" более сложный код от программиста, обеспечивая простоту использования.</p>
+
+<p>Для лучшего понимания рассмотрим аналогию с домашними электросетями. Когда вы хотите использовать какой-то электроприбор, вы просто подключаете его к розетке, и всё работает. Вы не пытаетесь подключить провода напрямую к источнику тока — делать это бесполезно и, если вы не электрик, сложно и опасно.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14317/plug-socket.png" style="display: block; height: 472px; margin: 0px auto; width: 700px;"></p>
+
+<p><em>Image source: <a href="https://www.flickr.com/photos/easy-pics/9518184890/in/photostream/lightbox/">Overloaded plug socket</a> by <a href="https://www.flickr.com/photos/easy-pics/">The Clear Communication People</a>, on Flickr.</em></p>
+
+<p>Точно также, если мы хотим, например, программировать 3D графику, гораздо легче сделать это с использованием API, написанных на языках высокого уровня, таких как JavaScript или Python.</p>
+
+<div class="note">
+<p><strong>Note</strong>: См. также <a href="/en-US/docs/Glossary/API">API в словаре</a>.</p>
+</div>
+
+<h3 id="API_клиентской_части_JavaScript">API клиентской части JavaScript</h3>
+
+<p>Для JavaScript на стороне клиента, в частности, существует множество API. Они не являются частью языка, а построены с помощью встроенных функций JavaScript для того, чтобы увеличить ваши возможности при написании кода. Их можно разделить на две категории:</p>
+
+<ul>
+ <li><strong>API браузера</strong> встроены в веб-браузер и способны использовать данные браузера и компьютерной среды для осуществления более сложных действий с этими данными. К примеру, <a href="/en-US/docs/Web/API/Geolocation/Using_geolocation">API Геолокации (Geolocation API)</a> предоставляет простые в использовании конструкции JavaScript для работы с данными местоположения, так что вы сможете, допустим, отметить свое расположение на карте Google Map. На самом деле, в браузере выполняется сложный низкоуровневый код (например, на C++) для подключения к устройству GPS (или любому другому устройству геолокации), получения данных и передачи их браузеру для обработки вашей программой, но, как было сказано выше, эти детали скрыты благодаря API.</li>
+ <li><strong>Сторонние API</strong> не встроены в браузер по умолчанию. Такие API и информацию о них обычно необходимо искать в интернете. Например, <a href="https://dev.twitter.com/overview/documentation">Twitter API</a> позволяет размещать последние твиты (tweets) на вашем веб-сайте. В данном API определён набор конструкций, осуществляющих запросы к сервисам Twitter и возвращающих определённые данные.</li>
+</ul>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13508/browser.png" style="display: block; height: 511px; margin: 0px auto; width: 815px;"></p>
+
+<h3 id="Взаимодействие_JavaScript_API_и_других_средств_JavaScript">Взаимодействие JavaScript, API и других средств JavaScript</h3>
+
+<p>Итак, выше мы поговорили о том, что такое JavaScript API клиентской части и как они связаны с языком JavaScript. Давайте теперь тезисно запишем основные понятия и определим назначение других инструментов JavaScript:</p>
+
+<ul>
+ <li>JavaScript — Язык программирования сценариев высокого уровня, встроенный в браузер, позволяющий создавать функционал веб-страниц/приложений. Отметим, что JavaScript также доступен на других программных платформах, таких как <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Node</a>. Но пока не будем останавливаться на этом.</li>
+ <li>API браузера (Browser APIs) — конструкции, встроенные в браузер, построенные на основе языка JavaScript, предназначенные для облегчения разработки функционала.</li>
+ <li>Сторонние API (Third party APIs) — конструкции, встроенные в сторонние платформы (такие как Twitter, Facebook) позволяющие вам использовать часть функционала этих платформ в своих собственных веб-страницах/приложениях (например, показывать последние Твиты на вашей странице).</li>
+ <li>Библиотеки JavaScript — Обычно один или несколько файлов, содержащих <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Custom_functions">пользовательские (custom) функции</a> . Такие файлы можно прикрепить к веб-странице, чтобы ускорить или предоставить инструменты для написания общего функционала. Примеры: jQuery, Mootools и React.</li>
+ <li>JavaScript фреймворки (frameworks) — Следующий шаг в развитии разработки после библиотек. Фреймворки JavaScript (такие как Angular и Ember) стремятся к тому, чтобы быть набором HTML, CSS, JavaScript и других технологий, после установки которого можно "писать" веб-приложение с нуля. Главное различие между фреймворками и библиотеками - "Обратное направление управления" ( “Inversion of Control” ). Вызов метода из библиотеки происходит по требованию разработчика. При использовании фреймворка - наоборот, фреймворк производит вызов кода разработчика.</li>
+</ul>
+
+<h2 id="На_что_способны_API">На что способны API?</h2>
+
+<p>Широкое разнообразие API в современных браузерах позволяет наделить ваше приложение большими возможностями. Достаточно посмотреть список на странице <a href="https://developer.mozilla.org/en-US/docs/Web/API">MDN APIs index page</a>.</p>
+
+<h3 id="Распространённые_API_браузера">Распространённые API браузера</h3>
+
+<p>В частности, к наиболее часто используемым категориям API (и которые мы рассмотрим далее в этом модуле) относятся :</p>
+
+<ul>
+ <li><strong>API для работы с документами</strong>, загруженными в браузер. Явный пример - <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model">DOM (Document Object Model) API</a>, позволяющий работать с HTML и CSS — создавать, удалять и изменять HTML, динамически изменять вид страницы и т.д. Любое всплывающее окно на странице или появляющееся "на ходу" содержимое - всё это благодаря DOM. Узнайте больше об этой категории API на странице <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Работа с документами</a>.</li>
+ <li><strong>API, принимающие данные от сервера</strong>, часто используются, чтобы обновить небольшие части веб-страницы. Эта, казалось бы, малая деталь оказывает огромное влияние на производительность и поведение сайтов, так как нет необходимости перезагружать всю страницу целиком, если вам нужно просто обновить список товаров или новых доступных историй. Это также сделает приложение или сайт более отзывчивым и "живым". Список API, благодаря которым это возможно, включает: <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest" title="XMLHttpRequest is an API that provides client functionality for transferring data between a client and a server. It provides an easy way to retrieve data from a URL without having to do a full page refresh. This enables a Web page to update just a part of the page without disrupting what the user is doing."><code>XMLHttpRequest</code></a> и <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>. Вы также могли встретить термин <strong>Ajax</strong>, описывающий эту технологию. Узнать больше об этой категории API на странице <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Получение данных от сервера</a>.</li>
+ <li><strong>API для работы с графикой</strong> широко поддерживаются браузерами,  самые популярные: <a href="/en-US/docs/Web/API/Canvas_API">Canvas</a> и <a href="/en-US/docs/Web/API/WebGL_API">WebGL</a>, позволяющие программно изменять данные о пикселях, содержащиеся в элементе HTML  {{htmlelement("canvas")}}  для создания 2D и 3D изображений. Например, вы можете нарисовать фигуры, скажем, прямоугольники или круги, импортировать изображение в canvas и применить к нему фильтры, такие как сепия или оттенки серого с помощью Canvas API, или создать сложное 3D-изображение с освещением и текстурами, используя WebGL. Такие API часто используют в сочетании с API создания анимационных циклов (таких как {{domxref("window.requestAnimationFrame()")}}) и другими для создания постоянно меняющегося изображения на экране, как в мультфильмах или играх .</li>
+ <li><strong><a href="https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery">Аудио и Видео API</a></strong> как {{domxref("HTMLMediaElement")}}, <a href="/en-US/docs/Web/API/Web_Audio_API">Web Audio API</a>, и <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a> позволяют делать действительно интересные вещи с мультимедиа. Например, создать собственный пользовательский интерфейс (User Interface, UI) для проигрывания аудио/видео, вывод на экран субтитров, записывать видео с веб-камеры для обработки в canvas (см. выше) или для передачи на другой компьютер в видео-конференции, применять звуковые эффекты к аудио-файлам (такие как gain, distortion, panning и т.д.).</li>
+ <li><strong>API устройств</strong> - в основном, API для обработки и считывания данных с современных устройств удобным для работы веб-приложений образом. Мы уже говорили об API Геолокации, позволяющем считать данные о местоположении устройства. Другие примеры включают уведомление пользователя о появившемся обновлении для веб-приложения с помощью системных уведомлений (см. <a href="/en-US/docs/Web/API/Notifications_API">Notifications API</a>) или вибрации (см. <a href="/en-US/docs/Web/API/Vibration_API">Vibration API</a>).</li>
+ <li><strong>API хранения данных на стороне пользователя</strong> приобретают всё большее распространение в веб-браузерах — возможность хранить информацию на стороне клиента очень полезна, когда необходимо создать приложение, которое будет сохранять своё состояние между перезагрузками страницы, или даже работать, когда устройство не в сети. В данный момент доступно немало таких API. Например, простое хранилище данных в формате имя/значение (name/value)  <a href="/en-US/docs/Web/API/Web_Storage_API">Web Storage API</a> или хранилище данных в формате таблиц <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a>.</li>
+</ul>
+
+<h3 id="Распространённые_сторонние_API">Распространённые сторонние API</h3>
+
+<p>Существует множество сторонних API; некоторые из наиболее популярных, которые вы рано или поздно будете использовать, включают:</p>
+
+<ul>
+ <li><a href="https://dev.twitter.com/overview/documentation">Twitter API</a> для добавления такого функционала, как показ последних твитов на сайте.</li>
+ <li><a href="https://developers.google.com/maps/">Google Maps API</a> для работы с картами на веб-странице (интересно, что Google Maps также использует этот API). Теперь это целый набор API, который может справляться с широким спектром задач, как свидетельствует <a href="https://developers.google.com/maps/documentation/api-picker">Google Maps API Picker</a>.</li>
+ <li><a href="https://developers.facebook.com/docs/">Набор Facebook API</a> позволяет использовать различные части платформы Facebook в вашем приложении, предоставляя, например, возможность входа в систему с логином Facebook, оплаты покупок в приложении, демонстрация целевой рекламы и т.д.</li>
+ <li><a href="https://developers.google.com/youtube/">YouTube API</a>, предоставляющий возможность встраивать видео с YouTube на вашем сайте, производить поиск, создавать плэйлисты и т.д.</li>
+ <li><a href="https://www.twilio.com/">Twilio API</a> - фреймворк для встраивания функционала голосовой и видео связи в вашем приложении, отправки SMS/MMS из приложения и т.д.</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: Вы можете найти информацию о гораздо большем количестве сторонних API в <a href="http://www.programmableweb.com/category/all/apis">Каталоге Web API</a>.</p>
+</div>
+
+<h2 id="Как_работает_API">Как работает API?</h2>
+
+<p>Работа разных JavaScript API немного отличается, но, в основном, у них похожие функции и принцип работы.</p>
+
+<h3 id="Они_основаны_на_объектах">Они основаны на объектах</h3>
+
+<p>Взаимодействие с API в коде происходит через один или больше <a href="/en-US/docs/Learn/JavaScript/Objects">объектов JavaScript</a>, которые служат контейнерами для информации, с которой работает API (содержится в свойствах объекта), и реализуют функционал, который предоставляет API (содержится в методах объекта).</p>
+
+<div class="note">
+<p><strong>Note</strong>: Если вам ещё не известно как работают объекты, советуем вернуться назад и изучить модуль <a href="/en-US/docs/Learn/JavaScript/Objects">Основы объектов JavaScript</a> прежде чем продолжать.</p>
+</div>
+
+<p>Вернёмся к примеру с API Геолокации — очень простой API, состоящий из нескольких простых объектов:</p>
+
+<ul>
+ <li>{{domxref("Geolocation")}}, содержит три метода для контроля и получения геоданных.</li>
+ <li>{{domxref("Position")}}, предоставляет данные о местоположении устройства в заданный момент времени — содержит {{domxref("Coordinates")}} - объект, хранящий координаты и отметку о текущем времени.</li>
+ <li>{{domxref("Coordinates")}}, содержит много полезной информации о расположении устройства, включая широту и долготу, высоту, скорость и направление движения и т.д.</li>
+</ul>
+
+<p>Так как же эти объекты взаимодействуют? Если вы посмотрите на наш пример <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/introduction/maps-example.html">maps-example.html</a> (<a href="http://mdn.github.io/learning-area/javascript/apis/introduction/maps-example.html">see it live also</a>), вы увидите следующий код:</p>
+
+<pre class="brush: js notranslate">navigator.geolocation.getCurrentPosition(function(position) {
+ var latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
+ var myOptions = {
+ zoom: 8,
+ center: latlng,
+ mapTypeId: google.maps.MapTypeId.TERRAIN,
+ disableDefaultUI: true
+ }
+ var map = new google.maps.Map(document.querySelector("#map_canvas"), myOptions);
+});</pre>
+
+<div class="note">
+<p><strong>Note</strong>: Когда вы впервые загрузите приведённый выше пример, появится диалоговое окно, запрашивающее разрешение на передачу данных о местонахождении этому приложению (см. раздел {{anch("У них есть дополнительные средства безопасности там, где это необходимо")}} далее в этой статье). Вам нужно разрешить передачу данных, чтобы иметь возможность отметить своё местоположение на карте. Если вы всё ещё не видите карту, возможно, требуется установить разрешения вручную; это делается разными способами в зависимости от вашего браузера; например, в Firefox перейдите &gt; <em>Tools</em> &gt; <em>Page Info</em> &gt; <em>Permissions</em>, затем измените настройки <em>Share Location</em>; в Chrome перейдите<em> Settings</em> &gt; <em>Privacy</em> &gt; <em>Show advanced settings</em> &gt; <em>Content settings</em> и измените настройки <em>Location</em>.</p>
+</div>
+
+<p>Во-первых, мы хотим использовать метод {{domxref("Geolocation.getCurrentPosition()")}}, чтобы получить текущее положение нашего устройства. Доступ к объекту браузера {{domxref("Geolocation")}} производится с помощью свойства {{domxref("Navigator.geolocation")}}, так что мы начнём с</p>
+
+<pre class="brush: js notranslate">navigator.geolocation.getCurrentPosition(function(position) { ... });</pre>
+
+<p>Это эквивалентно следующему коду</p>
+
+<pre class="brush: js notranslate">var myGeo = navigator.geolocation;
+myGeo.getCurrentPosition(function(position) { ... });</pre>
+
+<p>Но мы можем использовать точки, чтобы связать доступ к свойствам/методам объекта в одно выражение, уменьшая количество строк в программе.</p>
+
+<p>Метод {{domxref("Geolocation.getCurrentPosition()")}} имеет один обязательный параметр - анонимную функцию, которая запустится, когда текущее положение устройства будет успешно считано. Сама эта функция принимает параметр, являющийся объектом {{domxref("Position")}}, представляющим данные о текущем местоположении.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Функция, которая передаётся другой функции в качестве параметра, называется <a href="/en-US/docs/Glossary/Callback_function">функцией обратного вызова (callback function)</a>.</p>
+</div>
+
+<p>Такой подход, при котором функция вызывается только тогда, когда операция была завершена, очень распространён в JavaScript API — убедиться, что операция была завершена прежде, чем пытаться использовать данные, которые она возвращает, в другой операции. Такие операции также называют асинхронными операциями (<strong><a href="/en-US/docs/Glossary/Asynchronous">asynchronous</a> operations)</strong>. Учитывая, что получение данных геолокации производится из внешнего устройства (GPS-устройства или другого устройства геолокации), мы не можем быть уверены, что операция считывания будет завершена вовремя и мы сможем незамедлительно использовать возвращаемые ею данные. Поэтому такой код не будет работать:</p>
+
+<pre class="brush: js example-bad notranslate">var position = navigator.geolocation.getCurrentPosition();
+var myLatitude = position.coords.latitude;</pre>
+
+<p>Если первая строка ещё не вернула результат, вторая вызовет ошибку из-за того, что данные геолокации ещё не стали доступны. По этой причине, API, использующие асинхронные операции, разрабатываются с использованием {{glossary("callback function")}}, или более современной системы <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Обещаний(Promises)</a>, которая появилась в ECMAScript 6 и широко используются в новых API.</p>
+
+<p>Мы совмещаем API Геолокации со сторонним API - Google Maps API, который используем для того, чтобы отметить расположение, возвращаемое  <code>getCurrentPosition()</code> , на Google Map. Чтобы Google Maps API стал доступен на нашей странице, мы включаем его в HTML документ:</p>
+
+<pre class="brush: html notranslate">&lt;script type="text/javascript" src="https://maps.google.com/maps/api/js?key=AIzaSyDDuGt0E5IEGkcE6ZfrKfUtE9Ko_de66pA"&gt;&lt;/script&gt;</pre>
+
+<p>Чтобы использовать этот API, во-первых создадим объект <code>LatLng</code> с помощью конструктора <code>google.maps.LatLng()</code> , принимающим данные геолокации {{domxref("Coordinates.latitude")}} и {{domxref("Coordinates.longitude")}} :</p>
+
+<pre class="brush: js notranslate">var latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);</pre>
+
+<p>Этот объект сам является значением свойства <code>center</code> объекта настроек (options), который мы назвали <code>myOptions</code>. Затем мы создаём экземпляр объекта, представляющего нашу карту, вызывая конструктор <code>google.maps.Map()</code> и передавая ему два параметра — ссылку на элемент {{htmlelement("div")}}, на котором мы хотим отрисовывать карту (с ID <code>map_canvas</code>), и объект настроек (options), который мы определили выше.</p>
+
+<pre class="brush: js notranslate">var myOptions = {
+ zoom: 8,
+ center: latlng,
+ mapTypeId: google.maps.MapTypeId.TERRAIN,
+ disableDefaultUI: true
+}
+
+var map = new google.maps.Map(document.querySelector("#map_canvas"), myOptions);</pre>
+
+<p>Когда это сделано, наша карта отрисовывается.</p>
+
+<p>Последний блок кода демонстрирует два распространённых подхода, которые вы увидите во многих API:</p>
+
+<ul>
+ <li>Во-первых, объекты API обычно содержат конструкторы, которые вызываются для создания экземпляров объектов, используемых при написании программы.</li>
+ <li>Во-вторых, объекты API зачастую имеют несколько вариантов (options), которые можно настроить и получить именно ту среду для разработки, которую вы хотите. API конструкторы обычно принимают объекты вариантов (options) в качестве параметров, с помощью которых и происходит настройка.</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: Не отчаивайтесь, если вы что-то не поняли из этого примера сразу. Мы рассмотрим использование сторонних API более подробно в следующих статьях.</p>
+</div>
+
+<h3 id="У_них_узнаваемые_точки_входа">У них узнаваемые точки входа</h3>
+
+<p>При использовании API убедитесь, что вы знаете где точка входа для API. В API Геолокации это довольно просто — это свойство {{domxref("Navigator.geolocation")}}, возвращающее объект браузера {{domxref("Geolocation")}}, внутри которого доступны все полезные методы геолокации.</p>
+
+<p>Найти точку входа Document Object Model (DOM) API ещё проще — при применении этого API используется объект {{domxref("Document")}}, или экземпляр элемента HTML, с которым вы хотите каким-либо образом взаимодействовать, к примеру:</p>
+
+<pre class="brush: js notranslate">var em = document.createElement('em'); // создаёт новый элемент em
+var para = document.querySelector('p'); // ссылка на существующий элемент p
+em.textContent = 'Hello there!'; // присвоение текстового содержимого
+para.appendChild(em); // встроить em внутрь para</pre>
+
+<p>Точки входа других API немного сложнее, часто подразумевается создание особого контекста, в котором будет написан код API. Например, объект контекста Canvas API создаётся получением ссылки на элемент {{htmlelement("canvas")}}, на котором вы хотите рисовать, а затем необходимо вызвать метод {{domxref("HTMLCanvasElement.getContext()")}}:</p>
+
+<pre class="brush: js notranslate">var canvas = document.querySelector('canvas');
+var ctx = canvas.getContext('2d');</pre>
+
+<p>Всё, что мы хотим сделать с canvas после этого, достигается вызовом свойств и методов объекта содержимого (content) (который является экземпляром {{domxref("CanvasRenderingContext2D")}}), например:</p>
+
+<pre class="brush: js notranslate">Ball.prototype.draw = function() {
+ ctx.beginPath();
+ ctx.fillStyle = this.color;
+ ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
+ ctx.fill();
+};</pre>
+
+<div class="note">
+<p><strong>Note</strong>: Вы можете увидеть этот код в действии в нашем <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/introduction/bouncing-balls.html">bouncing balls demo</a> (see it <a href="http://mdn.github.io/learning-area/javascript/apis/introduction/bouncing-balls.html">running live</a> also).</p>
+</div>
+
+<h3 id="Они_используют_события_для_управления_состоянием">Они используют события для управления состоянием</h3>
+
+<p>Мы уже обсуждали события ранее в этом курсе, в нашей статье <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a> — в этой статье детально описываются события на стороне клиента и их применение. Если вы ещё не знакомы с тем, как работают события клиентской части, рекомендуем прочитать эту статью прежде, чем продолжить.</p>
+
+<p>В некоторых API содержится ряд различных событий, в некоторых - событий нет. Свойства обработчика, позволяющие запускать функции при совершении какого-либо события по большей части перечислены в нашем материале отдельного раздела "Обработчики событий (Event handlers)". Как простой пример, экземпляры объекта <code><a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> (каждый представляет собой HTTP-запрос к серверу на получение каких-либо ресурсов (resource)) имеют несколько доступных событий, например, событие <code>load</code> происходит, когда ответ с запрашиваемым ресурсом был успешно возвращён и доступен в данный момент.</p>
+
+<p>Следующий код содержит простой пример использования событий:</p>
+
+<pre class="brush: js notranslate">var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
+var request = new XMLHttpRequest();
+request.open('GET', requestURL);
+request.responseType = 'json';
+request.send();
+
+request.onload = function() {
+ var superHeroes = request.response;
+ populateHeader(superHeroes);
+ showHeroes(superHeroes);
+}</pre>
+
+<div class="note">
+<p><strong>Note</strong>: Вы можете увидеть этот код в действии в примере <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/introduction/ajax.html">ajax.html</a> (<a href="http://mdn.github.io/learning-area/javascript/apis/introduction/ajax.html">see it live</a> also).</p>
+</div>
+
+<p>В первых пяти строках мы задаём расположение ресурса, который хотим получить, создаём экземпляр объекта запроса с помощью конструктора <code>XMLHttpRequest()</code>, открываем HTTP-запрос <code>GET</code>, чтобы получить запрашиваемый ресурс, определяем, что мы хотим получить этот ресурс в формате json, после чего отсылаем запрос.</p>
+
+<p>Затем функция-обработчик <code>onload</code> определяет наши действия по обработке ответа сервера. Нам известно, что ответ успешно возвращён и доступен после наступления события load (и если не произойдёт ошибка), так что мы сохраняем ответ, содержащий возвращённый сервером объект JSON в переменной <code>superHeroes</code>, которую затем передаём двум различным функциям для дальнейшей обработки.</p>
+
+<h3 id="У_них_есть_дополнительные_средства_безопасности_там_где_это_необходимо">У них есть дополнительные средства безопасности там, где это необходимо</h3>
+
+<p>Функционал WebAPI подвержен тем же соображениям безопасности , что и JavaScript или другие веб-технологии (например, <a href="/en-US/docs/Web/Security/Same-origin_policy">same-origin policy</a>), но иногда они содержат дополнительные механизмы защиты. К примеру, некоторые из наиболее современных WebAPI работают только со страницами, обслуживаемыми через HTTPS в связи с передачей конфиденциальных данных (примеры: <a href="/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> и <a href="/en-US/docs/Web/API/Push_API">Push</a>).</p>
+
+<p>К тому же, некоторые WebAPI запрашивают разрешение от пользователя, как только к ним происходит вызов в коде. В качестве примера, вы, возможно, встречали такое диалоговое окно при загрузке нашего примера <a href="/en-US/docs/Web/API/Geolocation">Geolocation</a> ранее:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14313/location-permission.png" style="border-style: solid; border-width: 1px; display: block; height: 188px; margin: 0px auto; width: 413px;"></p>
+
+<p><a href="/en-US/docs/Web/API/Notifications_API">Notifications API</a> запрашивает разрешение подобным образом:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14315/notification-permission.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<p>Запросы разрешений необходимы для обеспечения безопасности пользователей — не будь их, сайты могли бы скрытно отследить ваше местоположение, не создавая множество надоедливых уведомлений.</p>
+
+<h2 id="Итоги">Итоги</h2>
+
+<p>На данном этапе, у вас должно сформироваться представление о том, что такое API, как они работают и как вы можете применить их в своём JavaScript коде. Вам наверняка не терпится начать делать по-настоящему интересные вещи с конкретными API, так вперёд! В следующий раз мы рассмотрим работу с документом с помощью Document Object Model (DOM).</p>
+
+<p>{{NextMenu("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs")}}</p>
+
+<h2 id="В_этом_модуле">В этом модуле</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Введение в web APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li>
+</ul>
diff --git a/files/ru/learn/javascript/client-side_web_apis/manipulating_documents/index.html b/files/ru/learn/javascript/client-side_web_apis/manipulating_documents/index.html
new file mode 100644
index 0000000000..e93334902a
--- /dev/null
+++ b/files/ru/learn/javascript/client-side_web_apis/manipulating_documents/index.html
@@ -0,0 +1,321 @@
+---
+title: Управление документами
+slug: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents
+tags:
+ - API
+ - DOM
+ - Изучение
+ - Навигатор
+ - Новичек
+ - Окно
+translation_of: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Introduction", "Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs")}}</div>
+
+<p class="summary">При написании веб-страниц и приложений вам придётся часто каким-либо образом управлять структурой документа. Обычно это делается с помощью Document Object Model (DOM), набора API для управления разметкой HTML и стилями, которая сильно использует объект {{domxref ("Document")}}. В этой статье мы подробно рассмотрим, как использовать DOM и некоторые другие интересные API, которые могут изменить вашу среду интересными способами.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Предпосылки:</th>
+ <td>Базовая компьютерная грамотность, базовое понимание HTML, CSS и JavaScript - включая объекты JavaScript.</td>
+ </tr>
+ <tr>
+ <th scope="row">Задача:</th>
+ <td>Познакомиться с основными DOM API и другими API, обычно связанными с DOM, и манипулированием документами</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Важные_элементы_веб-браузера">Важные элементы веб-браузера</h2>
+
+<p>Веб-браузеры - очень сложные части программного обеспечения с множеством движущихся частей, многие из которых не могут управляться или управляться веб-разработчиком с использованием JavaScript. Вы можете подумать, что такие ограничения - это плохо, но браузеры заблокированы по уважительным причинам (в основном ради безопасности). Представьте себе, что веб-сайт может получить доступ к вашим сохраненным паролям или другой конфиденциальной информации и войти на веб-сайты так, как если бы это были вы?</p>
+
+<p>Несмотря на ограничения, Web API по-прежнему дают нам доступ к множеству функциональных возможностей, которые позволяют нам многое делать с веб-страницами. Есть несколько действительно очевидных моментов, на которые вы будете регулярно ссылаться в своем коде. Рассмотрим следующую диаграмму, которая представляет основные части браузера, непосредственно участвующие в просмотре веб-страниц:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14557/document-window-navigator.png" style="display: block; margin: 0 auto;"></p>
+
+<ul>
+ <li>Окно - это вкладка браузера, в которую загружается веб-страница; это представлено в JavaScript объектом {{domxref("Window")}}. Используя методы, доступные для этого объекта, вы можете делать такие вещи, как возврат размера окна (см. {{Domxref("Window.innerWidth")}} и {{domxref("Window.innerHeight")}}), манипулировать документом, загруженным в этот window, хранить данные, специфичные для этого документа на стороне клиента (например, используя локальную базу данных или другой механизм хранения), присоединить обработчик событий (<a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#A_series_of_fortunate_events">event handler</a>) к текущему окну и многое другое.</li>
+ <li>Навигатор представляет состояние и идентификатор браузера (т. е. пользовательский агент), как он существует в Интернете. В JavaScript это представлено объектом {{domxref("Navigator")}}. Вы можете использовать этот объект для извлечения таких вещей, как геолокационная информация, предпочтительный язык пользователя, медиапоток с веб-камеры пользователя и т. д.</li>
+ <li>Документ (представленный DOM в браузерах) представляет собой фактическую страницу, загруженную в окно, и представлен в JavaScript объектом {{domxref("Document")}}. Вы можете использовать этот объект для возврата и обработки информации о HTML и CSS, содержащей документ, например, получить ссылку на элемент в DOM, изменить его текстовый контент, применить к нему новые стили, создать новые элементы и добавить их в текущий элемент как дочерний элемент, или даже вообще удалить его.</li>
+</ul>
+
+<p>В этой статье мы сосредоточимся главным образом на манипулировании документом, но мы покажем ещё несколько полезных моментов.</p>
+
+<h2 id="Объектная_модель_документа">Объектная модель документа</h2>
+
+<p>Документ, загруженный в каждый из ваших вкладок браузера, представлен объектной моделью документа. Это представление «древовидной структуры», созданное браузером, которое позволяет легко получить доступ к структуре HTML с помощью языков программирования - например, сам браузер использует его для применения стиля и другой информации к правильным элементам, поскольку он отображает страницу, а разработчики (как Вы) могут манипулировать DOM с JavaScript после того, как страница была отображена.</p>
+
+<p>Мы создали простую страницу примера в <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/dom-example.html">dom-example.html</a> (<a href="https://mdn.github.io/learning-area/javascript/apis/document-manipulation/dom-example.html">см. также live</a>). Попробуйте открыть это в своем браузере - это очень простая страница, содержащая элемент {{htmlelement("section")}}, внутри которого вы можете найти изображение и абзац со ссылкой внутри. Исходный код HTML выглядит так:</p>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;Simple DOM example&lt;/title&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;section&gt;
+ &lt;img src="dinosaur.png" alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."&gt;
+ &lt;p&gt;Here we will add a link to the &lt;a href="https://www.mozilla.org/"&gt;Mozilla homepage&lt;/a&gt;&lt;/p&gt;
+ &lt;/section&gt;
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>DOM, с другой стороны, выглядит так:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14559/dom-screenshot.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<div class="note">
+<p><strong>Примечание</strong>. Эта диаграмма дерева DOM была создана с использованием <a href="https://software.hixie.ch/utilities/js/live-dom-viewer/">Live DOM viewer</a> Яна Хиксона.</p>
+</div>
+
+<p>Вы можете видеть здесь, что каждый элемент и бит текста в документе имеют свою собственную запись в дереве - каждый из них называется <strong>узлом</strong> (<strong>node)</strong>. Вы также столкнетесь с различными терминами, используемыми для описания типа узла, и их положением в дереве относительно друг друга:</p>
+
+<ul>
+ <li><strong>Element node</strong>: элемент, как он существует в DOM.</li>
+ <li><strong>Root node</strong>: верхний узел в дереве, который в случае <code>HTML</code> всегда является узлом HTML (другие словари разметки, такие как SVG и пользовательский XML, будут иметь разные корневые элементы)..</li>
+ <li><strong>Child node</strong>: узел <em>непосредственно</em> внутри другого узла. Например, <code>IMG</code> является дочерним элементом <code>SECTION</code> в приведенном выше примере.</li>
+ <li><strong>Descendant node</strong> (узел потомок): узел внутри дочернего элемента. Например, <code>IMG</code> является дочерним элементом <code>SECTION</code> в приведенном выше примере, и он также является потомком для родителя <code>SECTION</code>. <code>IMG</code> не является ребенком <code>BODY</code>, так как он находится на двух уровнях ниже дерева в дереве, но он является потомком <code>BODY</code>.</li>
+ <li><strong>Parent node</strong>: узел, в котором текущий узел. Например, <code>BODY</code> является родительским узлом <code>SECTION</code> в приведенном выше примере.</li>
+ <li><strong>Sibling nodes</strong> (одноуровневый узел): узлы, которые расположены на одном уровне в дереве DOM. Например, <code>IMG</code> и <code>P</code> являются братьями и сестрами в приведенном выше примере.</li>
+ <li><strong>Text node</strong>: узел, содержащий текстовую строку.</li>
+</ul>
+
+<p>Полезно ознакомиться с этой терминологией перед тем, как работать с DOM, поскольку некоторые термины кода, с которыми вы столкнетесь, используют их.. Возможно, вы уже сталкивались с ними, если вы изучали CSS (например, селектор потомков, дочерний селектор).</p>
+
+<h2 id="Активное_обучение_основы_управления_структурой_DOM">Активное обучение: основы управления структурой DOM</h2>
+
+<p>Чтобы начать изучение по управлению структуры DOM, давайте начнем с практического примера.</p>
+
+<ol>
+ <li>Возьмите локальную копию страницы <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/dom-example.html">dom-example.html page</a> и изображение, которое вместе с ним.</li>
+ <li>Добавьте элемент <code>&lt;script&gt;&lt;/script&gt;</code> чуть выше закрывающего тега <code>&lt;/body&gt;</code>.</li>
+ <li>Чтобы управлять элементом внутри DOM, вам сначала нужно выбрать его и сохранить ссылку на него внутри переменной. Внутри вашего скриптового элемента добавьте следующую строку:
+ <pre class="brush: js notranslate">var link = document.querySelector('a');</pre>
+ </li>
+ <li>Теперь у нас есть ссылка на элемент, хранящаяся в переменной, мы можем начать ее манипулировать с использованием доступных ему свойств и методов (они определены на таких интерфейсах, как {{domxref("HTMLAnchorElement")}} в случае {{htmlelement ("a")}}, его более общий родительский интерфейс {{domxref ("HTMLElement")}} и {{domxref("Node")}} - который представляет все узлы в DOM). Прежде всего, давайте изменим текст внутри ссылки, обновив значение свойства {{domxref("Node.textContent")}}. Добавьте следующую строку ниже предыдущей:
+ <pre class="brush: js notranslate">link.textContent = 'Mozilla Developer Network';</pre>
+ </li>
+ <li>Мы также должны изменить URL-адрес, на который указывает ссылка, чтобы он не попадал в неправильное место при нажатии. Добавьте следующую строку, опять внизу:
+ <pre class="brush: js notranslate">link.href = 'https://developer.mozilla.org';</pre>
+ </li>
+</ol>
+
+<div>
+<p>Обратите внимание, что, как и во многих вещах в JavaScript, существует множество способов выбора элемента и хранения ссылки на него в переменной. {{domxref("Document.querySelector()")}} - рекомендуемый современный подход, который считается удобным, потому что он позволяет вам выбирать элементы с помощью селекторов CSS. Вышеупомянутый запрос <code>querySelector()</code> будет соответствовать первому элементу {{htmlelement("a")}}, который появляется в документе. Если вы хотите совместить и делать что-то с несколькими элементами, вы можете использовать {{domxref ("Document.querySelectorAll()")}}, который соответствует каждому элементу документа, который соответствует селектору и сохраняет ссылки на них в массиве <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Arrays">массиво</a>-подобном объекте, называемом NodeList.</p>
+
+<p>Существуют более старые методы для захвата ссылок на элементы, например:</p>
+
+<ul>
+ <li>{{domxref("Document.getElementById()")}}, который выбирает элемент с заданным значением атрибута <code>id</code>, например <code>&lt;p id="myId"&gt;Мой абзац&lt;/p&gt;</code>. Идентификатор передается функции как параметр, т.е. <code>var elementRef = document.getElementById('myId')</code>.</li>
+ <li>{{domxref("Document.getElementsByTagName()")}}, который возвращает массив, содержащий все элементы на странице данного типа, например <code>&lt;p&gt;</code>, <code>&lt;a&gt;</code> и т.д. Тип элемента передается к функции в качестве параметра, то есть <code>var elementRefArray = document.getElementsByTagName('p')</code>.</li>
+</ul>
+
+<p>Эти два работают в более старых браузерах, чем современные методы, такие как <code>querySelector()</code>, но не так удобны. Осмотритесь и вы увидите, что ещё можно найти!</p>
+</div>
+
+<h3 id="Создание_и_размещение_новых_узлов">Создание и размещение новых узлов</h3>
+
+<p>Вышесказанное дало вам немного вкуса от того, что вы можете сделать, но давайте продолжим и посмотрим, как мы можем создавать новые элементы.</p>
+
+<ol>
+ <li>Возвращаясь к текущему примеру, давайте начнем с захвата ссылки на наш элемент {{htmlelement("section")}} - добавьте следующий код внизу существующего скрипта (сделайте то же самое с другими строками):
+ <pre class="brush: js notranslate">var sect = document.querySelector('section');</pre>
+ </li>
+ <li>Теперь давайте создадим новый абзац, используя {{domxref("Document.createElement()")}} и передадим ему текстовое содержимое так же, как и раньше:
+ <pre class="brush: js notranslate">var para = document.createElement('p');
+para.textContent = 'We hope you enjoyed the ride.';</pre>
+ </li>
+ <li>Теперь вы можете добавить новый абзац в конце раздела, используя {{domxref("Node.appendChild()")}}:
+ <pre class="brush: js notranslate">sect.appendChild(para);</pre>
+ </li>
+ <li>Наконец, для этой части, давайте добавим текстовый узел в абзац, где находится ссылка, чтобы оформить предложение красиво. Сначала мы создадим текстовый узел, используя {{domxref("Document.createTextNode()")}}:
+ <pre class="brush: js notranslate">var text = document.createTextNode(' — the premier source for web development knowledge.');</pre>
+ </li>
+ <li>Теперь мы возьмем ссылку на абзац, в котором находится ссылка, и добавим к нему текстовый узел:
+ <pre class="brush: js notranslate">var linkPara = document.querySelector('p');
+linkPara.appendChild(text);</pre>
+ </li>
+</ol>
+
+<p>Это большая часть того, что вам нужно для добавления узлов в DOM - вы будете использовать эти методы при построении динамических интерфейсов (мы рассмотрим некоторые примеры позже).</p>
+
+<h3 id="Перемещение_и_удаление_элементов">Перемещение и удаление элементов</h3>
+
+<p>Могут быть моменты, когда вы хотите переместить узлы или вообще удалить их из DOM. Это вполне возможно.</p>
+
+<p>Если бы мы хотели переместить абзац со ссылкой внутри него в нижней части раздела, мы могли бы просто сделать это:</p>
+
+<pre class="brush: js notranslate">sect.appendChild(linkPara);</pre>
+
+<p>Это переводит абзац вниз в нижнюю часть раздела. Вы могли подумать, что это сделает вторую копию, но это не так - <code>linkPara</code> - ссылка на единственную копию этого абзаца. Если вы хотите сделать копию и добавить ее также, вам нужно будет использовать {{domxref("Node.cloneNode()")}}.</p>
+
+<p>Удаление узла довольно просто, по крайней мере, когда у вас есть ссылка на удаляемый узел и его родительский элемент. В нашем случае мы просто используем {{domxref("Node.removeChild()")}}, например:</p>
+
+<pre class="notranslate">sect.removeChild(linkPara);</pre>
+
+<p>Он становится немного сложнее, если вы хотите удалить узел, основанный только на ссылке на себя, что довольно часто. Нет способа сообщить узлу удалить себя, поэтому вам нужно будет сделать следующее.</p>
+
+<pre class="brush: js notranslate">linkPara.parentNode.removeChild(linkPara);</pre>
+
+<p>Попробуйте добавить вышеуказанные строки в свой код.</p>
+
+<h3 id="Управление_стилями">Управление стилями</h3>
+
+<p>Можно управлять стилями CSS с помощью JavaScript различными способами.</p>
+
+<p>Для начала вы можете получить список всех таблиц стилей, прикрепленных к документу, с помощью {{domxref("Document.stylesheets")}}, который возвращает массив объектов {{domxref("CSSStyleSheet")}}. Затем вы можете добавлять / удалять стили по желанию. Однако мы не будем расширять эти функции, потому что они являются несколько архаичным и трудным способом манипулирования стилем. Есть гораздо более простые способы.</p>
+
+<p>Первый способ - добавить встроенные стили непосредственно на элементы, которые вы хотите динамически стилизовать. Это делается с помощью свойства {{domxref("HTMLElement.style")}}, которое содержит встроенную информацию о стиле для каждого элемента документа. Вы можете установить свойства этого объекта для непосредственного обновления стилей элементов.</p>
+
+<ol>
+ <li>В качестве примера попробуйте добавить эти строки в наш текущий пример:
+ <pre class="brush: js notranslate">para.style.color = 'white';
+para.style.backgroundColor = 'black';
+para.style.padding = '10px';
+para.style.width = '250px';
+para.style.textAlign = 'center';</pre>
+ </li>
+ <li>Перезагрузите страницу, и вы увидите, что стили были применены к абзацу. Если вы посмотрите на этот параграф в инспекторе <a href="https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector">Page Inspector/DOM inspector </a>вашего браузера, вы увидите, что эти строки действительно добавляют встроенные стили в документ:
+ <pre class="brush: html notranslate">&lt;p style="color: white; background-color: black; padding: 10px; width: 250px; text-align: center;"&gt;We hope you enjoyed the ride.&lt;/p&gt;</pre>
+ </li>
+</ol>
+
+<div class="note">
+<p>Примечание: Обратите внимание на то, как версии свойств JavaScript стилей CSS пишутся в нижнем регистре верблюжьего стиля (lower camel case), в то время как версии свойств стилей CSS используют дефисы  (например, <code>backgroundColor</code> и <code>background-color</code>). Убедитесь, что вы не перепутали их, иначе это не сработает.</p>
+</div>
+
+<p>Существует еще один распространенный способ динамического управления стилями вашего документа, который мы рассмотрим сейчас.</p>
+
+<ol>
+ <li>Удалите предыдущие пять строк, добавленных в JavaScript.</li>
+ <li>Добавьте в свой HTML-код следующее: {{htmlelement("head")}}:
+ <pre class="notranslate">&lt;style&gt;
+.highlight {
+ color: white;
+ background-color: black;
+ padding: 10px;
+ width: 250px;
+ text-align: center;
+}
+&lt;/style&gt;</pre>
+ </li>
+ <li>Теперь мы перейдем к очень полезному методу для общего манипулирования HTML - {{domxref("Element.setAttribute()")}} - это принимает два аргумента, атрибут, который вы хотите установить для элемента, и значение, которое вы хотите для его установки. В этом случае мы укажем имя класса выделения в нашем абзаце:
+ <pre class="brush: js notranslate">para.setAttribute('class', 'highlight');</pre>
+ </li>
+ <li>Обновите свою страницу, и вы не увидите изменений - CSS по-прежнему применяется к абзацу, но на этот раз, предоставив ему класс, который выбран нашим правилом CSS, а не как встроенные стили CSS.</li>
+</ol>
+
+<p>Какой метод вы выбираете, зависит от вас; оба имеют свои преимущества и недостатки. Первый метод принимает меньше настроек и хорош для простого использования, тогда как второй метод более пурист (без смешивания CSS и JavaScript, без встроенных стилей, которые рассматриваются как плохая практика). Когда вы начнете создавать более крупные приложения, вы, вероятно, начнете использовать второй метод больше, но это действительно зависит от вас.</p>
+
+<p>На данный момент мы не сделали ничего полезного! Нет смысла использовать JavaScript для создания статического контента - вы можете просто записать его в свой HTML и не использовать JavaScript. Это сложнее, чем HTML, и для создания вашего контента с помощью JavaScript также есть другие связанные с ним проблемы (например, не читаемые поисковыми системами).</p>
+
+<p>В следующих параграфах мы рассмотрим еще несколько практических применений DOM API.</p>
+
+<div class="note">
+<p>Примечание. Вы можете найти наш пример <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/dom-example-manipulated.html">finished version of the dom-example.html</a> на GitHub (<a href="https://mdn.github.io/learning-area/javascript/apis/document-manipulation/dom-example-manipulated.html">см. также live</a>).</p>
+</div>
+
+<h2 id="Активное_обучение_динамический_список_покупок">Активное обучение: динамический список покупок</h2>
+
+<p>До сих пор мы действительно смотрели на использование функций {{domxref("Node")}} и {{domxref("Document")}} для управления документами, но нет причин, по которым вы не можете получить данные из других источников и использовать его в пользовательском интерфейсе. Вспомните нашу простую демонстрацию <a href="http://mdn.github.io/learning-area/javascript/apis/introduction/maps-example.html">maps-example.html</a> из последней статьи - там мы извлекли некоторые данные о местоположении и использовали ее для отображения карты вашей области. Вам просто нужно убедиться, что ваши данные в правильном формате; JavaScript упрощает работу, чем многие другие языки, будучи слабо типизированным - например, числа автоматически преобразуются в строки, когда вы хотите распечатать их на экране.</p>
+
+<p>В этом примере мы решим общую проблему: убедитесь, что ваше приложение имеет размер как окно, в котором он просматривается, независимо от его размера. Это часто полезно в таких ситуациях, как игры, где вы хотите использовать как можно большую площадь экрана, чтобы играть в игру.</p>
+
+<p>Для начала создайте локальную копию наших демо-файлов <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/window-resize-example.html">window-resize-example.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/bgtile.png">bgtile.png</a>. Откройте его и посмотрите - вы увидите, что у нас есть элемент {{htmlelement("div")}}, который покрывает небольшую часть экрана, на который нанесена фоновая плитка. Мы будем использовать это, чтобы представить нашу область пользовательского интерфейса приложения.</p>
+
+<ol>
+ <li>Прежде всего, давайте возьмем ссылку на div, а затем возьмем ширину и высоту окна просмотра (внутреннее окно, где отображается ваш документ) и сохраните их в переменных - эти два значения удобно содержатся в {{domxref("Window.innerWidth")}} и {{domxref("Window.innerHeight")}}. Добавьте следующие строки внутри существующего элемента {{htmlelement("script")}}:
+ <pre class="brush: js notranslate">var div = document.querySelector('div');
+var WIDTH = window.innerWidth;
+var HEIGHT = window.innerHeight;</pre>
+ </li>
+ <li>Затем мы динамически изменяем ширину и высоту div, равную ширине окна просмотра. Добавьте следующие две строки ниже своих первых:
+ <pre class="brush: js notranslate">div.style.width = WIDTH + 'px';
+div.style.height = HEIGHT + 'px';</pre>
+ </li>
+ <li>Сохраните и попробуйте обновить браузер - теперь вы должны увидеть, что div становится таким же большим, как ваш видовой экран, независимо от того, какой размер экрана вы используете. Если теперь вы попытаетесь изменить размер окна, чтобы увеличить его, вы увидите, что div остается одного размера - мы устанавливаем его только один раз.</li>
+ <li>Как насчет того, чтобы мы использовали событие, чтобы размер div изменялся при изменении размера окна? Объект {{domxref("Window")}} имеет событие, имеющееся на нем с именем resize, которое запускается каждый раз при изменении размера окна - давайте обратимся к нему через обработчик событий {{domxref("Window.onresize")}} и повторяйте наш размерный код каждый раз, когда он изменяется. Добавьте нижеследующую часть кода:
+ <pre class="brush: js notranslate">window.onresize = function() {
+ WIDTH = window.innerWidth;
+ HEIGHT = window.innerHeight;
+ div.style.width = WIDTH + 'px';
+ div.style.height = HEIGHT + 'px';
+}</pre>
+ </li>
+</ol>
+
+<div class="note">
+<p><strong>Примечание</strong>. Если у вас возникла проблема, посмотрите на наш <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/window-resize-example-finished.html">законченный пример изменения размера окна</a> (<a href="https://mdn.github.io/learning-area/javascript/apis/document-manipulation/window-resize-example-finished.html">см. также live</a>).</p>
+</div>
+
+<h2 id="Активное_обучение_динамический_список_покупок_2">Активное обучение: динамический список покупок</h2>
+
+<p>Чтобы завершить статью, мы хотели бы задать вам небольшой вызов - мы хотим сделать простой пример списка покупок, который позволяет динамически добавлять элементы в список с помощью ввода формы и кнопки. Когда вы добавляете элемент на вход и нажимаете кнопку:</p>
+
+<ul>
+ <li>Элемент должен появиться в списке.</li>
+ <li>Каждому элементу должна быть предоставлена кнопка, которую можно нажать, чтобы удалить этот элемент из списка.</li>
+ <li>Вход должен быть опустошен и сфокусирован, чтобы вы могли ввести другой элемент.</li>
+</ul>
+
+<p>Готовое демо будет выглядеть примерно так:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14563/shopping-list.png" style="border-style: solid; border-width: 1px; display: block; height: 225px; margin: 0px auto; width: 369px;"></p>
+
+<p>Чтобы завершить упражнение, выполните следующие действия и убедитесь, что список ведет себя так, как описано выше.</p>
+
+<ol>
+ <li>Для начала загрузите копию нашего начального файла <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/shopping-list.html">shopping-list.html</a> и скопируйте его где-нибудь. Вы увидите, что у него есть минимальный CSS, список с меткой, ввод и кнопка, пустой список и элемент {{htmlelement("script")}}. Вы будете делать все свои дополнения внутри скрипта.</li>
+ <li>Создайте три переменные, содержащие ссылки на список ({{htmlelement("ul")}}, {{htmlelement("input")}} и {{htmlelement("button")}} элементы.</li>
+ <li>Создайте <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Functions">function</a>, которая будет запускаться в ответ на нажатие кнопки.</li>
+ <li>Внутри тела функции начните с сохранения текущего значения (<a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement#Properties">value</a>) входного элемента в переменной.</li>
+ <li>Затем очистите элемент ввода, установив его значение в пустую строку — <code>''</code>.</li>
+ <li>Создайте три новых элемента - элемент списка ({{htmlelement('li')}}), {{htmlelement('span')}} и {{htmlelement('button')}} и сохраните их в переменных.</li>
+ <li>Добавьте диапазон и кнопку в качестве дочерних элементов списка.</li>
+ <li>Установите текстовое содержимое диапазона на значение входного элемента, которое вы сохранили ранее, и текстовое содержимое кнопки «Удалить».</li>
+ <li>Добавить элемент списка в качестве дочернего списка.</li>
+ <li>Прикрепите обработчик события к кнопке удаления, чтобы при щелчке удалял весь элемент списка, внутри которого он находится.</li>
+ <li>Наконец, используйте метод <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus">focus()</a></code>, чтобы сфокусировать входной элемент, готовый для входа в следующий элемент списка покупок.</li>
+</ol>
+
+<div class="note">
+<p>Примечание: Если у вас возникла действительно сложная проблема, взгляните на наши примеры <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/shopping-list-finished.html">finished shopping list</a> (<a href="http://mdn.github.io/learning-area/javascript/apis/document-manipulation/shopping-list-finished.html">see it running live also</a>.)</p>
+</div>
+
+<h2 id="Краткая_информация">Краткая информация</h2>
+
+<p>Мы закончили изучение документа и манипулирования DOM. На этом этапе вы должны понимать, что важная часть веб-браузера связана с управлением документами и другими аспектами веб-интерфейса пользователя. Самое главное, вы должны понять, что такое Document Object Model, и как манипулировать им для создания полезных функций.</p>
+
+<h2 id="Дополнительная_информация">Дополнительная информация</h2>
+
+<p>Есть много возможностей, которые можно использовать для управления вашими документами. Ознакомьтесь с некоторыми нашими рекомендациями и узнайте, что вы можете обнаружить:</p>
+
+<ul>
+ <li>{{domxref("Document")}}</li>
+ <li>{{domxref("Window")}}</li>
+ <li>{{domxref("Node")}}</li>
+ <li>{{domxref("HTMLElement")}}, {{domxref("HTMLInputElement")}}, {{domxref("HTMLImageElement")}}, etc.</li>
+</ul>
+
+<p>(Полный список веб-индексов API, задокументированных MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/API">Web API index</a>)</p>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Introduction", "Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs")}}</div>
+
+<div>
+<h2 id="В_этот_модуль_входит">В этот модуль входит</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li>
+</ul>
+</div>
diff --git a/files/ru/learn/javascript/client-side_web_apis/third_party_apis/index.html b/files/ru/learn/javascript/client-side_web_apis/third_party_apis/index.html
new file mode 100644
index 0000000000..4977fe99c7
--- /dev/null
+++ b/files/ru/learn/javascript/client-side_web_apis/third_party_apis/index.html
@@ -0,0 +1,482 @@
+---
+title: Сторонние API
+slug: Learn/JavaScript/Client-side_web_APIs/Third_party_APIs
+tags:
+ - 3rd party
+ - API
+ - Third party
+ - Новичку
+translation_of: Learn/JavaScript/Client-side_web_APIs/Third_party_APIs
+---
+<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs/Drawing_graphics", "Learn/JavaScript/Client-side_web_APIs")}}</div>
+
+<p class="summary">API, которые мы рассмотрели до сих пор, встроены в браузер, но не все API таковы. Многие крупные веб-сайты и сервисы, такие как Google Maps, Twitter, Facebook, PayPal и т. д., Предоставляют API-интерфейсы, позволяющие разработчикам использовать свои данные (например, показывать ваш твиттер-поток в вашем блоге) или сервисы (например, отображение пользовательских карт Google на вашем сайте, или использование логина Facebook для входа в систему ваших пользователей). В этой статье рассматривается различие между API-интерфейсами браузера и сторонними API и показано типичное использование последних.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Необходимые условия:</th>
+ <td>Основы JavaScript (см. <a href="/en-US/docs/Learn/JavaScript/First_steps">первые шаги</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">структурные элементы</a>, <a href="/en-US/docs/Learn/JavaScript/Objects">объекты JavaScript</a>), the <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">основы клиентских API</a></td>
+ </tr>
+ <tr>
+ <th scope="row">Задача:</th>
+ <td>Изучить, как работают сторонние API, и как использовать их для улучшения ваших сайтов.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Что_такое_сторонние_API">Что такое сторонние API?</h2>
+
+<p>Сторонние API - это API, предоставляемые третьими лицами — как правило, такими компаниями, как Facebook, Twitter, or Google — чтобы вы могли получить доступ к их функциям с помощью JavaScript и использовать его на своем собственном сайте. Как мы показали в нашей <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">вводной статье об API</a>, одним из наиболее очевидных примеров является использование <a href="https://developers.google.com/maps/">Google Maps APIs</a> для отображения пользовательских карт на ваших страницах.</p>
+
+<p>Давайте снова посмотрим на наш пример карты (см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/introduction/maps-example.html">исходный код на GitHub</a>; <a href="https://mdn.github.io/learning-area/javascript/apis/introduction/maps-example.html">см. это в действии</a>),  и используем его для иллюстрации того, как сторонние API отличаются от API-интерфейсов браузера.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: По умолчанию использование сторонних API на вашем сайте позволит им отслеживать файлы cookie своих доменов, устанавливать файлы cookie в исходное состояние, получать заголовки ссылок, определяющие посещаемые страницы, и разрешать им выполнять JavaScript на страницах, на которых они загружаются с теми же разрешениями (например, выполнить запросы AJAX на ваши серверы с теми же кукисами сеанса). Должны быть оценены вопросы регулирования, безопасности и конфиденциальности.</p>
+</div>
+
+<div class="note">
+<p><strong>Примечание</strong>: Возможно, вы захотите сразу <a href="/en-US/docs/Learn#Getting_our_code_examples">получить все наши примеры кода</a>, в этом случае вы можете просто искать репо для файлов примеров, которые вам нужны в каждом разделе.</p>
+</div>
+
+<h3 id="Они_находятся_на_сторонних_серверах">Они находятся на сторонних серверах</h3>
+
+<p>API браузера встроены в браузер - вы можете получить к ним доступ сразу из JavaScript. Например, <a href="/en-US/docs/Web/API/Geolocation/Using_geolocation">API геолокации</a>, доступный в нашем примере, осуществляется с использованием свойства геолокации объекта <code><a href="/en-US/docs/Web/API/Navigator">Navigator</a></code>, которое возвращает объект <code><a href="/en-US/docs/Web/API/Geolocation">Geolocation</a></code>. Этот пример использует метод <code><a href="/en-US/docs/Web/API/Geolocation/getCurrentPosition">getCurrentPosition()</a></code> этого объекта, для запроса текущего положения устройства:</p>
+
+<pre class="brush: js">navigator.geolocation.getCurrentPosition(function(position) { ... });</pre>
+
+<p>Сторонние API, с другой стороны, расположены на сторонних серверах. Чтобы получить доступ к ним из JavaScript, вам сначала нужно подключиться к функциям API и сделать его доступным на вашей странице. Обычно это связано с первой ссылкой на библиотеку JavaScript, доступную на сервере через элемент {{htmlelement("script")}}, как показано в нашем примере:</p>
+
+<pre class="brush: js">&lt;script type="text/javascript" src="https://maps.google.com/maps/api/js?key=AIzaSyDDuGt0E5IEGkcE6ZfrKfUtE9Ko_de66pA"&gt;&lt;/script&gt;</pre>
+
+<p>Затем вы можете начать использовать объекты, доступные в этой библиотеке. Например:</p>
+
+<pre class="brush: js">var latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
+var myOptions = {
+ zoom: 8,
+ center: latlng,
+ mapTypeId: google.maps.MapTypeId.TERRAIN,
+ disableDefaultUI: true
+}
+
+var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);</pre>
+
+<p>Здесь мы создаем новый объект <code>LatLng</code>, используя конструктор <code>google.maps.LatLng()</code>, который содержит широту и долготу местоположения, которое мы хотим показать, полученные из API геолокации. Затем мы создаем объект опций (<code>myOptions</code>), содержащий эту и другую информацию, связанную с отображением карты. Наконец, мы фактически создаем карту, используя конструктор <code>google.maps.Map()</code>, который принимает в качестве параметров элемент, на котором мы хотим нарисовать карту, и объект опций.</p>
+
+<p>Это вся информация, которую API Карт Google требует для построения простой карты. Сервер, к которому вы подключаетесь, обрабатывает все сложные вещи, такие как отображение правильных фрагментов карты для отображаемой области и т. д.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Некоторые API обрабатывают доступ к их функциям несколько иначе, требуя от разработчика сделать HTTP-запрос (см. <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Получение данных с сервера</a>) на определенный шаблон URL для получения определенных данных. Они называются RESTful API, и мы покажем пример этого позже в статье.</p>
+</div>
+
+<h3 id="Разрешения_обрабатываются_по-разному">Разрешения обрабатываются по-разному</h3>
+
+<p>Безопасность API-интерфейсов браузеров, как правило, обрабатывается запросами разрешения, как <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction#They_have_additional_security_mechanisms_where_appropriate">описано в нашей первой статье</a>. Целью этого является то, что пользователь знает, что происходит на сайтах, которые он посещает, и с меньшей вероятностью может стать жертвой того, кто использует API, злонамеренно.</p>
+
+<p>Сторонние API имеют немного другую систему разрешений - они, как правило, используют ключевые коды, чтобы позволить разработчикам получить доступ к функциям API. Просмотрите URL-адрес библиотеки API Карт Google, с которой мы связались:</p>
+
+<pre>https://maps.google.com/maps/api/js?key=AIzaSyDDuGt0E5IEGkcE6ZfrKfUtE9Ko_de66pA</pre>
+
+<p>Параметр URL, указанный в конце URL-адреса, является ключом разработчика - разработчик приложения должен применять его для получения ключа, а затем включать его в свой код определенным образом, чтобы иметь доступ к функциям API. В случае с Картами Google (и другими API Google) вы подаете заявку на получение ключа на <a href="https://console.cloud.google.com/">Google Cloud Platform</a>.</p>
+
+<p>Другие API могут потребовать, чтобы вы включили ключ немного по-другому, но шаблон для большинства из них довольно схож. <br>
+  <br>
+ Требование к ключу заключается в том, что не каждый может использовать функциональность API без какой-либо подотчетности. Когда разработчик зарегистрировался для ключа, они затем известны поставщику API, и действие может быть предпринято, если они начинают делать что-то вредоносное с помощью API (например, отслеживать местоположение пользователей или пытаться спамить API с множеством запросов для остановки его работы, например). Самое простое действие - просто отменить их привилегии API.</p>
+
+<h2 id="Расширенный_пример_Карт_Google">Расширенный пример Карт Google</h2>
+
+<p>Теперь когда мы рассмотрели пример API Карт Google и посмотрели, как он работает, добавим еще несколько функций, чтобы показать, как использовать некоторые другие функции API.</p>
+
+<ol>
+ <li>
+ <p>Чтобы начать этот раздел, сделайте себе копию <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/third-party-apis/google-maps/maps_start.html">исходного файла Карт Google</a>, в новой папке. Если Вы уже <a href="/en-US/docs/Learn#Getting_our_code_examples">клонировали репозиторий примеров</a>, у вас уже есть копия этого файла, которую Вы можете найти в папке the <em>javascript/apis/third-party-apis/google-maps</em>.</p>
+ </li>
+ <li>
+ <p>Затем получите свой собственный ключ разработчика, выполнив следующие шаги:</p>
+
+ <ol>
+ <li>Перейдите в <a href="https://console.cloud.google.com/apis/dashboard">панель управления API-интерфейсом Google Cloud Platform</a>.</li>
+ <li>Создайте новый проект, если у вас его еще нет.</li>
+ <li>Нажмите кнопку <em>Enable API</em>.</li>
+ <li>Выберите <em>Google Maps JavaScript API</em>.</li>
+ <li>Нажмите кнопку <em>Enable</em>.</li>
+ <li>Нажмите <em>Create credentials</em>, затем выберите <em>API key</em>.</li>
+ <li>Скопируйте свой ключ API и замените существующий ключ в первом элементе {{htmlelement ('script')}} примера вашим собственным (фрагмент между <code>?key=</code> и меткой закрытия закрытия атрибута (<code>"</code>).)</li>
+ </ol>
+
+ <div class="note">
+ <p><strong>Примечание</strong>: Получение ключей API, связанных с Google, может быть немного затруднительным: в Менеджере API Google Cloud Platform много разных экранов, и рабочий процесс может немного отличаться в зависимости от того, как у вас уже установлена ​​учетная запись. Если у вас возникнут проблемы с этим шагом, мы будем рады помочь — <a href="/en-US/docs/Learn#Contact_us">Свяжитесь с нами</a>.</p>
+ </div>
+ </li>
+ <li>Откройте исходный файл Карт Google, найдите строку <code>INSERT-YOUR-API-KEY-HERE</code>, и замените ее фактическим ключом API, который вы получили из панели управления Google Cloud Platform API Manager.</li>
+</ol>
+
+<h3 id="Adding_a_custom_marker">Adding a custom marker</h3>
+
+<p>Adding a marker (icon) at a certain point on the map is easy — you just need to create a new marker using the <code>google.maps.Marker()</code> constructor, passing it an options object containing the position to display the marker at (as a <code>LatLng</code> object), and the <code>Map</code> object to display it on.</p>
+
+<ol>
+ <li>
+ <p>Add the following just below the <code>var map ...</code> line:</p>
+
+ <pre class="brush: js">var marker = new google.maps.Marker({
+ position: latlng,
+ map: map
+});</pre>
+
+ <p>Now if you refresh your page, you'll see a nice little marker pop up in the centre of the map. This is cool, but it is not exactly a custom marker — it is using the default marker icon.</p>
+ </li>
+ <li>
+ <p>To use a custom icon, we need to specify it when we create the marker, using its URL. First of all, add the following line above the previous block you added:</p>
+
+ <pre class="brush: js">var iconBase = 'https://maps.google.com/mapfiles/kml/shapes/';</pre>
+
+ <p>This defines the base URL where all the official Google Maps icons are stored (you could also specify your own icon location if you wished).</p>
+ </li>
+ <li>
+ <p>The icon location is specified in the <code>icon</code> property of the options object. Update the constructor like so:</p>
+
+ <pre class="brush: js">var marker = new google.maps.Marker({
+ position: latlng,
+ icon: iconBase + 'flag_maps.png',
+ map: map
+});</pre>
+
+ <p>Here we specify the icon property value as the <code>iconBase</code> plus the icon filename, to create the complete URL. Now try reloading your example and you'll see a custom marker displayed on your map!</p>
+ </li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: See <a href="https://developers.google.com/maps/documentation/javascript/custom-markers">Customizing a Google Map: Custom Markers</a> for more information.</p>
+</div>
+
+<div class="note">
+<p><strong>Note</strong>: See <a href="https://fusiontables.google.com/DataSource?dsrcid=308519#map:id=3">Map marker or Icon names</a> to find out what other icons are available, and see what their reference names are. Their file name will be the icon name they display when you click on them, with ".png" added on the end.</p>
+</div>
+
+<h3 id="Displaying_a_popup_when_the_marker_is_clicked">Displaying a popup when the marker is clicked</h3>
+
+<p>Another common use case for Google Maps is displaying more information about a place when its name or marker is clicked (popups are called <strong>info windows</strong> in the Google Maps API). This is also very simple to achieve, so let's have a look at it.</p>
+
+<ol>
+ <li>
+ <p>First of all, you need to specify a JavaScript string containing HTML that will define the content of the popup. This will be injected into the popup by the API and can contain just about any content you want. Add the following line below the <code>google.maps.Marker()</code> constructor definition:</p>
+
+ <pre class="brush: js">var contentString = '&lt;div id="content"&gt;&lt;h2 id="firstHeading" class="firstHeading"&gt;Custom info window&lt;/h2&gt;&lt;p&gt;This is a cool custom info window.&lt;/p&gt;&lt;/div&gt;';</pre>
+ </li>
+ <li>
+ <p>Next, you need to create a new info window object using the <code>google.maps.InfoWindow()</code> constructor. Add the following below your previous line:</p>
+
+ <pre class="brush: js">var infowindow = new google.maps.InfoWindow({
+ content: contentString
+});</pre>
+
+ <p>There are other properties available (see <a href="https://developers.google.com/maps/documentation/javascript/infowindows">Info Windows</a>), but here we are just specifying the <code>content</code> property in the options object, which points to the source of the content.</p>
+ </li>
+ <li>
+ <p>Finally, to get the popup to display when the marker is clicked, we use a simple click event handler. Add the following below the <code>google.maps.InfoWindow()</code> constructor:</p>
+
+ <pre class="brush: js">marker.addListener('click', function() {
+ infowindow.open(map, marker);
+});</pre>
+
+ <p>Inside the function, we simply invoke the infowindow's <code>open()</code> function, which takes as parameters the map you want to display it on, and the marker you want it to appear next to.</p>
+ </li>
+ <li>
+ <p>Now try reloading the example, and clicking on the marker!</p>
+ </li>
+</ol>
+
+<h3 id="Controlling_what_map_controls_are_displayed">Controlling what map controls are displayed</h3>
+
+<p>Inside the original <code>google.maps.Map()</code> constructor, you'll see the property <code>disableDefaultUI: true</code> specified. This disables all the standard UI controls you usually get on Google Maps.</p>
+
+<ol>
+ <li>
+ <p>Try setting its value to <code>false</code> (or just removing the line altogether) then reloading your example, and you'll see the map zoom buttons, scale indicator, etc.</p>
+ </li>
+ <li>
+ <p>Now undo your last change.</p>
+ </li>
+ <li>
+ <p>You can show or hide the controls in a more granular fashion by using other properties that specify single UI features. Try adding the following underneath the <code>disableDefaultUI: true</code> (remember to put a comma after <code>disableDefaultUI: true</code>, otherwise you'll get an error):</p>
+
+ <pre class="brush: js">zoomControl: true,
+mapTypeControl: true,
+scaleControl: true,</pre>
+ </li>
+ <li>
+ <p>Now try reloading the example to see the effect these properties have. You can find more options to experiment with at the <a href="https://developers.google.com/maps/documentation/javascript/3.exp/reference#MapOptions">MapOptions object reference page</a>.</p>
+ </li>
+</ol>
+
+<p>That's it for now — have a look around the <a href="https://developers.google.com/maps/documentation/javascript/">Google Maps APIs documentation</a>, and have some more fun playing!</p>
+
+<h2 id="A_RESTful_API_—_NYTimes">A RESTful API — NYTimes</h2>
+
+<p>Now let's look at another API example — the <a href="https://developer.nytimes.com">New York Times API</a>. This API allows you to retrieve New York Times news story information and display it on your site. This type of API is known as a <strong>RESTful API</strong> — instead of getting data using the features of a JavaScript library like we did with Google Maps, we get data by making HTTP requests to specific URLs, with data like search terms and other properties encoded in the URL (often as URL parameters). This is a common pattern you'll encounter with APIs.</p>
+
+<h2 id="An_approach_for_using_third-party_APIs">An approach for using third-party APIs</h2>
+
+<p>Below we'll take you through an exercise to show you how to use the NYTimes API, which also provides a more general set of steps to follow that you can use as an approach for working with new APIs.</p>
+
+<h3 id="Find_the_documentation">Find the documentation</h3>
+
+<p>When you want to use a third party API, it is essential to find out where the documentation is, so you can find out what features the API has, how you use them, etc. The New York Times API documentation is at <a href="https://developer.nytimes.com/">https://developer.nytimes.com/</a>.</p>
+
+<h3 id="Get_a_developer_key">Get a developer key</h3>
+
+<p>Most APIs require you to use some kind of developer key, for reasons of security and accountability. To sign up for an NYTimes API key, you need to go to <a href="https://developer.nytimes.com/signup">https://developer.nytimes.com/signup</a>.</p>
+
+<ol>
+ <li>
+ <p>Let's request a key for the "Article Search API" — fill in the form, selecting this as the API you want to use.</p>
+ </li>
+ <li>
+ <p>Next, wait a few minutes, then get the key from your email.</p>
+ </li>
+ <li>
+ <p>Now, to start the example off, make copies of <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/third-party-apis/nytimes/nytimes_start.html">nytimes_start.html</a> and <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/third-party-apis/nytimes/nytimes.css">nytimes.css</a> in a new directory on your computer. If you've already <a href="/en-US/docs/Learn#Getting_our_code_examples">cloned the examples repository</a>, you'll already have a copy of these files, which you can find in the <em>javascript/apis/third-party-apis/nytimes</em> directory. Initially the <code>&lt;script&gt;</code> element contains a number of variables needed for the setup of the example; below we'll fill in the required functionality.</p>
+ </li>
+</ol>
+
+<p>The app will end up allowing you to type in a search term and optional start and end dates, which it will then use to query the Article Search API and display the search results.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14821/nytimes-search.png" style="border-style: solid; border-width: 1px; display: block; height: 374px; margin: 0px auto; width: 700px;"></p>
+
+<h3 id="Connect_the_API_to_your_app">Connect the API to your app</h3>
+
+<p>First, you'll need to make a connection between the API, and your app. This is usually done either by connecting to the API's JavaScript (as we did in the Google Maps API), or by making requests to the correct URL(s).</p>
+
+<p>In the case of this API, you need to include the API key as a <a href="/en-US/docs/Web/HTTP/Methods/GET">get</a> parameter every time you request data from it.</p>
+
+<ol>
+ <li>
+ <p>Find the following line:</p>
+
+ <pre class="brush: js">var key = 'INSERT-YOUR-API-KEY-HERE';</pre>
+
+ <p>Replace <code>INSERT-YOUR-API-KEY-HERE</code> with the actual API key you got in the previous section.</p>
+ </li>
+ <li>
+ <p>Add the following line to your JavaScript, below the "<code>// Event listeners to control the functionality</code>" comment. This runs a function called <code>fetchResults()</code> when the form is submitted (the button is pressed).</p>
+
+ <pre class="brush: js">searchForm.addEventListener('submit', submitSearch);</pre>
+ </li>
+ <li>
+ <p>Now add the <code>submitSearch()</code> and <code>fetchResults()</code> function definitions, below the previous line:</p>
+
+ <pre class="brush: js">function submitSearch(e) {
+ pageNumber = 0;
+ fetchResults(e);
+}
+
+function fetchResults(e) {
+ // Use preventDefault() to stop the form submitting
+ e.preventDefault();
+
+ // Assemble the full URL
+ url = baseURL + '?api-key=' + key + '&amp;page=' + pageNumber + '&amp;q=' + searchTerm.value <span class="blob-code-inner"><span class="pl-s1"><span class="pl-k x">+</span><span class="x"> </span><span class="pl-s"><span class="pl-pds x">'</span><span class="x">&amp;fq=document_type:("article")</span><span class="pl-pds x x-last">'</span></span></span></span>;
+
+ if(startDate.value !== '') {
+ url += '&amp;begin_date=' + startDate.value;
+ };
+
+ if(endDate.value !== '') {
+ url += '&amp;end_date=' + endDate.value;
+ };
+
+}</pre>
+ </li>
+</ol>
+
+<p><code>submitSearch()</code> sets the page number back to 0 to begin with, then calls <code>fetchResults()</code>. This first calls <code><a href="/en-US/docs/Web/API/Event/preventDefault">preventDefault()</a></code> on the event object, to stop the form actually submitting (which would break the example). Next, we use some string manipulation to assemble the full URL that we will make the request to. We start off by assembling the parts we deem as mandatory for this demo:</p>
+
+<ul>
+ <li>The base URL (taken from the <code>baseURL</code> variable).</li>
+ <li>The API key, which has to be specified in the <code>api-key</code> URL parameter (the value is taken from the <code>key</code> variable).</li>
+ <li>The page number, which has to be specified in the <code>page</code> URL parameter (the value is taken from the <code>pageNumber</code> variable).</li>
+ <li>The search term, which has to be specified in the <code>q</code> URL parameter (the value is taken from the value of the <code>searchTerm</code> text {{htmlelement("input")}}).</li>
+ <li>The document type to return results for, as specified in an expression passed in via the <code>fq</code> URL parameter. In this case, we just want to return articles.</li>
+</ul>
+
+<p>Next, we use a couple of <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if()</a></code> statements to check whether the <code>startDate</code> and <code>endDate</code> <code>&lt;input&gt;</code>s have had values filled in on them. If they do, we append their values to the URL, specified in <code>begin_date</code> and <code>end_date</code> URL parameters respectively.</p>
+
+<p>So, a complete URL would end up looking something like this:</p>
+
+<pre>https://api.nytimes.com/svc/search/v2/articlesearch.json?api-key=4f3c267e125943d79b0a3e679f608a78&amp;page=0&amp;q=cats
+&amp;<span class="blob-code-inner"><span class="pl-s1"><span class="pl-s"><span class="x">fq=document_type:("article")</span></span></span></span>&amp;begin_date=20170301&amp;end_date=20170312</pre>
+
+<div class="note">
+<p><strong>Note</strong>: You can find more details of what URL parameters can be included in the <a href="https://developer.nytimes.com/article_search_v2.json">Article Search API reference</a>.</p>
+</div>
+
+<div class="note">
+<p><strong>Note</strong>: The example has rudimentary form data validation — the search term field has to be filled in before the form can be submitted (achieved using the <code>required</code> attribute), and the date fields have <code>pattern</code> attributes specified, which means they won't submit unless their values consist of 8 numbers (<code>pattern="[0-9]{8}"</code>). See <a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Form data validation</a> for more details on how these work.</p>
+</div>
+
+<h3 id="Requesting_data_from_the_API">Requesting data from the API</h3>
+
+<p>Now we've constructed our URL, let's make a request to it. We'll do this using the <a href="/en-US/docs/Web/API/Fetch_API/Using_Fetch">Fetch API</a>.</p>
+
+<p>Add the following code block inside the <code>fetchResults()</code> function, just above the closing curly brace:</p>
+
+<pre class="brush: js">// Use fetch() to make the request to the API
+fetch(url).then(function(result) {
+ return result.json();
+}).then(function(json) {
+ displayResults(json);
+});</pre>
+
+<p>Here we run the request by passing our <code>url</code> variable to <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code>, convert the response body to JSON using the <code><a href="/en-US/docs/Web/API/Body/json">json()</a></code> function, then pass the resulting JSON to the <code>displayResults()</code> function so the data can be displayed in our UI.</p>
+
+<h3 id="Displaying_the_data">Displaying the data</h3>
+
+<p>OK, let's look at how we'll display the data. Add the following function below your <code>fetchResults()</code> function.</p>
+
+<pre class="brush: js">function displayResults(json) {
+ while (section.firstChild) {
+ section.removeChild(section.firstChild);
+ }
+
+ var articles = json.response.docs;
+
+ if(articles.length === 10) {
+ nav.style.display = 'block';
+ } else {
+ nav.style.display = 'none';
+ }
+
+ if(articles.length === 0) {
+ var para = document.createElement('p');
+ para.textContent = 'No results returned.'
+ section.appendChild(para);
+ } else {
+ for(var i = 0; i &lt; articles.length; i++) {
+ var article = document.createElement('article');
+ var heading = document.createElement('h2');
+ var link = document.createElement('a');
+ var img = document.createElement('img');
+ var para1 = document.createElement('p');
+ var para2 = document.createElement('p');
+ var clearfix = document.createElement('div');
+
+ var current = articles[i];
+ console.log(current);
+
+ link.href = current.web_url;
+ link.textContent = current.headline.main;
+ para1.textContent = current.<span class="blob-code-inner"><span class="pl-s1"><span class="pl-smi x x-first x-last">snippet</span></span></span>;
+ para2.textContent = 'Keywords: ';
+ for(var j = 0; j &lt; current.keywords.length; j++) {
+ var span = document.createElement('span');
+ span.textContent += current.keywords[j].value + ' ';
+ para2.appendChild(span);
+ }
+
+ if(current.multimedia.length &gt; 0) {
+ img.src = 'http://www.nytimes.com/' + current.multimedia[0].url;
+ img.alt = current.headline.main;
+ }
+
+ clearfix.setAttribute('class','clearfix');
+
+ article.appendChild(heading);
+ heading.appendChild(link);
+ article.appendChild(img);
+ article.appendChild(para1);
+ article.appendChild(para2);
+ article.appendChild(clearfix);
+ section.appendChild(article);
+ }
+ }
+};</pre>
+
+<p>There's a lot of code here; let's explain it step by step:</p>
+
+<ul>
+ <li>The <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/while">while</a></code> loop is a common pattern used to delete all of the contents of a DOM element, in this case, the {{htmlelement("section")}} element. We keep checking to see if the <code>&lt;section&gt;</code> has a first child, and if it does, we remove the first child. The loop ends when <code>&lt;section&gt;</code> no longer has any children.</li>
+ <li>Next, we set the <code>articles</code> variable to equal <code>json.response.docs</code> — this is the array holding all the objects that represent the articles returned by the search. This is done purely to make the following code a bit simpler.</li>
+ <li>The first <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if()</a></code> block checks to see if 10 articles are returned (the API returns up to 10 articles at a time.) If so, we display the {{htmlelement("nav")}} that contains the <em>Previous 10</em>/<em>Next 10</em> pagination buttons. If less than 10 articles are returned, they will all fit on one page, so we don't need to show the pagination buttons. We will wire up the pagination functionality in the next section.</li>
+ <li>The next <code>if()</code> block checks to see if no articles are returned. If so, we don't try to display any — we just create a {{htmlelement("p")}} containing the text "No results returned." and insert it into the <code>&lt;section&gt;</code>.</li>
+ <li>If some articles are returned, we, first of all, create all the elements that we want to use to display each news story, insert the right contents into each one, and then insert them into the DOM at the appropriate places. To work out which properties in the article objects contained the right data to show, we consulted the <a href="https://developer.nytimes.com/article_search_v2.json">Article Search API reference</a>. Most of these operations are fairly obvious, but a few are worth calling out:
+ <ul>
+ <li>We used a <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for">for loop</a> (<code>for(var j = 0; j &lt; current.keywords.length; j++) { ... }</code> ) to loop through all the keywords associated with each article, and insert each one inside its own {{htmlelement("span")}}, inside a <code>&lt;p&gt;</code>. This was done to make it easy to style each one.</li>
+ <li>We used an <code>if()</code> block (<code>if(current.multimedia.length &gt; 0) { ... }</code>) to check whether each article actually has any images associated with it (some stories don't.) We display the first image only if it actually exists (otherwise an error would be thrown).</li>
+ <li>We gave our &lt;div&gt; element a class of "clearfix", so we can easily apply clearing to it (this technique is needed at the time of writing to stop floated layouts from breaking.)</li>
+ </ul>
+ </li>
+</ul>
+
+<p>If you try the example now, it should work, although the pagination buttons won't work yet.</p>
+
+<h3 id="Wiring_up_the_pagination_buttons">Wiring up the pagination buttons</h3>
+
+<p>To make the pagination buttons work, we will increment (or decrement) the value of the <code>pageNumber</code> variable, and then re-rerun the fetch request with the new value included in the page URL parameter. This works because the NYTimes API only returns 10 results at a time — if more than 10 results are available, it will return the first 10 (0-9) if the <code>page</code> URL parameter is set to 0 (or not included at all — 0 is the default value), the next 10 (10-19) if it is set to 1, and so on.</p>
+
+<p>This allows us to easily write a simplistic pagination function.</p>
+
+<ol>
+ <li>
+ <p>Below the existing <code><a href="/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code> call, add these two new ones, which cause the <code>nextPage()</code> and <code>previousPage()</code> functions to be invoked when the relevant buttons are clicked:</p>
+
+ <pre class="brush: js">nextBtn.addEventListener('click', nextPage);
+previousBtn.addEventListener('click', previousPage);</pre>
+ </li>
+ <li>
+ <p>Below your previous addition, let's define the two functions — add this code now:</p>
+
+ <pre class="brush: js">function nextPage(e) {
+ pageNumber++;
+ fetchResults(e);
+};
+
+function previousPage(e) {
+ if(pageNumber &gt; 0) {
+ pageNumber--;
+ } else {
+ return;
+ }
+ fetchResults(e);
+};</pre>
+
+ <p>The first function is simple — we increment the <code>pageNumber</code> variable, then run the <code>fetchResults()</code> function again to display the next page's results.</p>
+
+ <p>The second function works nearly exactly the same way in reverse, but we also have to take the extra step of checking that <code>pageNumber</code> is not already zero before decrementing it — if the fetch request runs with a minus <code>page</code> URL parameter, it could cause errors. If the <code>pageNumber</code> is already 0, we simply <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/return">return</a></code> out of the function, to avoid wasting processing power (If we are already at the first page, we don't need to load the same results again).</p>
+ </li>
+</ol>
+
+<h2 id="YouTube_example">YouTube example</h2>
+
+<p>We also built another example for you to study and learn from — see our <a href="https://mdn.github.io/learning-area/javascript/apis/third-party-apis/youtube/">YouTube video search example</a>. This uses two related APIs:</p>
+
+<ul>
+ <li>The <a href="https://developers.google.com/youtube/v3/docs/">YouTube Data API</a> to search for YouTube videos and return results.</li>
+ <li>The <a href="https://developers.google.com/youtube/iframe_api_reference">YouTube IFrame Player API</a> to display the returned video examples inside IFrame video players so you can watch them.</li>
+</ul>
+
+<p>This example is interesting because it shows two related third-party APIs being used together to build an app. The first one is a RESTful API, while the second one works more like Google Maps (with constructors, etc.). It is worth noting however that both of the APIs require a JavaScript library to be applied to the page. The RESTful API has functions available to handle making the HTTP requests and returning the results, so you don't have to write them out yourself using say fetch or XHR.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14823/youtube-example.png" style="border-style: solid; border-width: 1px; display: block; height: 389px; margin: 0px auto; width: 700px;"></p>
+
+<p>We are not going to say too much more about this example in the article — <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/third-party-apis/youtube">the source code</a> has detailed comments inserted inside it to explain how it works.</p>
+
+<h2 id="Summary">Summary</h2>
+
+<p>This article has given you a useful introduction to using third party APIs to add functionality to your websites.</p>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs/Drawing_graphics", "Learn/JavaScript/Client-side_web_APIs")}}</p>
+
+<p> </p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li>
+</ul>