diff --git a/1-js/10-es-modern/1-es-modern-usage/article.md b/1-js/10-es-modern/1-es-modern-usage/article.md
index 68cb6795..82c8896e 100644
--- a/1-js/10-es-modern/1-es-modern-usage/article.md
+++ b/1-js/10-es-modern/1-es-modern-usage/article.md
@@ -5,11 +5,11 @@
[/smart]
-[Стандарт ES-2015](http://www.ecma-international.org/publications/standards/Ecma-262.htm) был принят в июне 2015. Пока что большинство браузеров реализуют его частично, текущее состояние реализации различных возможностей можно посмотреть здесь: [](https://kangax.github.io/compat-table/es6/), поэтому в этом учебнике ему выделена отдельная секция.
+[Стандарт ES-2015](http://www.ecma-international.org/publications/standards/Ecma-262.htm) был принят в июне 2015. Пока что большинство браузеров реализуют его частично, текущее состояние реализации различных возможностей можно посмотреть здесь: [](https://kangax.github.io/compat-table/es6/).
-Когда стандарт будет поддерживаться почти целиком везде, то весь учебник будет обновлён в соответствии с ним.
+Когда стандарт будет более-менее поддерживаться во всех браузерах, то весь учебник будет обновлён в соответствии с ним. Пока же, как центральное место для "сбора" современных фич JavaScript, создан этот раздел.
-Пока же, чтобы писать код на ES-2015, есть следующие варианты.
+Чобы писать код на ES-2015 прямо сейчас, есть следующие варианты.
## Конкретный движок JS
@@ -62,11 +62,17 @@
# Примеры на этом сайте
-На этом сайте запускаемые примеры гарантированно работают в [последнем Chrome](https://www.google.com/chrome/browser/canary.html), браузерный Babel не используется, при желании вы можете запустить их в любом браузере вместе с Babel, как показано выше.
-
-Ещё раз заметим, что самая актуальная ситуация по поддержке современного стандарта браузерами отражена вот тут: [](https://kangax.github.io/compat-table/es6/).
-
+Запускаемые примеры с ES-2015 будут работать только если ваш браузер поддерживает соответствующую возможность стандарта.
+Рекомендуется [Chrome Canary](https://www.google.com/chrome/browser/canary.html), Edge или [Firefox Developer Edition](https://www.mozilla.org/en-US/firefox/channel/#developer).
+
+Впрочем, если пример в браузере не работает (обычно проявляется как ошибка синтаксиса) -- вы можете запустить его при помощи Babel, на странице [Babel: try it out](https://babeljs.io/repl/). Там же увидите и преобразованный код.
+
+На практике для кросс-браузерности всё равно используют Babel.
+
+Ещё раз заметим, что самая актуальная ситуация по поддержке современного стандарта браузерами и транспайлерами отражена на странице [](https://kangax.github.io/compat-table/es6/).
+
+Итак, поехали!
diff --git a/1-js/10-es-modern/2-let-const/article.md b/1-js/10-es-modern/2-let-const/article.md
index 7554fca1..2f889f40 100644
--- a/1-js/10-es-modern/2-let-const/article.md
+++ b/1-js/10-es-modern/2-let-const/article.md
@@ -61,7 +61,7 @@ alert(apples); // 5 (снаружи блока значение не измен
Заметим, что если объявление `apples` в строке `(*)` закомментировать, то в последнем `alert` будет ошибка: переменная неопределена. Это потому что переменная `let` всегда видна именно в том блоке, где объявлена и не более.
-
**Переменная `let` не видна до объявления.**
+**Переменная `let` видна только после объявления.**
Как мы помним, переменные `var` существуют и до объявления. Они равны `undefined`:
@@ -87,10 +87,50 @@ alert(a); // ошибка, нет такой переменной
let a = 5;
```
+
+Заметим также, что переменные `let` нельзя повторно объявлять. То есть, такой код выведет ошибку:
+
+```js
+//+ run
+'use strict';
+
+let x;
+let x; // ошибка: переменная x уже объявлена
+```
+
+Это -- хоть и выглядит ограничением по сравнению с `var`, но на самом деле проблем не создаёт, так как область видимости ограничена блоком.
+
+Например, два таких цикла совсем не конфликтуют:
+```js
+//+ run
+'use strict';
+
+for(let i = 0; i<10; i++) { /* … */ }
+for(let i = 0; i<10; i++) { /* … */ }
+
+alert( i ); // ошибка, переменная не определена
+```
+
+При объявлении внутри цикла переменная `i` будет видна только в блоке цикла. Она не видна снаружи, поэтому будет ошибка в последнем `alert`.
+
+
**При использовании в цикле, для каждой итерации создаётся своя переменная.**
-Объявление `let` позволяет легко решить классическую проблему с замыканиями, описанную в задаче [](/task/make-army).
+Переменная `var` -- одна на все итерации цикла (и видна после цикла):
+
+```js
+//+ run
+for(var i=0; i<10; i++) { /* … */ }
+
+alert(i); // 10
+```
+
+С переменной `let` -- всё по-другому. Добавляется ещё одна область видимости: блок цикла.
+
+Каждому блоку цикла соответствует своя, независимая, переменная `let`. Если внутри цикла объявляются функции, то в замыкании каждой будет та переменная, которая была при итерации.
+
+Это позволяет легко решить классическую проблему с замыканиями, описанную в задаче [](/task/make-army).
```js
//+ run
@@ -117,13 +157,13 @@ army[5](); // 5
Если бы объявление было `var i`, то была бы одна переменная `i` на всю функцию, и вызовы в последних строках выводили бы `10` (подробнее -- см. задачу [](/task/make-army)).
-Объявление `let i` создаёт для каждого повторения блока в цикле свою переменную.
+А выше объявление `let i` создаёт для каждого повторения блока в цикле свою переменную, которую функция и получает из замыкания в последних строках.
-# const
+## const
-По области видимости -- это то же самое, что `let`, но константа, нельзя менять:
+Объявление `const` задаёт константу, то есть переменную, которую нельзя менять:
```js
//+ run
@@ -133,5 +173,18 @@ const apple = 5;
apple = 10; // ошибка
```
+В остальном объявление `const` полностью аналогично `let`.
+
+## Итого
+Переменные `let`:
+
+
+- Видны только после объявления и только в текущем блоке.
+- Нельзя переобъявлять (в том же блоке).
+- В цикле каждое значение `let` принадлежит конкретной итерации цикла (и видно в замыканиях).
+
+
+Переменная `const` -- это константа, в остальном -- как `let`.
+
diff --git a/1-js/10-es-modern/3-es-function/article.md b/1-js/10-es-modern/3-es-function/article.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/1-js/10-es-modern/4-es-string/article.md b/1-js/10-es-modern/4-es-string/article.md
deleted file mode 100644
index c3543391..00000000
--- a/1-js/10-es-modern/4-es-string/article.md
+++ /dev/null
@@ -1,95 +0,0 @@
-
-# Строки и регэкспы
-
-Есть ряд улучшений и новых методов для строк и регулярных выражений.
-
-Начнём с, пожалуй, самого важного.
-
-## Строки-шаблоны
-
-Добавлен новый вид кавычек для строк:
-```js
-let str = `обратные кавычки`;
-```
-
-Основные отличия от `"…"` и `'…'`:
-
-
-- **В них разрешён перевод строки.**
-
-Например:
-```js
-//+ run
-alert(`моя
- многострочная
- строка`);
-```
-Заметим, что пробелы и, собственно, перевод строки также входят в строку, и будут выведены.
-
-- **Можно вставлять выражения при помощи `${…}`.**
-
-Например:
-```js
-//+ run
-'use strict';
-let apples = 2;
-let oranges = 3;
-
-alert(`${apples} + ${oranges} = ${apples + oranges}`); // 2 + 3 = 5
-```
-
-Как видно, можно вставлять как и значение переменной, так и более сложные выражения, вызовы функций и т.п. Это называют "интерполяцией".
-
-- **Можно использовать свою функцию шаблонизации для строк.**
-
-Перед первой обратной кавычкой может стоять имя функции, которая запустится с этой строкой:
-```js
-let str = f`...`;
-```
-
-Эти два кода делают одно и то же:
-
-```js
-//+ run
-alert( eval`1 + 2 - 3` );
-alert( eval("1 + 2 - 3") );
-```
-
-Пример использования:
-
-
-...Однако, при первой
-
-
-
-
-
-
-
-
-
-
-
-
-Основные улучшения для строк -- улучшенная поддержка юникода. Кроме того, добавлены некоторые новые методы.
-
-## Улучшена поддержка юникода
-
-[smart header="А ваши сайты читают китайцы?"]
-Это улучшение имеет значение только если мы поддерживаем китайский и другие языки, которые выходят за границы стандартного 2-байтового диапазона.
-[/smart]
-
-Внутренняя кодировка строк в JavaScript -- это UTF-16, то есть под каждый символ отводится ровно два байта.
-
-Под всевозможные символы всех языков мира двух байт не хватает.
-
-Поэтому, к примеру, китайские иероглифы представляются двумя юникодными символами, например:
-
-```js
-//+ run
-alert( "我".length ); // 2
-```
-
-Такое представление, когда одному символу языка соответствует два юникодных символа, называют "суррогатные пары".
-
-Ю
\ No newline at end of file
diff --git a/1-js/10-es-modern/5-promise/1-promise-settimeout/solution.md b/1-js/10-es-modern/5-promise/1-promise-settimeout/solution.md
deleted file mode 100644
index 791fe90e..00000000
--- a/1-js/10-es-modern/5-promise/1-promise-settimeout/solution.md
+++ /dev/null
@@ -1,8 +0,0 @@
-
-```js
-function delay(ms) {
- return new Promise((resolve, reject) => {
- setTimeout(resolve, ms);
- });
-}
-```
\ No newline at end of file
diff --git a/1-js/10-es-modern/5-promise/1-promise-settimeout/task.md b/1-js/10-es-modern/5-promise/1-promise-settimeout/task.md
deleted file mode 100644
index 0dd9edc4..00000000
--- a/1-js/10-es-modern/5-promise/1-promise-settimeout/task.md
+++ /dev/null
@@ -1,27 +0,0 @@
-
-# Промисифицировать setTimeout
-
-Напишите функцию `delay(ms)`, которая возвращает промис, переходящий в состояние `"resolved"` через `ms` миллисекунд.
-
-Пример использования:
-```js
-delay(1000)
- .then(() => alert("Hello!"))
-````
-
-Такая полезна для использования в других промис-цепочках.
-
-Вот такой вызов:
-```js
-return new Promise((resolve, reject) => {
- setTimeout(() => {
- doSomeThing();
- resolve();
- }, ms)
-});
-```
-
-Станет возможным переписать так:
-```js
-return delay(ms).then(doSomething);
-```
diff --git a/1-js/10-es-modern/5-promise/anon.png b/1-js/10-es-modern/5-promise/anon.png
deleted file mode 100644
index a1675d2f..00000000
Binary files a/1-js/10-es-modern/5-promise/anon.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/article.md b/1-js/10-es-modern/5-promise/article.md
deleted file mode 100644
index f9b75db9..00000000
--- a/1-js/10-es-modern/5-promise/article.md
+++ /dev/null
@@ -1,789 +0,0 @@
-# Promise
-
-Promise (обычно их так и называют "промисы") -- предоставляют удобный способ организации асинхронного кода.
-
-В современном JavaScript промисы часто используются в том числе и неявно, при помощи генераторов, но об этом чуть позже.
-
-## Что такое Promise?
-
-Promise -- это специальный объект, который содержит своё состояние. Вначале `pending` ("ожидание"), затем -- одно из: `fulfilled` ("выполнено успешно") или `rejected` ("выполнено с ошибкой").
-
-
-
-На `promise` можно навешивать коллбэки двух типов:
-
-
-- `onFulfilled` -- срабатывают, когда `promise` в состоянии "выполнен успешно".
-- `onRejected` -- срабатывают, когда `promise` в состоянии "выполнен с ошибкой".
-
-
-Способ использования, в общих чертах, такой:
-
-- Код, которому надо сделать что-то асинхронно, создаёт объект `promise` и возвращает его.
-- Внешний код, получив `promise`, навешивает на него обработчики.
-- По завершении процесса асинхронный код переводит `promise` в состояние `fulfilled` (с результатом) или `rejected` (с ошибкой). При этом автоматически вызываются соответствующие обработчики во внешнем коде.
-
-
-Синтаксис создания `Promise`:
-
-```js
-var promise = new Promise(function(resolve, reject) {
- // Эта функция будет вызвана автоматически
-
- // В ней можно делать любые асинхронные операции,
- // А когда они завершаться — нужно вызвать одно из:
- // resolve(результат) при успешном выполнении
- // reject(ошибка) при ошибке
-})
-```
-
-Универсальный метод для навешивания обработчиков:
-
-```
-promise.then(onFulfilled, onRejected)
-```
-
-
-- `onFulfilled` -- функция, которая будет вызвана с результатом при `resolve`.
-- `onRejected` -- функция, которая будет вызвана с ошибкой при `reject`.
-
-
-С его помощью можно назначить как оба обработчика сразу, так и только один:
-
-```js
-// только на успешное выполнение
-promise.then(onFulfilled)
-// только на ошибку
-promise.then(null, onRejected)
-```
-
-[smart header=".catch"]
-Для того, чтобы поставить обработчик только на ошибку, вместо `.then(null, onRejected)` можно написать `.catch(onRejected)` -- это то же самое.
-[/smart]
-
-[smart header="Синхронный `throw` -- то же самое, что `reject`"]
-Если в функции промиса происходит синхронный `throw` (или иная ошибка), то вызывается `reject`:
-```js
-//+ run
-var p = new Promise((resolve, reject) => {
- // то же что reject(new Error("o_O"))
- throw new Error("o_O");
-})
-
-p.catch(alert); // Error: o_O
-```
-[/smart]
-
-Посмотрим, как это выглядит вместе, на простом примере.
-
-
-## Пример с setTimeout
-
-Возьмём `setTimeout` в качестве асинхронной операции, которая должна через некоторое время успешно завершиться с результатом "result":
-
-```js
-//+ run
-// Создаётся объект promise
-var promise = new Promise((resolve, reject) => {
-
- setTimeout(() => {
- // переведёт промис в состояние fulfilled с результатом "result"
- resolve("result");
- }, 1000);
-
-});
-
-// promise.then навешивает обработчики на успешный результат или ошибку
-promise
- .then(
- result => {
- // первая функция-обработчик - запустится при вызове resolve
- alert("Fulfilled: " + result); // result - аргумент resolve
- },
- error => {
- // вторая функция - запустится при вызове reject
- alert("Rejected: " + error); // error - аргумент reject
- }
- );
-
-```
-
-В результате запуска кода выше -- через 1 секунду выведется "Fulfilled: result".
-
-А если бы вместо `resolve("result")` был вызов `reject("error")`, то вывелось бы "Rejected: error". Впрочем, как правило, если при выполнении возникла проблема, то `reject` вызывают не со строкой, а с объектом ошибки типа `new Error`:
-
-```js
-//+ run
-// Этот promise завершится с ошибкой через 1 секунду
-var promise = new Promise((resolve, reject) => {
-
- setTimeout(() => {
-*!*
- reject(new Error("время вышло!"));
-*/!*
- }, 1000);
-
-});
-
-promise
- .then(
- result => alert("Fulfilled: " + result),
-*!*
- error => alert("Rejected: " + error.message) // Rejected: время вышло!
-*/!*
- );
-
-```
-
-Конечно, вместо `setTimeout` мог бы быть и запрос к серверу и ожидание ввода пользователя, или другой асинхронный процесс.
-
-[smart header="Только один аргумент"]
-Функции `resolve/reject` принимают ровно один аргумент -- результат/ошибку.
-
-Именно он передаётся обработчикам в `.then`, как можно видеть в примерах выше.
-[/smart]
-
-## Promise после reject/resolve -- неизменны
-
-Заметим, что после вызова `resolve/reject` промис уже не может "передумать".
-
-Когда промис переходит в состояние "выполнен" -- с результатом (resolve) или ошибкой (reject) -- это навсегда.
-
-Например:
-
-```js
-//+ run
-var promise = new Promise((resolve, reject) => {
-
-*!*
- // через 1 секунду готов результат: result
-*/!*
- setTimeout(() => resolve("result"), 1000);
-
-*!*
- // через 2 секунды — reject с ошибкой, он будет проигнорирован
-*/!*
- setTimeout(() => reject(new Error("ignored")), 2000);
-
-});
-
-promise
- .then(
- result => alert("Fulfilled: " + result), // сработает
- error => alert("Rejected: " + error) // не сработает
- );
-
-```
-
-В результате вызова этого кода сработает только первый обработчик `then`, так как после вызова `resolve` промис уже получил состояние (с результатом), и в дальнейшем его уже ничто не изменит.
-
-Последующие вызовы resolve/reject будут просто проигнороированы.
-
-А так -- наоборот, ошибка будет раньше:
-
-
-```js
-//+ run
-var promise = new Promise((resolve, reject) => {
-
- // reject вызван раньше, resolve будет проигнорирован
- setTimeout(() => reject(new Error("error")), 1000);
-
- setTimeout(() => resolve("ignored"), 2000);
-
-});
-
-promise
- .then(
- result => alert("Fulfilled: " + result), // не сработает
- error => alert("Rejected: " + error) // сработает
- );
-
-```
-
-
-## Промисификация
-
-*Промисификация* -- это когда берут асинхронный функционал и делают для него обёртку, возвращающую промис.
-
-После промисификации использование функционала зачастую становится гораздо удобнее.
-
-В качестве примера сделаем такую обёртку для запросов при помощи XMLHttpRequest.
-
-Функция `httpGet(url)` будет возвращать промис, который при успешной загрузки данных с `url` будет переходить в `fulfilled` с этими данными, а при ошибке -- в `rejected` с информацией об ошибке:
-
-```js
-//+ autorun
-function httpGet(url) {
-
- return new Promise(function(resolve, reject) {
-
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, true);
-
- xhr.onload = function() {
- if (this.status == 200) {
-*!*
- resolve(this.response);
-*/!*
- } else {
-*!*
- var error = new Error(this.statusText);
- error.code = this.status;
- reject(error);
-*/!*
- }
- };
-
- xhr.onerror = function() {
-*!*
- reject(new Error("Network Error"));
-*/!*
- };
-
- xhr.send();
- });
-
-}
-```
-
-Как видно, внутри функции объект `XMLHttpRequest` создаётся и отсылается как обычно, при `onload/onerror` вызываются, соответственно, `resolve` (при статусе 200) или `reject`.
-
-Использование:
-
-```js
-//+ run
-httpGet("/article/promise/user.json")
- .then(
- response => alert(`Fulfilled: ${response}`),
- error => alert(`Rejected: ${error}`)
- );
-```
-
-
-[smart header="Метод `fetch`"]
-Заметим, что ряд современных браузеров уже поддерживает [fetch](https://fetch.spec.whatwg.org) -- новый встроенный метод для AJAX-запросов, призванный заменить XMLHttpRequest. Он, конечно, гораздо мощнее, чем `httpGet`. И -- да, этот метод использует промисы. Полифилл для него доступен на [](https://github.com/github/fetch).
-[/smart]
-
-
-## Цепочки промисов
-
-"Чейнинг" (chaining), то есть возможность строить асинхронные цепочки из промисов -- пожалуй, основная причина, из-за которой существуют и активно используются промисы.
-
-Например, мы хотим по очереди:
-
-- Загрузить данные посетителя с сервера (асинхронно).
-- Затем отправить запрос о нём на github (асинхронно).
-- Когда это будет готово, вывести его github-аватар на экран (асинхронно).
-- ...И сделать код расширяемым, чтобы цепочку можно было легко продолжить.
-
-
-Вот код для этого, использующий функцию `httpGet`, описанную выше:
-
-```js
-//+ run
-'use strict';
-
-// сделать запрос
-httpGet('/article/promise/user.json')
-*!*
- // 1. Получить данные о пользователе в JSON и передать дальше
-*/!*
- .then(response => {
- console.log(response);
- let user = JSON.parse(response);
-*!*
- return user;
-*/!*
- })
-*!*
- // 2. Получить информацию с github
-*/!*
- .then(user => {
- console.log(user);
-*!*
- return httpGet(`https://api.github.com/users/${user.name}`);
-*/!*
- })
-*!*
- // 3. Вывести аватар на 3 секунды (можно с анимацией)
-*/!*
- .then(githubUser => {
- console.log(githubUser);
- githubUser = JSON.parse(githubUser);
-
- let img = new Image();
- img.src = githubUser.avatar_url;
- img.className = "promise-avatar-example";
- document.body.appendChild(img);
-
-*!*
- setTimeout(() => img.remove(), 3000); // (*)
-*/!*
- });
-```
-
-Самое главное в этом коде -- последовательность вызовов:
-
-```js
-httpGet(...)
- .then(...)
- .then(...)
- .then(...)
-```
-
-При чейнинге, то есть последовательных вызовах `.then...then..then`, в каждый следующий `then` переходит результат от предыдущего.
-
-**Причём, если очередной `then` вернул промис, то далее по цепочке будет передан не сам этот промис, а его результат.**
-
-В коде выше:
-
-
-- В первом `then` возвращается объект `user`, он переходит в следующий `then`.
-- Во втором `then` возвращается промис (результат `loadUser`). Когда он будет завершён (может пройти какое-то время), то будет вызван следующий `then`.
-- Третий `then` ничего не возвращает.
-
-
-Схематично его работу можно изобразить так:
-
-
-
-Значком "песочные часы" помечены периоды ожидания. Если `then` возвращает промис, то до его выполнения может пройти некоторое время, оставшаяся часть цепочки ждёт.
-
-Обратим внимание, что последний `then` в нашем примере ничего не возвращает. Если мы хотим, чтобы после `setTimeout` `(*)` асинхронная цепочка могла быть продолжена, то последний `then` тоже должен вернуть промис.
-
-Это стандартный приём. Если внутри `then` стартует новый асинхронный процесс, то для того, чтобы оставшаяся часть цепочки выполнилась после его окончания, мы должны вернуть промис, который перейдёт в состояние "выполнен" после `setTimeout`.
-
-
-
-Строку `(*)` для этого нужно переписать так:
-```js
-.then(githubUser => {
- ...
-
- // вместо setTimeout(() => img.remove(), 3000); (*)
-
- return new Promise((resolve, reject) => {
- setTimeout(() => {
- img.remove();
- // после таймаута — вызов resolve,
- // можно без результата, чтобы управление перешло в следующий then
- // (или можно передать данные пользователя дальше по цепочке)
- resolve();
- }, 3000);
- });
-})
-```
-
-Теперь, если к цепочке добавить ещё `then`, то он будет вызван после окончания `setTimeout`.
-
-## Перехват ошибок
-
-Выше мы рассмотрели "идеальный случай" выполнения, когда ошибок нет.
-
-А что, если github не отвечает? Или JSON.parse бросил синтаксическую ошибку при обработке данных?
-
-Да мало ли, где ошибка...
-
-Правило здесь очень простое.
-
-**При возникновении ошибки -- она отправляется в ближайший обработчик `onRejected`.**
-
-Такой обработчик нужно поставить через второй аргумент `.then(..., onRejected)` или, что то же самое, через `.catch(onRejected)`.
-
-Чтобы поймать всевозможные ошибки, которые возникнут при загрузке и обработке данных, добавим `catch` в конец нашей цепочки:
-
-```js
-//+ run
-'use strict';
-
-*!*
-// в httpGet обратимся к несуществующей странице
-*/!*
-httpGet('/page-not-exists')
- .then(response => JSON.parse(response))
- .then(user => httpGet(`https://api.github.com/users/${user.name}`))
- .then(githubUser => {
- githubUser = JSON.parse(githubUser);
-
- let img = new Image();
- img.src = githubUser.avatar_url;
- img.className = "promise-avatar-example";
- document.body.appendChild(img);
-
- return new Promise((resolve, reject) => {
- setTimeout(() => {
- img.remove();
- resolve();
- }, 3000);
- });
- })
-*!*
- .catch(error => {
- alert(error); // Error: Not Found
- });
-*/!*
-```
-
-В примере выше ошибка возникает в первом же `httpGet`, но `catch` с тем же успехом поймал бы ошибку во втором `httpGet` или в `JSON.parse`.
-
-Принцип очень похож на обычный `try..catch`: мы делаем асинхронную цепочку из `.then`, а затем, когда нужно перехватить ошибки, вызываем `.catch(onRejected)`.
-
-
-[smart header="А что после `catch`?"]
-Обработчик `.catch(onRejected)` получает ошибку и должен обработать её.
-
-Здесь два варианта развития событий:
-
-- Если ошибка не критичная, то обработчик возвращает значение через `return`, и управление переходит в ближайший `.then(onFulfilled)`.
-- Если продолжить выполнение с такой ошибкой нельзя, то он делает `throw`, и тогда ошибка переходит в ближайший `.catch(onRejected)`.
-
-
-
-Это также похоже на обычный `try..catch` -- в блоке `catch` ошибка либо обрабатывается, и тогда выполнение кода продолжается как обычно, либо он делает `throw`. Существенное отличие -- в том, что промисы асинхронные, поэтому при отсутствии внешнего `.catch` ошибка не "вываливается" в консоль и не "убивает" скрипт.
-
-Ведь возможно, что новый обработчик `.catch` будет добавлен в цепочку позже.
-[/smart]
-
-## Промисы в деталях
-
-Самым основным источником информации по промисам является, разумеется, [стандарт](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise-objects).
-
-Чтобы наше понимание промисов было полным, и мы могли с лёгкостью разрешать сложные ситуации, посмотрим внимательнее, что такое промис и как он работает, но уже не в общих словах, а детально, в соответствии со стандартом EcmaScript.
-
-Согласно стандарту, у объекта `new Promise(executor)` при создании есть четыре внутренних свойства:
-
-
-- `PromiseState` -- состояние, вначале "pending".
-- `PromiseResult` -- результат, при создании значения нет.
-- `PromiseFulfillReactions` -- список функций-обработчиков успешного выполнения.
-- `PromiseRejectReactions` -- список функций-обработчиков ошибки.
-
-
-
-
-Когда функция-executor вызывает reject или resolve, то `PromiseState` становится `"resolved"` или `"rejected"`, а все функции-обработчики из соответствующего списка перемещаются в специальную системную очередь `"PromiseJobs"`.
-
-Эта очередь автоматически выполняется, когда интерпретатору "нечего делать". Иначе говоря, все функции выполнятся асинхронно, одна за другой, по завершении текущего кода, примерно как `setTimeout(..,0)`.
-
-Исключение из этого правила -- если `resolve` возвращает другой Promise. Тогда дальнейшее выполнение ожидает его результата (в очередь помещается специальная задача), и функции-обработчики выполняются уже с ним.
-
-Добавляет обработчики в списки один метод: `.then(onResolved, onRejected)`. Метод `.catch(onRejected)` -- всего лишь сокращённая запись `.then(null, onRejected)`.
-
-Он делает следующее:
-
-- Если `PromiseState == "pending"`, то есть промис ещё не выполнен, то обработчики добавляются в соответствующие списки.
-- Иначе обработчики сразу помещаются в очередь на выполнение.
-
-
-Здесь важно, что обработчики можно добавлять в любой момент. Можно до выполнения промиса (они подождут), а можно -- после (выполнятся в ближайшее время, через асинхронную очередь).
-
-Например:
-
-```js
-//+ run
-// Промис выполнится сразу же
-var promise = new Promise((resolve, reject) => resolve(1));
-
-// PromiseState = "resolved"
-// PromiseResult = 1
-
-// Добавили обработчик к выполненному промису
-promise.then(alert); // ...он сработает тут же
-```
-
-Разумеется, можно добавлять и много обработчиков на один и тот же промис:
-
-
-```js
-//+ run
-// Промис выполнится сразу же
-var promise = new Promise((resolve, reject) => resolve(1));
-
-promise.then( function f1(result) {
-*!*
- alert(result); // 1
-*/!*
- return 'f1';
-})
-
-promise.then( function f2(result) {
-*!*
- alert(result); // 1
-*/!*
- return 'f2';
-})
-```
-
-Вид объекта `promise` после этого:
-
-
-
-На этой иллюстрации можно увидеть, что `.then` если один из обработчиков не указан, добавляет его "от себя", следующим образом:
-
-- Для успешного выполнения -- функция `Identity`, которая выглядит как `arg => return arg`, то есть возвращает аргумент без изменений.
-- Для ошибки -- функция `Thrower`, которая выглядит как `arg => throw arg`, то есть генерирует ошибку.
-
-
-Это, по сути дела, формальность, но без неё некоторые особенности поведения промисов могут "не сойтись" в общую логику, поэтому мы упоминаем о ней здесь.
-
-Обратим внимание, в этом примере намеренно *не используется чейнинг*. То есть, обработчики добавляются именно на один и тот же промис.
-
-Поэтому оба `alert` выдадут одно значение `1`. Алгоритм такой -- все функции из списка обработчиков вызываются с результатом промиса, одна за другой. Никакой передачи результатов между обработчиками одного промиса нет, а сам результат промиса (`PromiseResult`) после установки не меняется.
-
-**Для того, чтобы результат обработчика передать следующей функции, `.then` создаёт новый промис и возвращает его.**
-
-В примере выше создаётся два таких промиса, каждый из которых даёт свою ветку выполнения:
-
-
-
-Изначально эти новые промисы -- пустые. Когда в будущем выполнятся обработчики `f1, f2`, то их результат будет передан в новые промисы по стандартному принципу:
-
-
-- Если вернётся обычное значение (не промис), новый промис перейдёт в `"resolved"` с ним.
-- Если был `throw`, то новый промис перейдёт в состояние `"rejected"` с ошибкой.
-- Если вернётся промис, то используем его результат (он может быть как `resolved`, так и `rejected`).
-
-
-
-
-Чтобы лучше понять происходящее, посмотрим на цепочку, которая получается в процессе написания кода для показа github-аватара.
-
-Первый промис и обработка его результата:
-
-```js
-httpGet('/article/promise/user.json')
- .then(JSON.parse)
-```
-
-
-
-
-Если промис завершился через `resolve`, то результат -- в `JSON.parse`, если `reject` -- то в Thrower.
-
-Как было сказано выше, `Thrower` -- это стандартная внутренняя функция, которая автоматически используется, если второй обработчик не указан. Можно сказать, что второй обработчик выглядит так:
-
-```js
-*!*
-function thrower(err) {
- throw err;
-}
-*/!*
-
-httpGet('/article/promise/user.json')
- .then(JSON.parse, thrower)
-```
-
-Заметим, что когда обработчик в промисах делает `throw`, то ошибка не "валит" скрипт и не выводится в консоли. Она просто будет передана в ближайший следующий обработчик `onRejected`.
-
-Добавим в код ещё строку:
-
-```js
-httpGet('/article/promise/user.json')
- .then(JSON.parse)
-*!*
- .then(user => httpGet(`https://api.github.com/users/${user.name}`))
-*/!*
-```
-
-Цепочка "выросла вниз":
-
-
-
-Функция `JSON.parse` либо возвращает объект с данными, либо генерирует ошибку (что расценивается как `reject`).
-
-Если всё хорошо, то `then(user => httpGet(…))` вернёт новый промис, на который стоят уже два обработчика:
-
-
-```js
-httpGet('/article/promise/user.json')
- .then(JSON.parse)
- .then(user => httpGet(`https://api.github.com/users/${user.name}`))
- .then(
-*!*
- JSON.parse,
- function avatarError(error) {
- if (error.code == 404) {
- return {name: "NoGithub", avatar_url: '/article/promise/anon.png'};
- } else {
- throw error;
- }
- }
-*/!*
- })
-```
-
-
-
-Наконец-то хоть какая-то обработка ошибок!
-
-Обработчик `avatarError` перехватит ошибки, которые были ранее. Функция `httpGet` при генерации ошибки записывает её HTTP-код в свойство `error.code`, так что мы легко можем понять -- что это:
-
-
-- Если страница на Github не найдена -- можно продолжить выполнение, используя "аватар по умолчанию"
-- Иначе -- пробрасываем ошибку дальше.
-
-
-Итого, после добавления оставшейся части цепочки, картина получается следующей:
-
-```js
-//+ run
-'use strict';
-
-httpGet('/article/promise/userNoGithub.json')
- .then(JSON.parse)
- .then(user => loadUrl(`https://api.github.com/users/${user.name}`))
- .then(
- JSON.parse,
- function githubError(error) {
- if (error.code == 404) {
- return {name: "NoGithub", avatar_url: '/article/promise/anon.png'};
- } else {
- throw error;
- }
- }
- })
- .then(function showAvatar(githubUser) {
- let img = new Image();
- img.src = githubUser.avatar_url;
- img.className = "promise-avatar-example";
- document.body.appendChild(img);
- setTimeout(() => img.remove(), 3000);
- })
- .catch(function genericError(error) {
- alert(error); // Error: Not Found
- });
-```
-
-
-
-В конце срабатывает общий обработчик `genericError`, который перехватывает любые ошибки. В данном случае ошибки, которые в него попадут, уже носят критический характер, что-то серьёзно не так. Чтобы посетитель не удивился отсутствию информации, мы показываем ему сообщение об этом.
-
-Можно и как-то иначе вывести уведомление о проблеме, главное -- не забыть обработать ошибки в конце. Если последнего `catch` не будет, а цепочка завершится с ошибкой, то посетитель об этом не узнает.
-
-В консоли тоже ничего не будет, так как ошибка остаётся "внутри" промиса, ожидая добавления следующего обработчика `onRejected`, которому будет передана.
-
-
-## Вспомогательные методы
-
-В классе `Promise` есть следующие статические методы.
-
-### Promise.all(iterable)
-
-Вызов `Promise.all(iterable)` получает массив (или другой итерируемый объект) промисов и возвращает промис, который завершается, когда все они завершаться, с их результатом.
-
-Например:
-
-```js
-//+ run
-
-Promise.all([
- httpGet('/article/promise/user.json'),
- httpGet('/article/promise/guest.json')
-]).then(results => {
- results = results.map(JSON.parse);
- alert( results[0].name + ', ' + results[1].name ); // iliakan, guest
-});
-```
-
-Заметим, что если какой-то из промисов завершился с ошибкой, то результатом `Promise.all` будет эта ошибка. При этом остальные промисы игнорируются.
-
-Например:
-
-
-```js
-//+ run
-
-Promise.all([
- httpGet('/article/promise/user.json'),
- httpGet('/article/promise/guest.json'),
- httpGet('/article/promise/no-such-page.json') // (нет такой страницы)
-]).then(
- result => alert("не сработает"),
- error => alert("Ошибка: " + error.message) // Ошибка: Not Found
-)
-```
-
-### Promise.race(iterable)
-
-Как и `Promise.all` получает итерируемый объект с промисами и возвращает новый промис.
-
-Но, в отличие от `Promise.all`, результатом будет только первый успешно выполнившийся промис из списка. Остальные игнорируются.
-
-Например:
-
-```js
-//+ run
-
-Promise.race([
- httpGet('/article/promise/user.json'),
- httpGet('/article/promise/guest.json')
-]).then(firstResult => {
- firstResult = JSON.parse(firstResult);
- alert( firstResult.name ); // iliakan или guest, смотря что загрузится раньше
-});
-```
-
-### Promise.resolve(value)
-
-Вызов `Promise.resolve(value)` создаёт успешно выполнившийся промис с результатом `value`.
-
-Он аналогичен конструкции:
-
-```js
-new Promise((resolve) => resolve(value))
-```
-
-`Promise.resolve`, когда хотят построить асинхронную цепочку, и начальный результат уже есть.
-
-
-Например:
-
-```js
-//+ run
-Promise.resolve(window.location) // начать с этого значения
- .then(httpGet) // вызвать для него httpGet
- .then(alert) // и вывести результат
-```
-
-### Promise.reject(error)
-
-Аналогично `Promise.resolve(value)` создаёт уже выполнившийся промис, но не с успешным результатом, а с ошибкой `error`.
-
-Например:
-
-```js
-//+ run
-Promise.reject(new Error("..."))
- .catch(alert) // Error: ...
-```
-
-Метод `Promise.reject` используется очень редко, гораздо реже чем `resolve`, потому что ошибка возникает обычно не в начале цепочки, а в процессе её выполнения.
-
-### Итого
-
-
-- Промис -- это специальный объект, который хранит своё состояние, текущий результат (если есть) и коллбэки.
-- При создании `new Promise((resolve, reject) => ...)` автоматически запускается функция-аргумент, которая должна вызвать `resolve(result)` при успешном выполнении и `reject(error)` -- при ошибке.
-- Аргумент `resolve/reject` (только первый, остальные игнорируются) передаётся обработчикам на этом промисе.
-- Обработчики назначаются вызовом `.then/catch`.
-- Для передачи результата от одного обработчика к другому используется чейнинг.
-
-
-В современной JavaScript-разработки промисы в явном виде используются, как ни странно, довольно редко.
-
-Тем не менее, понимать промисы нужно обязательно, так как бывают ситуации, когда без них сложно.
-
-Промисы служат основой для более продвинутых способов написания асинхронного кода, использующих генераторы. Мы рассмотрим их далее в этом разделе.
-
-
-[head]
-
-[/head]
diff --git a/1-js/10-es-modern/5-promise/guest.json b/1-js/10-es-modern/5-promise/guest.json
deleted file mode 100644
index c32ac845..00000000
--- a/1-js/10-es-modern/5-promise/guest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "guest",
- "isAdmin": false
-}
diff --git a/1-js/10-es-modern/5-promise/promiseEcma.png b/1-js/10-es-modern/5-promise/promiseEcma.png
deleted file mode 100644
index f27e0e0b..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseEcma.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseEcma@2x.png b/1-js/10-es-modern/5-promise/promiseEcma@2x.png
deleted file mode 100644
index 6fa3bd76..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseEcma@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseHandlerVariants.png b/1-js/10-es-modern/5-promise/promiseHandlerVariants.png
deleted file mode 100644
index c2c4a734..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseHandlerVariants.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseHandlerVariants@2x.png b/1-js/10-es-modern/5-promise/promiseHandlerVariants@2x.png
deleted file mode 100644
index 5f1f4da6..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseHandlerVariants@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseInit.png b/1-js/10-es-modern/5-promise/promiseInit.png
deleted file mode 100644
index dc2e324f..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseInit.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseInit@2x.png b/1-js/10-es-modern/5-promise/promiseInit@2x.png
deleted file mode 100644
index 957f91f7..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseInit@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-1.png b/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-1.png
deleted file mode 100644
index 3f84d6fd..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-1.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-1@2x.png b/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-1@2x.png
deleted file mode 100644
index 6602a3fb..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-1@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-2.png b/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-2.png
deleted file mode 100644
index 9d2c01cb..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-2.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-2@2x.png b/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-2@2x.png
deleted file mode 100644
index c8ae285e..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-2@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-3.png b/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-3.png
deleted file mode 100644
index 27a61c64..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-3.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-3@2x.png b/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-3@2x.png
deleted file mode 100644
index 3954f250..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-3@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-4.png b/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-4.png
deleted file mode 100644
index a59a1a44..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-4.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-4@2x.png b/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-4@2x.png
deleted file mode 100644
index 6c196a3c..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain-4@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain.png b/1-js/10-es-modern/5-promise/promiseLoadAvatarChain.png
deleted file mode 100644
index ea162ad1..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain@2x.png b/1-js/10-es-modern/5-promise/promiseLoadAvatarChain@2x.png
deleted file mode 100644
index 1e5f23bb..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseLoadAvatarChain@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseTwo.png b/1-js/10-es-modern/5-promise/promiseTwo.png
deleted file mode 100644
index 9ef03e37..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseTwo.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseTwo@2x.png b/1-js/10-es-modern/5-promise/promiseTwo@2x.png
deleted file mode 100644
index 1e9ea11d..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseTwo@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseTwoThen.png b/1-js/10-es-modern/5-promise/promiseTwoThen.png
deleted file mode 100644
index 25922cc0..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseTwoThen.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseTwoThen@2x.png b/1-js/10-es-modern/5-promise/promiseTwoThen@2x.png
deleted file mode 100644
index b2130043..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseTwoThen@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseUserFlow.png b/1-js/10-es-modern/5-promise/promiseUserFlow.png
deleted file mode 100644
index 19b2a7cf..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseUserFlow.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/promiseUserFlow@2x.png b/1-js/10-es-modern/5-promise/promiseUserFlow@2x.png
deleted file mode 100644
index fff1d353..00000000
Binary files a/1-js/10-es-modern/5-promise/promiseUserFlow@2x.png and /dev/null differ
diff --git a/1-js/10-es-modern/5-promise/user-no-guthub.json b/1-js/10-es-modern/5-promise/user-no-guthub.json
deleted file mode 100644
index 9e23f32b..00000000
--- a/1-js/10-es-modern/5-promise/user-no-guthub.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "an-unknown-person-32662",
- "isAdmin": false
-}
diff --git a/1-js/10-es-modern/5-promise/user.json b/1-js/10-es-modern/5-promise/user.json
deleted file mode 100644
index 32f89971..00000000
--- a/1-js/10-es-modern/5-promise/user.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "iliakan",
- "isAdmin": true
-}
diff --git a/1-js/10-es-modern/5-promise/userNoGithub.json b/1-js/10-es-modern/5-promise/userNoGithub.json
deleted file mode 100644
index 9e23f32b..00000000
--- a/1-js/10-es-modern/5-promise/userNoGithub.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "an-unknown-person-32662",
- "isAdmin": false
-}