И снова здравствуйте. Сегодня, я представляю вашему вниманию предпоследнюю часть перевода статьи о промисах. В ней речь пойдет не только о них, а и о некоторых других новшествах ES6, в частности о генераторах. И о том, как эти два нововведения работают вместе. Это скорее обзор, чем исчерпывающее руководство, как было в случаи с промисами, но тем не менее, думаю многим это будет интересно.

В следующей статье будет представлено описание API промисов. Ее будет удобно использовать как справочную информацию.

Ну а пока, давайте посмотрим, чем нас могут порадовать генераторы.

Дополнение: Промисы и Генераторы



Следующий раздел касается целой кучи новых возможностей ES6, при этом он не является обязательным для применения промисов в современном JavaScript. Относитесь к нему, как к трейлеру, к новому фильму, готовящемуся к выпуску.
ES6 так же предоставляет возможность использования генераторов, которые позволяют завершить выполнение функции в некотором месте, как "return", но далее продолжить с того же места и того же состояния. Например:

function *addGenerator() {
var i = 0;
while (true) {
i += yield i;
}
}
Обратите внимание на звездочку перед началом имени функции, это обозначает, что она — генератор . Ключевое слово yield определяет точку выхода/возобновления. Мы можем использовать это следующим образом:

var adder = addGenerator();
adder.next().value; // 0
adder.next(5).value; // 5
adder.next(5).value; // 10
adder.next(5).value; // 15
adder.next(50).value; // 65


Но что это дает для промисов? Вы можете использовать выход/возобновление для написания асинхронного кода, который выглядит (и столь же легко читаем), как синхронный код. Не беспокойтесь слишком, о понимании каждой строчки приведенного ниже кода, но все же обратите на него внимание, поскольку он описывает вспомогательную функцию, позволяющую применять 'yield' для ожидания завершения промиса:

function spawn(generatorFunc) {
function continuer(verb, arg) {
var result;
try {
result = generator[verb](arg);
} catch (err) {
return Promise.reject(err);
}
if (result.done) {
return result.value;
} else {
return Promise.cast(result.value).then(onFulfilled, onRejected);
}
}
var generator = generatorFunc();
var onFulfilled = continuer.bind(continuer, "next");
var onRejected = continuer.bind(continuer, "throw");
return onFulfilled();
}


…которую я практически дословно упер из Q, но адаптировал к JavaScript-промисам. С этим мы можем взять лучший из наших алгоритмов для скачивания разделов, добавить кое-каких новых приятностей из ES6, и превратить в:

spawn(function *() {
try {
// 'yield' фактически выполняет функцию асинхронного ожидания,
// возвращая результат промиса
let story = yield getJSON('story.json');
addHtmlToPage(story.heading);

// Установим соответствие между массивом ссылок на разделы
// и массивом промисов json'ов разделов.
// Таким образом мы удостоверимся, что все они будут выполнятся параллельно.
let chapterPromises = story.chapterUrls.map(getJSON);

for (let chapterPromise of chapterPromises) {
// Ожидаем готовности каждого из разделов, затем добавляем его на страницу
let chapter = yield chapterPromise;
addHtmlToPage(chapter.html);
}

addTextToPage("Все готово");
}
catch (err) {
// try/catch необходим, поскольку отклоненные промисы вызывают ошибку, которая
// обрабатывается здесь
addTextToPage("Черт, сломалось: " + err.message);
}
document.querySelector('.spinner').style.display = 'none';
});


Этот код, работает так же как и раньше, но его куда проще читать. На данный момент, он работает в Chrome и Opera (см. пример), но вначале, необходимо перейти на страницу about:flags и включить «Enable experimental JavaScript».
Тут мы одновременно используем многие новые возможности ES6: промисы, генераторы, let, for-of. Когда мы выполняем yield для промиса, вспомогательная функция spawn ожидает выполнения промиса и возвращает результат. В случае, если промис завершается отказом, spawn заставляет выражение yield выбросить исключение statement, которое можно можно затем обработать стандартной конструкцией JavaScript try/catch. Удивительно простое асинхронное программирование!
0

Комментарии

Для того, чтоб оставлять комментарии или зарегистрируйтесь.