Выход Javascript из функции, вложенной внутри генератора

Этот код генерирует ошибку:

function *giveNumbers() {
    [1, 2, 3].forEach(function(item) {
        yield item;
    })
}

Это, вероятно, потому, что выход внутри функции, которая не является генератором. Есть ли элегантный способ преодолеть это? Я имею в виду, кроме:

function *giveNumbers() {
    let list = [1, 2, 3];
    for (let i = 0; i < list.length; i++) {
        yield list[i];
    }
}

Ответы

Ответ 1

Это, вероятно, потому, что выход внутри функции, которая не является генератором.

Да. Вы не можете использовать yield от обратных вызовов.

Есть ли элегантный способ преодолеть это?

Зависит от варианта использования. Обычно существует нулевая причина, по которой на самом деле нужно получить yield от обратного вызова.

В вашем случае вы хотите, чтобы for…of цикла, который превосходит .forEach почти в каждом аспекте:

function *giveNumbers() {
    for (let item of [1, 2, 3])
        yield item;
}

Ответ 2

yield возвращает результат вызывающему.
допустим, что обратный вызов forEach является генератором (это не проблема для установки там генератора костюмов) - это означает, что когда обратный вызов yield результат, он возвращает его обратно для forEach.

В принципе, в вашем вопросе, что вы можете сделать, это:

callback -> yields to forEach -> yields to giveNumbers -> yields to caller

Итак, forEach должен вернуть результат, чтобы giveNumbers. но поскольку forEach не работает так, это невозможно без повторных прототипов массивов с костюмом forEach.

На самом деле, второй фрагмент является самым элегантным для начала.

Ответ 3

вы можете использовать синтаксис yield *.

function *giveNumbers() {
    yield * [1, 2, 3].map(function(item) {
        return item;
    })
}

Ответ 4

Вы также можете использовать аргументы while и pass как таковые (Demo)

function *giveNumbers(array, start) {
    var index = start || 0;
    while(array.length > index + 1) {
        yield array[index++];
    }
    return array[index];
}


var g = giveNumbers([1,2,3], 0);

var finished = false;

while(!finished) {
    var next = g.next();
    console.log(next.value);
    if(next.done) {
        finished = true;
    }
}