Поиск…
Вступление
 Функции генератора (определенные ключевым словом function* ) выполняются как сопрограммы, генерируя ряд значений по мере их запроса через итератор. 
Синтаксис
- function * name (parameters) {значение доходности; возвращаемое значение}
- generator = имя (аргументы)
- {значение, сделано} = generator.next (значение)
- {значение, сделано} = generator.return (значение)
- generator.throw (ошибка)
замечания
 Функции генератора - это функция, представленная как часть спецификации ES 2015 и недоступная во всех браузерах. Они также полностью поддерживаются в Node.js с v6.0 . Подробный список совместимости браузеров см. В документации MDN и узле, см. Веб- сайт node.green . 
Функции генератора
 Функция генератора создается с помощью декларации function* . Когда он вызывается, его тело не выполняется сразу. Вместо этого он возвращает объект-генератор , который может использоваться для «выполнения» выполнения функции. 
 Выражение yield внутри тела функции определяет точку, в которой выполнение может приостанавливаться и возобновляться. 
function* nums() {
    console.log('starting');  // A
    yield 1;                  // B
    console.log('yielded 1'); // C
    yield 2;                  // D
    console.log('yielded 2'); // E
    yield 3;                  // F
    console.log('yielded 3'); // G
}
var generator = nums(); // Returns the iterator. No code in nums is executed
generator.next();  // Executes lines A,B returning { value: 1, done: false }
// console: "starting"
generator.next();  // Executes lines C,D returning { value: 2, done: false }
// console: "yielded 1"
generator.next();  // Executes lines E,F returning { value: 3, done: false }
// console: "yielded 2"
generator.next();  // Executes line G returning { value: undefined, done: true }
// console: "yielded 3"
Ранний выход итерации
generator = nums();
generator.next(); // Executes lines A,B returning { value: 1, done: false }
generator.next(); // Executes lines C,D returning { value: 2, done: false }
generator.return(3); // no code is executed returns { value: 3, done: true }
// any further calls will return done = true 
generator.next(); // no code executed returns { value: undefined, done: true }
Выброс ошибки в функцию генератора
function* nums() {
    try {
        yield 1;                  // A
        yield 2;                  // B
        yield 3;                  // C
    } catch (e) {
        console.log(e.message);    // D
    }
}
var generator = nums();
generator.next();  // Executes line A returning { value: 1, done: false }
generator.next();  // Executes line B returning { value: 2, done: false }
generator.throw(new Error("Error!!"));  // Executes line D returning { value: undefined, done: true}
// console: "Error!!"
generator.next();  // no code executed. returns { value: undefined, done: true }
итерация
 Генератор истребитель . Он может быть закодирован с помощью инструкции for...of и использоваться в других конструкциях, которые зависят от протокола итерации. 
function* range(n) {
    for (let i = 0; i < n; ++i) {
        yield i;
    }
}
// looping
for (let n of range(10)) {
    // n takes on the values 0, 1, ... 9
}
// spread operator
let nums = [...range(3)];  // [0, 1, 2]
let max = Math.max(...range(100));  // 99
 Вот еще один пример использования генератора для пользовательского итеративного объекта в ES6. Здесь используется function * анонимного генератора. 
let user = {
  name: "sam", totalReplies: 17, isBlocked: false
};
user[Symbol.iterator] = function *(){
  let properties = Object.keys(this);
  let count = 0;
  let isDone = false;
  for(let p of properties){
    yield this[p];
  }
};
for(let p of user){
  console.log( p );
} 
Отправка значений генератору
 Можно отправить значение генератору, передав его next() методу. 
function* summer() {
    let sum = 0, value;
    while (true) {
        // receive sent value
        value = yield;
        if (value === null) break;
        // aggregate values
        sum += value;
    }
    return sum;
}
let generator = summer();
// proceed until the first "yield" expression, ignoring the "value" argument
generator.next();
// from this point on, the generator aggregates values until we send "null"
generator.next(1);
generator.next(10);
generator.next(100);
// close the generator and collect the result
let sum = generator.next(null).value;  // 111
Передача другому генератору
 Из функции генератора управление может быть делегировано другой функции генератора с использованием yield* . 
function* g1() {
  yield 2;
  yield 3;
  yield 4;
}
function* g2() {
  yield 1;
  yield* g1();
  yield 5;
}
var it = g2();
console.log(it.next()); // 1
console.log(it.next()); // 2
console.log(it.next()); // 3
console.log(it.next()); // 4
console.log(it.next()); // 5
console.log(it.next()); // undefined
Интерфейс Iterator-Observer
 Генератор представляет собой комбинацию из двух вещей - Iterator и Observer . 
