es6
31
1-js/10-es-modern/16-fetch/article.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
# AJAX-запросы: fetch
|
||||
|
||||
Метод [fetch](https://fetch.spec.whatwg.org/) -- это `XMLHttpRequest` нового поколения. Он предоставляет улучшенный интерфейс для осуществления запросов к серверу: как по части возможностей и контроля над происходящим, так и по синтаксису, так как построен на промисах.
|
||||
|
||||
Поддержка в браузерах пока не очень распространена, но есть [полифилл](https://github.com/github/fetch) и не один.
|
||||
|
||||
## Использование
|
||||
|
||||
Синтаксис:
|
||||
|
||||
Начнём сразу с примера:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
fetch('/article/fetch/user.json')
|
||||
.then( response => {
|
||||
alert(response.headers.get('Content-Type')); // text/html; charset=utf-8
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then( user => alert(user.name) ) // iliakan
|
||||
.catch( alert );
|
||||
```
|
||||
|
||||
Поток такой:
|
||||
|
||||
<ul>
|
||||
<li>
|
4
1-js/10-es-modern/16-fetch/user.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "iliakan",
|
||||
"isAdmin": true
|
||||
}
|
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 65 KiB |
|
@ -1,5 +1,5 @@
|
|||
|
||||
# Генераторы
|
||||
# Генераторы [todo]
|
||||
|
||||
Генераторы -- новый вид функций в современном JavaScript. Они отличаются от обычных тем, что могут приостанавливать своё выполнение, возвращать промежуточный результат и далее возобновлять его позже, в произвольный момент времени.
|
||||
|
||||
|
@ -332,4 +332,119 @@ alert( generator.next(9).done ); // true
|
|||
Исключением является первый вызов `next`, который не может передать значение в генератор, т.к. ещё не было ни одного `yield`.
|
||||
|
||||
|
||||
## generator.throw
|
||||
|
||||
Как мы видели в примерах выше, внешний код может вернуть генератору в качестве результата `yield` любое значение.
|
||||
|
||||
Можно "вернуть" не только результат, но и ошибку!
|
||||
|
||||
Это делает вызов `generator.throw(err)`.
|
||||
|
||||
Например:
|
||||
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
function* gen() {
|
||||
// Передать вопрос во внешний код и подождать ответа
|
||||
try {
|
||||
let result = yield "Сколько будет 2 + 2?";
|
||||
|
||||
alert(result);
|
||||
} catch(e) {
|
||||
alert(e);
|
||||
}
|
||||
}
|
||||
|
||||
let generator = gen();
|
||||
|
||||
let question = generator.next().value;
|
||||
|
||||
*!*
|
||||
generator.throw(new Error("ответ не найден в моей базе данных"));
|
||||
*/!*
|
||||
```
|
||||
|
||||
"Вброшенная" извне ошибка обрабатывается как обычно. Она возникает в строке с `yield` и может быть перехвачена `try..catch`, как продемонстрировано выше.
|
||||
|
||||
|
||||
# Плоский асинхронный код
|
||||
|
||||
Одна из основных областей применения генераторов -- написание "плоского" асинхронного кода.
|
||||
|
||||
Общий принцип такой:
|
||||
<ul>
|
||||
<li>Генератор `yield'ит` не просто значения, а промисы.</li>
|
||||
<li>Есть специальная "функция-чернорабочий" `execute(generator)` которая запускает генератор, последовательными вызовами `next` получает из него эти промисы, ждёт их выполнения и возвращает в генератор результат, пока генератор не завершится.</li>
|
||||
<li>Последнее значение генератора `execute` возвращает через промис, коллбэк или просто использует, как в примере ниже.</li>
|
||||
</ul>
|
||||
|
||||
Получается примерно так:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
function* showUserAvatar() {
|
||||
|
||||
let userFetch = yield fetch('/article/generator/user.json');
|
||||
let userInfo = yield userFetch.json();
|
||||
|
||||
let githubFetch = yield fetch(`https://api.github.com/users/${userInfo.name}`);
|
||||
let githubUserInfo = yield githubFetch.json();
|
||||
|
||||
let img = new Image();
|
||||
img.src = githubUserInfo.avatar_url;
|
||||
img.className = "promise-avatar-example";
|
||||
document.body.appendChild(img);
|
||||
|
||||
yield new Promise(resolve => setTimeout(resolve, 3000));
|
||||
|
||||
img.remove();
|
||||
|
||||
return img.src;
|
||||
}
|
||||
|
||||
function execute(generator, yieldValue) {
|
||||
|
||||
let next = generator.next(yieldValue);
|
||||
|
||||
if (!next.done) {
|
||||
next.value.then(
|
||||
result => execute(generator, result),
|
||||
err => generator.throw(err)
|
||||
);
|
||||
} else {
|
||||
// return из генератора (его результат)
|
||||
alert(next.value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*!*
|
||||
execute( showUserAvatar() );
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
[head]
|
||||
<style>
|
||||
.promise-avatar-example {
|
||||
border-radius: 50%;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
</style>
|
||||
[/head]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
BIN
1-js/10-es-modern/17-generator/genYield2-3.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
1-js/10-es-modern/17-generator/genYield2-3@2x.png
Normal file
After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 9 KiB After Width: | Height: | Size: 9 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
4
1-js/10-es-modern/17-generator/user.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "iliakan",
|
||||
"isAdmin": true
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
# Таблица транспортов и их возможностей
|
||||
|
||||
Здесь мы подведём итог раздела, сравним транспорты и их возможности.
|
||||
[cut]
|
||||
|
||||
## Способы опроса сервера
|
||||
|
||||
Основные способы опроса сервера:
|
||||
<ol>
|
||||
<li>**Частые опросы** -- регулярно к серверу отправляется запрос за данными. Сервер тут же отвечает на него, возвращая данные, если они есть. Если нет -- получается, что запрос был зря.
|
||||
|
||||
Этот способ очень лёгок в реализации, но приводит к большому количеству лишних запросов, поэтому мы его далее не рассматриваем.
|
||||
</li>
|
||||
<li>**Длинные опросы** -- к серверу отправляется запрос за данными. Сервер не отвечает на него, пока данные не появятся. Когда данные появились -- ответ с ними отправляется в браузер, и тот тут же делает новый запрос.
|
||||
|
||||
Способ хорош, пока сообщений не слишком много. В идеальном случае соединение почти всё время висит открытым, лишь иногда сервер отвечает на него, доставляя данные в браузер.
|
||||
|
||||
Также удобен в реализации, но даёт большое количество висящий соединений на сервере. Не все сервера хорошо поддерживают это. Например, `Apache` будет есть очень много памяти.
|
||||
</li>
|
||||
<li>**Потоковое соединение** -- открыто соединение к серверу, и через него непрерывно поступают данные.</li>
|
||||
</ol>
|
||||
|
||||
## Таблица транспортов
|
||||
Основные характеристики всех транспортов, которые мы обсуждали в деталях, собраны в этой таблице.
|
||||
|
||||
Они были детально рассмотрены в предыдущих главах раздела.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>`XMLHttpRequest`</th>
|
||||
<th>`IFRAME`</th>
|
||||
<th>`SCRIPT`</th>
|
||||
<th>`EventSource`</th>
|
||||
<th>`WebSocket`</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Кросс-доменность</th>
|
||||
<td>да, кроме IE9-<a class="link-ref" href="#x1">x1</a></td>
|
||||
<td>да<a class="link-ref" href="#i1">i1</a></td>
|
||||
<td>да</td>
|
||||
<td>да</td>
|
||||
<td>да</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Методы</th>
|
||||
<td>Любые</td>
|
||||
<td>GET / POST</td>
|
||||
<td>GET</td>
|
||||
<td>GET</td>
|
||||
<td>Свой протокол</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>COMET</th>
|
||||
<td>Длинные опросы<a class="link-ref" href="#x2">x2</a></td>
|
||||
<td>Непрерывное соединение</td>
|
||||
<td>Длинные опросы</td>
|
||||
<td>Непрерывное соединение</td>
|
||||
<td>Непрерывное соединение в обе стороны</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Поддержка</th>
|
||||
<td>Все браузеры, ограничения в IE9-<a class="link-ref" href="#x3">x3</a></td>
|
||||
<td>Все браузеры</td>
|
||||
<td>Все браузеры</td>
|
||||
<td>Кроме IE</td>
|
||||
<td>IE 10, FF11, Chrome 16, Safari 6, Opera 12.5<a class="link-ref" href="#w1">w1</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Пояснения:
|
||||
|
||||
<dl>
|
||||
<dt>`XMLHttpRequest`</dt>
|
||||
<dd>
|
||||
<ol>
|
||||
<li id="x1">В IE8-9 поддерживаются кросс-доменные GET/POST запросы с ограничениями через `XDomainRequest`.</li>
|
||||
<li id="x2">Можно говорить об ограниченной поддержке непрерывного соединения через `onprogress`, но это событие вызывается не чаще чем в `50ms` и не гарантирует получение полного пакета данных. Например, сервер может записать "Привет!", а событие вызовется один раз, когда браузер получил "При". Поэтому наладить обмен пакетами сообщений с его помощью затруднительно.
|
||||
</li>
|
||||
<li id="x3">Многие возможности современного стандарта включены в IE лишь с версии 10.</li>
|
||||
</ol>
|
||||
</dd>
|
||||
<dt>`IFRAME`</dt>
|
||||
<dd>
|
||||
<ol>
|
||||
<li id="i1">Во всех современных браузерах и IE8 кросс-доменность обеспечивает `postMessage`. В более старых браузерах возможны решения через `window.name` и хэш.</li>
|
||||
</ol>
|
||||
</dd>
|
||||
<dt>`WebSocket`</dt>
|
||||
<dd>
|
||||
<ol>
|
||||
<li id="w1">Имеется в виду поддержка окончательной редакции протокола [RFC 6455](http://tools.ietf.org/html/rfc6455), описанной в разделе [](/websockets). Более старые браузеры могут поддерживать черновики протокола. IE9- не поддерживает `WebSocket`.</li>
|
||||
</ol>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
Существует также нестандартный транспорт, не рассмотренный здесь:
|
||||
<ul>
|
||||
<li>XMLHttpRequest с флагом `multipart`, только для Firefox.
|
||||
|
||||
При указании свойства `xhr.multipart = true` и специального multipart-формата ответа сервера, Firefox инициирует `onload` при получении очередной части ответа. Ответ может состоять из любого количества частей, досылаемых по инициативе сервера. Мы не рассматривали его, так как Firefox поддерживает другие, более кросс-браузерные и стандартные транспорты.
|
||||
</li>
|
||||
</ul>
|
||||
|