www.luxoft.com
Generators Flexibility in Modern Code
Andrii Orlov
www.luxoft.com
ES6 introduced a new way of working with
functions and iterators in the form of Generators
(or generator functions).
A generator is a function that can stop
midway and then continue from where it
stopped.
In short, a generator appears to be a function
but it behaves like an iterator.
What is a generator?
www.luxoft.com
Simple generator function
function* gen() {
yield 1
yield 2
yield 3
return 4
}
const generator = gen()
generator.next() // {value: 1, done: false}
generator.next() // {value: 2, done: false}
generator.next() // {value: 3, done: false}
generator.next() // {value: 4, done: true}
generator.next() // {value: undefined, done: true}
www.luxoft.com
Function !== Function*
www.luxoft.com
ITERATORS
(data producers)
OBSERVERS
(data consumers)
COROUTINES
(data producers
and consumers)
For-of loops,
spread operator
Observer pattern Cooperatively
multitasked tasks
Roles generators can play
www.luxoft.com
What is an iterator?
interface iteratorResult {
done: boolean,
value: any
}
Iterator is a way to pull data from a data structure on one-at-a-time fashion, it needs to
implement the iterator interface (which has three methods - next(), return() and
throw()).
An iteratorResult that returns from the iterator next() method needs to follow this
interface:
So each time we call next() on an iterator we should get {value: the current
iteration value, done: false/true}
www.luxoft.com
Generator as iterator
function* gen() {
yield 1
yield 2
yield 3
return 4
}
const generator = gen()
for(let value of generator) {
console.log(value); // 1, 2, 3
}
const spreadValues = […generator] // [1, 2, 3]
www.luxoft.com
Generator as observer
function createObserver(iterator) {
return {
next(value) { iterator.next(value) },
error(err) { iterator.throw(err) },
complete() { iterator.return() }
}
}
function* observerGenerator() {
try {
while(true) {
let value = yield
console.log(`next -> ${value}`)
}
} catch (err) {
console.log('error')
}
console.log('completed')
}
function observable(observer) {
for(let i = 0; i <= 10; i++) {
observer.next(i)
}
observer.error()
observer.complete()
}
observable(
createObserver(
observerGenerator()
)
)
Observer Observable
www.luxoft.com
Generators as coroutines. “CO” library
import co from 'co'
const fetchJSON = co.wrap(function* (url) {
try {
let request = yield fetch(url)
let text = yield request.text()
return JSON.parse(text)
}
catch (error) {
console.log(`ERROR: ${error.stack}`)
}
})
www.luxoft.com
Generator + Promise = Async/await ???
www.luxoft.com
Async/await vs generators
async function fetchJSON(url) {
try {
let request = await fetch(url)
let text = await request.text()
return JSON.parse(text)
}
catch (error) {
console.log(`ERROR: ${error.stack}`)
}
}
import co from 'co'
const fetchJSON = co.wrap(function* (url) {
try {
let request = yield fetch(url)
let text = yield request.text()
return JSON.parse(text)
}
catch (error) {
console.log(`ERROR: ${error.stack}`)
}
})
Async/await Generators
www.luxoft.com
Thank you!

Andrii Orlov "Generators Flexibility in Modern Code"

  • 1.
  • 2.
    www.luxoft.com ES6 introduced anew way of working with functions and iterators in the form of Generators (or generator functions). A generator is a function that can stop midway and then continue from where it stopped. In short, a generator appears to be a function but it behaves like an iterator. What is a generator?
  • 3.
    www.luxoft.com Simple generator function function*gen() { yield 1 yield 2 yield 3 return 4 } const generator = gen() generator.next() // {value: 1, done: false} generator.next() // {value: 2, done: false} generator.next() // {value: 3, done: false} generator.next() // {value: 4, done: true} generator.next() // {value: undefined, done: true}
  • 4.
  • 5.
    www.luxoft.com ITERATORS (data producers) OBSERVERS (data consumers) COROUTINES (dataproducers and consumers) For-of loops, spread operator Observer pattern Cooperatively multitasked tasks Roles generators can play
  • 6.
    www.luxoft.com What is aniterator? interface iteratorResult { done: boolean, value: any } Iterator is a way to pull data from a data structure on one-at-a-time fashion, it needs to implement the iterator interface (which has three methods - next(), return() and throw()). An iteratorResult that returns from the iterator next() method needs to follow this interface: So each time we call next() on an iterator we should get {value: the current iteration value, done: false/true}
  • 7.
    www.luxoft.com Generator as iterator function*gen() { yield 1 yield 2 yield 3 return 4 } const generator = gen() for(let value of generator) { console.log(value); // 1, 2, 3 } const spreadValues = […generator] // [1, 2, 3]
  • 8.
    www.luxoft.com Generator as observer functioncreateObserver(iterator) { return { next(value) { iterator.next(value) }, error(err) { iterator.throw(err) }, complete() { iterator.return() } } } function* observerGenerator() { try { while(true) { let value = yield console.log(`next -> ${value}`) } } catch (err) { console.log('error') } console.log('completed') } function observable(observer) { for(let i = 0; i <= 10; i++) { observer.next(i) } observer.error() observer.complete() } observable( createObserver( observerGenerator() ) ) Observer Observable
  • 9.
    www.luxoft.com Generators as coroutines.“CO” library import co from 'co' const fetchJSON = co.wrap(function* (url) { try { let request = yield fetch(url) let text = yield request.text() return JSON.parse(text) } catch (error) { console.log(`ERROR: ${error.stack}`) } })
  • 10.
  • 11.
    www.luxoft.com Async/await vs generators asyncfunction fetchJSON(url) { try { let request = await fetch(url) let text = await request.text() return JSON.parse(text) } catch (error) { console.log(`ERROR: ${error.stack}`) } } import co from 'co' const fetchJSON = co.wrap(function* (url) { try { let request = yield fetch(url) let text = yield request.text() return JSON.parse(text) } catch (error) { console.log(`ERROR: ${error.stack}`) } }) Async/await Generators
  • 12.