Reputation: 639
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];
}
}
Upvotes: 26
Views: 9478
Reputation: 45454
Sometimes there's no way to yield directly like with the .map
example in the other answer. For example, if we have a tree of nodes, and each node has a traverse
method to traverse the tree, accepting a callback that runs for each node, we can create an additional array to yield:
function nodes(obj) {
const nodes = []
obj.traverse(node => nodes.push(node))
yield * nodes
}
for (const node of nodes(someTree)) console.log(node)
If we have access to the array, we can directly loop to avoid an extra array:
function nodes(obj) {
yield obj
for (const node of obj.children) {
yield * nodes(node)
}
}
for (const node of nodes(someTree)) console.log(node)
Upvotes: 0
Reputation: 145
you can use the yield *
syntax.
function *giveNumbers() {
yield * [1, 2, 3].map(function(item) {
return item;
})
}
Upvotes: 6
Reputation: 5928
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;
}
}
Upvotes: 0
Reputation: 664297
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;
}
Upvotes: 14
Reputation: 26476
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.
Upvotes: 1