DEV Community

Damien Cosset
Damien Cosset

Posted on • Originally published at damiencosset.com

Introduction to Generators in ES6

Introduction

With ES6, we were given a new tool: generators. In a normal function, there is only one entry point: the invocation of the function itself. A generator allows you to pause the execution of a function and resume it later. Generators are useful when dealing with iterators and can simplify the asynchronous nature of Javascript.

Syntax

So, how would we define a generator, compared to a normal function? You declare a generator function by using the * ( asterisk ) operator after the function keyword:

function* awesomeGenerator(){
  //code
}
Enter fullscreen mode Exit fullscreen mode

To pause the execution inside the generator, we use the statement yield:

function* awesomeGenerator(){
  yield 'Hey friend' // We pause the execution here
  console.log('Back again') // When we resume, we are here
}
Enter fullscreen mode Exit fullscreen mode

next() method

A generator gives you a next() method, which is used to start/resume the execution. This method returns an object with two keys:

{
  value: [ yielded value ],
  done: [ true if we reach the end]
}
Enter fullscreen mode Exit fullscreen mode

Let's see a very simple generator in action:

function* groceriesGenerator(){
  yield 'Eggs'
  yield 'Tomatoes'
  yield 'Milk'
  return 'Paper Bag'
}

const groceries = groceriesGenerator()

console.log(groceries.next()) // [1]
console.log(groceries.next()) // [2]
console.log(groceries.next()) // [3]
console.log(groceries.next()) // [4]

// [1] { value: 'Eggs', done: false }
// [2] { value: 'Tomatoes', done: false }
// [3] { value: 'Milk', done: false }
// [4] { value: 'Paper Bag', done: true }
Enter fullscreen mode Exit fullscreen mode

At our first groceries.next() call, our groceriesGenerator reached our first yield statement and paused, returning the value Eggs to the caller. Our second next() resumed the execution at the second yield statement, pausing it again and returning Tomatoes...

Our last next() terminates the generator, returns Paper Bag and sets done to true.

As iterators

In the introduction, I said that generators could help to implement iterators. Let's see an example:

function* iterationGenerator( arr ){
  for( let i = 0; i < arr.length; i++ ){
    yield arr[i]
  }
}

const iterator = iterationGenerator( ['John', 'Sarah', 'Joe', 'Emily'])

let current = iterator.next()

while( !current.done ){
  console.log( current.value )
  current = iterator.next()
}

// John
// Sarah
// Joe
// Emily
Enter fullscreen mode Exit fullscreen mode

In this example, you can see how the state of the generator is maintained accross invocations. Whne we resume the execution by calling next(), the variables and loops are the same.

Pass values back to generators

Finally, you can also pass a value back to a generator. Here is a example:

function* twoWayGenerator(arr){
  for( let i = 0; i < arr.length; i++ ) {
    const symbol = yield 
    console.log(`${arr[i]} ${symbol}`)
  }
}

const prices = twoWayGenerator([10, 23, 12])

prices.next()
prices.next('โ‚ฌ')
prices.next('ยฃ')
prices.next('$')

// 10 โ‚ฌ
// 23 ยฃ
// 12 $
Enter fullscreen mode Exit fullscreen mode

Here, our first next() will not print anything because we pause the execution before the first console.log. The second next() is called with an argument. This argument is provided as the returned value of the yield statement. We store this value inside the symbol variable and use it next.

You can also force a generator to throw an error:

prices.next()
prices.throw( new Error('Invalid Amount'))

//  const symbol = yield
//                   ^
//  Error: Invalid Amount
Enter fullscreen mode Exit fullscreen mode

That's it for a quick and dirty introduction about generators. In the next article, we will go a bit deeper and explore how generators can help us control the asynchronous flow of Javascript.

Oldest comments (3)

Collapse
 
eljayadobe profile image
Eljay-Adobe • Edited

ES6 is sooooo much nicer than ES3/ES5 or TypeScript.

(Hard to tell intonation. I'm serious, I think ES6 is a significant improvement. I'd still probably use Elm or Reason, but I like what ES6 brings to the table.)

Collapse
 
maxwell_dev profile image
Max Antonucci

Thanks for this! It explained the basics very well, I'll likely use it in my next small project of remaking the Monty Hall Dilemma.

Collapse
 
bgadrian profile image
Adrian B.G. • Edited

It's one of the addition that brings JS almost on the same level as other common languages.

Too bad that devs have a low adoption rate to ES6, it's an improvement, and with Babel there is no excuse why to postpone the update.

Speaking of JS6 I made a playlist with Advanced JS topics from 2017 conferences , ranging from async to NodeJS event loop if anyone is interested.