Best of Modern JavaScript — Generator Methods
By: John Au-Yeung
Tags: Technology, Programming, Software Development, Web Development, JavaScript

Photo by Jason Blackeye on Unsplash

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at JavaScript generators.

The First next()

The next call starts an observer.

The only purpose of the first invocation next is to start the observer.

So if we pass in a value to the first next call, it won’t be obtained by yield .

For example, we can write:

function* genFn() {

while (true) {

console.log(yield);

}

} const gen = genFn();

gen.next('a');

gen.next('b');

gen.next('c');

Then:

b

c

is logged.

The first call of next feeds 'a' to the generator, but there’s no way to receive it since there’s no yield statement.

Once it runs yield , then the value can be received.

yield ‘s operand is returned once next is called.

The returned value would be undefined since we don’t have an operand to go with it.

The 2nd invocation of next feeds 'b' into next , which is received by yield .

And that’s logged with the console log.

And next returned undefined value again because yield has no operand.

Therefore, we can only feed data to yield when next is called.

For example, we can write:

function* genFn() {

while (true) {

console.log(yield);

}

} const gen = genFn();

gen.next();

gen.next('a');

gen.next('b');

gen.next('c');

Then we get:

a

b

c

logged in the console.

yield Binds Loosely

yield treats the whole expression that’s after it as its operand.

For instance, if we have:

yield foo + bar + baz;

Then it’s treated as:

yield (foo + bar + baz);

rather than:

(yield foo) + bar + baz;

Therefore, we’ve to wrap our yield expressions with parentheses so that we can avoid syntax errors.

For example, instead of writing:

function* genFn() {

console.log('yielded: ' + yield);

}

We write:

function* genFn() {

console.log('yielded: ' + (yield));

}

return() and throw()

The return and throw methods are similar to next .

return lets us return something at the location of yield .

throw lets us throw an expression at the location of yield .

The next method is suspended at a yield operator.

The value from next is sent to yield .

return terminates the generator.

For example, we can write:

function* genFn() {

try {

console.log('start');

yield;

} finally {

console.log('end');

}

} const gen = genFn();

gen.next()

gen.return('finished')

We have the genFn function that returns a generator with a given value.

The next method will run the generator.

And return ends the generator.

If we log the value of the return call, we get:

{value: "finished", done: true}

throw() lets us Throw Errors

We can throw errors with the throw keyword.

For instance, we can write:

function* genFn() {

try {

console.log('started');

yield;

} catch (error) {

console.log(error);

}

} const gen = genFn();

gen.next();

console.log(gen.throw(new Error('error')));

We call throw with the generator function.

The catch block will be invoked once we call next to start the generator.

Then we’ll see:

Error: error

logged with the console log of the catch block.

And {value: undefined, done: true} is returned from the throw call.

Photo by Jerry Zhang on Unsplash

Conclusion

We can call the next method and use it with the yield operator without an operand.

This will take the value from next and return it.