diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
commit | 074785cea106179cb3305637055ab0a009ca74f2 (patch) | |
tree | e6ae371cccd642aa2b67f39752a2cdf1fd4eb040 /files/ru/learn/javascript/client-side_web_apis/fetching_data/index.html | |
parent | da78a9e329e272dedb2400b79a3bdeebff387d47 (diff) | |
download | translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.gz translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.bz2 translated-content-074785cea106179cb3305637055ab0a009ca74f2.zip |
initial commit
Diffstat (limited to 'files/ru/learn/javascript/client-side_web_apis/fetching_data/index.html')
-rw-r--r-- | files/ru/learn/javascript/client-side_web_apis/fetching_data/index.html | 379 |
1 files changed, 379 insertions, 0 deletions
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></script></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> |