Regular function returns single value or nothing Generator can return multiple values, one after another by calling yield Generator function needs to have a * symbol: function* Generator function creates a generator object [object Generator] Code execution does not start on generator creation, but on .next() call Result of .next() is an object with two properties: {value: 1, done: false} Syntax function* generateSequence1() { yield 1 yield 2 yield 3 } let generator1 = generateSequence1() // generateSequence {<suspended>} let one = generator1.next() // {value: 1, done: false} let two = generator1.next() // {value: 2, done: false} let three = generator1.next() // {value: 3, done: false} let four = generator1.next() // {value: undefined, done: true} // with return function* generateSequence2() { yield 1 yield 2 return 3 } let generator2 = generateSequence2() let one = generator2.next() // {value: 1, done: false} let two = generator2.next() // {value: 2, done: false} let three = generator2.next() // {value: 3, done: true} let four = generator2.next() // {value: undefined, done: true} Generator is iterable // without return for(let value of generator1) { console.log(value) // 1, 2, 3 } // with return for(let value of generator2) { console.log(value) // 1, 2 } Spread syntax [...generator1] // [1, 2, 3] Iterable object based on generator let range = { from: 1, to: 5, *[Symbol.iterator]() { for(let value = this.from; value <= this.to; value++) { yield value; } } }; alert( [...range] ); // 1,2,3,4,5 Generator inside generator - yield* yield* directive delegates the execution to another generator function* generateSequence(start, end) { for (let i = start; i <= end; i++) yield i; } function* generatePasswordCodes() { yield* generateSequence(48, 57) // 0..9 // for (let i = 48; i <= 57; i++) yield i; yield* generateSequence(65, 90) // A..Z yield* generateSequence(97, 122) // a..z } let str = '' for(let code of generatePasswordCodes()) { str += String.fromCharCode(code) } alert(str) // 0..9A..Za..z Pass values from next to yield yield not only returns the result to the outside, but can pass the value inside the generator function* gen() { let ask1 = yield "2 + 2 = ?" alert(ask1) // 4 let ask2 = yield "3 * 3 = ?" alert(ask2) // 9 } let generator = gen() alert( generator.next().value ) // "2 + 2 = ?" // first next() should be always w/o arg alert( generator.next(4).value ) // "3 * 3 = ?" alert( generator.next(9).done ) // true Throw error into generator Outer code may pass error into a generator function* gen() { try { yield "start" alert("not reach here") yield "end" } catch(e) { alert(e) // shows the error } } let generator = gen() alert(generator.next().value) generator.throw(new Error("error")) alert(generator.next().value) // start // error // undefined