Итератор
 Итератором является то, что при вызове возвращает iterable . iterable - это то, что вы можете повторить. Начиная с ES6 / ES2015, все коллекции (Array, Map, Set, WeakMap, WeakSet) соответствуют контракту Iterable. 
Генератор (итератор) является производителем. В итерации потребитель
PULLот производителя.
Пример:
function *gen() { yield 5; yield 6; }
let a = gen();
 Всякий раз , когда вы звоните a.next() , вы существенно pull -ную значение из итератора и pause исполнение на yield . При следующем вызове a.next() выполнение возобновляется из ранее приостановленного состояния. 
наблюдатель
Генератор также является наблюдателем, с помощью которого вы можете отправить некоторые значения обратно в генератор.
function *gen() {
  document.write('<br>observer:', yield 1);
}
var a = gen();
var i = a.next();
while(!i.done) {
  document.write('<br>iterator:', i.value);
  i = a.next(100);
}
 Здесь вы можете видеть, что yield 1 используется как выражение, которое оценивается до некоторого значения. Значение, которое оно оценивает, - это значение, отправленное в качестве аргумента для a.next функции a.next . 
 Таким образом, впервые i.value будет первым значением, полученным ( 1 ), и при продолжении итерации к следующему состоянию мы отправим значение обратно генератору, используя a.next(100) . 
Выполнение асинхронизации с генераторами
 Генераторы широко используются с функцией spawn (from taskJS или co), где функция принимает генератор и позволяет нам писать асинхронный код синхронно. Это НЕ означает, что асинхронный код преобразуется в синхронный код / выполняется синхронно. Это означает, что мы можем писать код, похожий на sync но внутри он все еще async . 
Синхронизация - БЛОКИРОВКА; Async ОЖИДАЕТ. Написание кода, который блокирует, легко. Когда PULLing, значение появляется в позиции назначения. Когда PUSHing, значение появляется в позиции аргумента обратного вызова.
 Когда вы используете итераторы, вы PULL значение от производителя. Когда вы используете обратные вызовы, производитель PUSH присваивает значение позиции аргумента обратного вызова. 
var i = a.next() // PULL
dosomething(..., v => {...}) // PUSH
 Здесь вы вытаскиваете значение из a.next() а во втором, v => {...} - это обратный вызов, а значение PUSH ed в позицию аргумента v функции обратного вызова. 
Используя этот механизм pull-push, мы можем написать асинхронное программирование, как это,
let delay = t => new Promise(r => setTimeout(r, t));
spawn(function*() {
  // wait for 100 ms and send 1
  let x = yield delay(100).then(() => 1);
  console.log(x); // 1
   // wait for 100 ms and send 2
  let y = yield delay(100).then(() => 2);
  console.log(y); // 2
});
 Итак, глядя на приведенный выше код, мы пишем асинхронный код, который выглядит как blocking (операторы доходности ждут 100 мс, а затем продолжают выполнение), но это на самом деле waiting . Свойство pause и resume генератора позволяет нам сделать этот потрясающий трюк. 
Как это работает ?
 Функция spawn использует yield promise чтобы PULL состояние обещания от генератора, ждет, пока обещание будет разрешено, и ОТПУСКАЕТ полученное значение обратно генератору, чтобы он мог его использовать. 
Используйте его сейчас
Итак, с генераторами и функцией spawn вы можете очистить весь ваш асинхронный код в NodeJS, чтобы выглядеть и чувствовать себя синхронным. Это облегчит отладку. Также код будет выглядеть аккуратно.
 Эта функция подходит к будущим версиям JavaScript - async...await . Но вы можете использовать их сегодня в ES2015 / ES6, используя функцию spawn, определенную в библиотеках - taskjs, co или bluebird 
Асинхронный поток с генераторами
Генераторы - это функции, которые могут приостановить и возобновить выполнение. Это позволяет эмулировать асинхронные функции с использованием внешних библиотек, в основном q или co. В основном это позволяет записывать функции, которые ждут результатов async для продолжения:
function someAsyncResult() {
    return Promise.resolve('newValue')
}
q.spawn(function * () {
    var result = yield someAsyncResult()
    console.log(result) // 'newValue'
})
Это позволяет написать асинхронный код, как если бы он был синхронным. Кроме того, попробуйте и поймайте работу над несколькими асинхронными блоками. Если обещание отклонено, ошибка будет улавливаться следующим уловом:
function asyncError() {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            reject(new Error('Something went wrong'))
        }, 100)
    })
}
q.spawn(function * () {
    try {
        var result = yield asyncError()
    } catch (e) {
        console.error(e) // Something went wrong
    }
})
 Использование co будет работать точно так же, но с co(function * (){...}) вместо q.spawn