Home » Nodejs » Javascript yield from the function nested inside generator

Javascript yield from the function nested inside generator

Posted by: admin November 30, 2017 Leave a comment

Questions:

This code generates an error:

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

This is probably because yield is inside a function that is not a generator. Is there an elegant way to overcome this? I mean other than:

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

This is probably because yield is inside a function that is not a generator.

Yes. You cannot use yield from callbacks.

Is there an elegant way to overcome this?

Depends on the use case. Usually there is zero reason to actually want to yield from a callback.

In your case, you want a for…of loop, which is superior to .forEach in almost every aspect anyway:

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

Questions:
Answers:

yield returns the result to the caller.
let’s assume the forEach callback is a generator (it’s not a problem to set a costume generator there) – it means tha when the callback yield the result – it yields it back to forEach.

Basically, in your question what you attemp to do is:

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

So, forEach should yield the result back to giveNumbers. but since forEach doesn’t work like this, it’s impossible without re-prototype arrays with costume forEach.

Actually, you second snippet is the most elegant to begin with.

Questions:
Answers:

You can also use while and pass arguments as such (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;
    }
}