Skip to content
This repository has been archived by the owner on May 26, 2020. It is now read-only.

Latest commit

 

History

History
88 lines (67 loc) · 5.48 KB

File metadata and controls

88 lines (67 loc) · 5.48 KB

Новые возможности JavaScript — Генераторы

Генераторы — новый вид функций в современном JavaScript, который был добавлен в ECMAScript 6. Отличаются они от обычных функций тем, что могу приостанавливать своё выполнение, возвращать промежуточный результат и далее возобновлять его позже, в произвольный момент времени.

Для объявления генератора используется новая синтаксическая конструкция: function* (), — её называют «функция-генератор».

// ECMAScript 6
function* createRequest(url) {
  try {
    let request = yield fetch(url);
    let response = yield request.text();

    return JSON.parse(response);
  } catch(error) {
    throw new Error(`Error: ${error.stack}`);
  }
}

Основным методом генератора является next(). При вызове он возобновляет выполнение кода до ближайшего ключевого слова yield. По достижении yield выполнение приостанавливается, а значение — возвращается во внешний код:

// ECMAScript 6
function* sequence() {
  yield 'one';
  yield 'two';
  return 'three';
}

let generator = sequence();

let step = generator.next();

console.log(step);
// Ожидаемый результат: {value: "one", done: false}

let secondStep = generator.next();

console.log(secondStep);
// Ожидаемый результат: {value: "two", done: false}

let thirdStep = generator.next();

console.log(thirdStep);
// Ожидаемый результат: {value: "three", done: true}

Функции-генераторы имеют 2 отличия от обычных функций:

  • Обычные функции начинаются с function, функции-генераторы начинаются с function*;
  • Внутри функции-генератора есть ключевое слово yield с синтаксисом, похожим на return. Отличие в том, что функция (в том числе функция-генератор) может вернуть значение только один раз, но отдать значение функция-генератор может любое количество раз. Выражение yield приостанавливает выполнение генератора, так что его можно позже обновить.

В этом и есть самая большая разница между обычными функциями и функциями-генераторами. Обычные функции не могут поставить себя на паузу, а функции-генераторы могут.

Вызов генератора выглядит так же как и обычной функции. Но после того, как вы вызовете генератор, он ещё не начнёт выполняться. Вместо этого он вернёт приостановленный объект Generator. Вы можете считать, что объект Generator — это вызов функции, замороженный во времени. Если точнее, он заморожен прямо в самом начале, функции-генератора, перед первой строчкой кода.

Каждый раз, когда вызывается метод next() у объекта Generator, вызов функции «оттаивает» и выполняется, пока не достигнет следующего выражения yield.

Вот почему в примере выше после вызовов метода next() мы всякий раз получали новое строковое значение. Эти значения производятся выражениями yield в теле функции.

При последнем вызове next() мы, наконец, достигли конца функции-генератора, так что поле done результата стало равно true.

Стоит отметить, что генераторы не являются потоками выполнения. В языках с потоками различные куски кода могут выполняться одновременно, обычно приводя к состояниям гонки, недетерменированности и страстно желанному приросту производительности. Генераторы вообще на это не похожи. Когда генератор выполняется, он работает в том же потоке, что и код его вызвавший. Порядок выполнения последователен и строго определён, и нет никакой параллельности. В отличие от системных потоков, генератор останавливается только на тех местах, где в коде есть yield.