# JS Tip of the Day: Interacting With Generators

**URL:** <https://forum.kirupa.com/t/js-tip-of-the-day-interacting-with-generators/643126>\
**Category:** web dev\
**Created:** [April 10, 2020, 12:28pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-interacting-with-generators/643126 "2020-04-10T12:28:28Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![senocular](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/senocular/32/7217_2.png) [@senocular](https://forum.kirupa.com/u/senocular)\
**Post date:** [April 10, 2020, 12:28pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-interacting-with-generators/643126/1 "2020-04-10T12:28:28Z")

</div>

**Interacting With Generators**  
Version: ES2015  
Level: Advanced

The iterator protocol provides methods for interacting with iterators. These include `next()` and optionally `return()` and `throw()`. Each of these are used both for pulling data from iterators (iterator result objects) as well as sending data to them. When working with generators, these methods relate directly to operations in the execution of the generator function.

Normal usage of the `next()` method will run the generator function of the generator object up until it reaches the next `yield` in its execution. The value yielded is set as the `value` property of the iterator result object returned back to the `next()` call.

```javascript
function * counter () {
    yield 1;
    yield 2;
    yield 3;
}

let count = counter();

// run counter() up to yield 1
console.log(count.next()); // {value: 1, done: false}

// continue running counter() up to yield 2
console.log(count.next()); // {value: 2, done: false}

```

The `next()` function can also be passed a value. This value is becomes the what the previous `yield` expression in the generator resolves to.

```javascript
function * counter () {
    let fromNext = yield 1; // returns what's passed to next()
    console.log('from next:', fromNext);
    yield 2;
    yield 3;
}

let count = counter();
count.next(); // (starts function)
count.next('there'); // from next: there

```

Since the value passed to `next()` is tied to a `yield` in the generator, there’s currently no way to get the value in the first `next()` call that starts the generator function. However there is a proposal (stage 2) for doing this using `function.sent`.

```javascript
function * counter () {
    console.log('first next:', function.sent); // proposed
    let fromNext = yield 1;
    console.log('from next:', fromNext);
    yield 2;
    yield 3;
}

let count = counter();
count.next('hello'); // first next: hello
count.next('there'); // from next: there

```

Because you can pass values into `next()`, what it sends to the generator can be used to alter how the generator produces additional values.

```javascript
function * counter () {
    let stopCounting = yield 1;
    if (stopCounting) {
        return;
    }
    yield 2;
    yield 3;
}

let count = counter();
console.log(count.next()); // {value: 1, done: false}
console.log(count.next(true)); // {value: undefined, done: true}

```

Here, passing `true` to the generator through `next()` will cause it to return, exiting early. However, for this specific case, a condition like this isn’t actually needed because this behavior is already built-in using the `return()` method.

When using `return()` the generator will return immediately from its current point of execution in the function. Anything you pass into the `return()` method will be returned from the generator function and ultimately given back to the iterator result object.

```javascript
function * counter () {
    yield 1;
    yield 2;
    yield 3;
}

let count = counter();
console.log(count.next()); // {value: 1, done: false}
console.log(count.return('end')); // {value: 'end', done: true}

```

The result is the same as though a `return` statement immediately followed the respective `yield`.

```javascript
function * counter () {
    yield 1;
    return 'end';
    yield 2;
    yield 3;
}

let count = counter();
console.log(count.next()); // {value: 1, done: false}
console.log(count.next()); // {value: 'end', done: true}

```

`throw()` works much the same way except it will inject a `throw` statement into the execution of the generator, throwing whatever argument it was given when called.

```javascript
function * counter () {
    try {
        yield 1;
        yield 2;
        yield 3;
    } catch (error) {
        console.log('Error:', error);
    }
}

let count = counter();
console.log(count.next()); // {value: 1, done: false}
console.log(count.throw('wanted letters')); // Error: wanted letters
// { value: undefined, done: true }

```

This being the same as…

```javascript
function * counter () {
    try {
        yield 1;
        throw 'wanted letters';
        yield 2;
        yield 3;
    } catch (error) {
        console.log('Error:', error);
    }
}

let count = counter();
console.log(count.next()); // {value: 1, done: false}
console.log(count.next()); // Error: wanted letters
// { value: undefined, done: true }

```

Bear in mind that both `return()` and `throw()` suffer similar problems for the first invocation of a generator as does `next()`. If the initial call to a generator object was a `throw()`, it’d have no way to handle it because it would be thrown before the generator would have time to even reach a `try...catch` statement.

```javascript
function * counter () {
    try {
        yield 1;
        yield 2;
        yield 3;
    } catch (error) {
        console.log('Error:', error);
    }
}

let count = counter();
console.log(count.throw('wanted letters')); // Uncaught wanted letters

```

Also, while all generators inherently implement `return()` and `throw()`, they are not required methods for all iterators. If you are working with some arbitrary iterator which may not have originated from a generator, you may want to see if these methods exist before attempting to call them.

More info:

- [Generator on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator)
- [Proposal: function.sent](https://github.com/tc39/proposal-function.sent)
- [Iteration protocols on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)
