Генераторы

Генератор — специальный итерируемый объект возвращаемый функцией-генератором function*:

// функция-генератор GeneratorFunction(),
function* gen() { 
    yield 1;
    yield 2;
}

// которая возвращает объект Generator { }
const g = gen();

Вызов g.next() запускает выполнение функции до ближайшего yield и возвращает объект { value, done }, где value — значение возвращаемое yield, а done — статус генератора:

g.next(); // => Object {value: 1, done: false}
g.next(); // => Object {value: 2, done: false}
g.next(); // => Object {value: undefined, done: true}

yield

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

function* gen() {
    // yield возвращает 2,
    // а затем записывает 6 в val, переданное через следующий вызов next
    const val = yield 2;
    return val * 2;
}

const g = gen();

g.next();  // => Object {value: 2, done: false}
g.next(6); // => Object {value: 12, done: true}

Итерация

Генераторы можно обойти с помощью цикла for of:

for (let i of gen()) {
    console.log(i); // выведет 1, а затем 2
}

return

В конце функции генератора можно использовать return, например:

function* gen() { 
    yield 1;
    yield 2;
    return 3;
}

// В этом случае, третий next() вернёт это значение
g.next(); // => Object {value: 3, done: true}

Однако, цикл for of по прежнему выведет только два значения.

Генераторы и Промисы

// Функция #1 возвращающая промис и делающая что-то...
function pr1(num) {
    return new Promise(res => {
        setTimeout(() => res(num * 2), 1000);
    });
}

// Функция #2 возвращающая промис и делающая что-то...
function pr2(num) {
    return new Promise(res => {
        setTimeout(() => res(num + 2), 2000);
    });
}

// Функция-генератор работающая с промисами в синхронном стиле
function* doSomething(startNum) {
    const value1 = yield pr1(startNum); // value1 === 4
    const value2 = yield pr2(value1);   // value2 === 6
    return value2;
}

// Вспомогательная функция
function execute(generator, yieldValue) {
    const next = generator.next(yieldValue);

    if (!next.done) {
        next.value.then(res => execute(generator, res));
    } else {
        console.log(`done with: ${next.value}`);
    }
}

execute(doSomething(2));

Ссылки

results matching ""

    No results matching ""