본문 바로가기

ECMAScript 2015, ECMAScript 6th Edition

12. Generator

사실 Generator 라는걸 처음 접했을 땐 진짜 뭥미... 했었다... ㅋㅋ


그런데 python 에서도 scala 에서도 generator 라는 개념이 있더라. +_+ 그리고 java 에서도 generator 형태로 코드를 짜는 방법도 "java generator" 라고 검색하면 많이 있더라 :)


* python generator : http://bluese05.tistory.com/56

* java generator : https://www.codeproject.com/Articles/793374/Generators-with-Java

* scala generator : http://notes.backgroundsignal.com/Generators_in_Scala.html


위에 javascript generator : ... 라고 적고 싶지만! 이건 내 블로그에서 설명할거니까 빼자 ㅎㅎ

Sample Code

class Member {
	*gen() {
		yield 10;
		yield 20;
	}
}

let obj = new Member();
let genObj = obj.gen();

let result = genObj.next();
console.log(result);
// { value: 10, done: false }
let result = genObj.next();
console.log(result);
//{ value: 20, done: false }
result = genObj.next();
console.log(result);
// { value: undefined, done: true }

가장 이해하기 좋은 예제가 아닐까... ㅎㅎ 

Generator function 은 안에 더이상 yield 할게 없을 때까지 yield 한다. 그리고 항상 return 의 형태는 { value : xxx, done: false/true } 형태이다. 


value : yield 된 값을 의미

done : 더이상 yield 할게 없을 경우 true, 더 남아 있을 경우 false 가 반환된다.


Generator funciton 을 이용한 iterator 구현

let fibonacci = {
    *[Symbol.iterator]() {
        let pre = 0, cur = 1
        for (;;) {
            [ pre, cur ] = [ cur, pre + cur ]
            yield cur
        }
    }
}

for (let n of fibonacci) {
    if (n > 1000)
        break
    console.log(n)
}
Symbol ... 을 아직 배우지 않아 혼돈 스러울 수 있을것 같은데 일단은 "구현체 안에 *[Symbol.iterator]() 이 있으면 for-of 구문에 사용할 수 있다." 정도로만 이해해 놓자. fibonacci 가 Array 혹은 Array-like 가 아님에도 불구하고 for of 에서 사용되는 것을 볼 수 있다. 그리고 for 문에 돌면서 generator function 인 Symbol.iterator 가 계속해서 호출되는 것을 볼 수 있다.


Generator function 을 이용한 Control-flow

//  generic asynchronous control-flow driver
function async (proc, ...params) {
    var iterator = proc(...params)
    return new Promise((resolve, reject) => {
        let loop = (value) => {
            let result
            try {
                result = iterator.next(value)
            }
            catch (err) {
                reject(err)
            }
            if (result.done)
                resolve(result.value)
            else if (   typeof result.value      === "object"
                     && typeof result.value.then === "function")
                result.value.then((value) => {
                    loop(value)
                }, (err) => {
                    reject(err)
                })
            else
                loop(result.value)
        }
        loop()
    })
}

//  application-specific asynchronous builder
function makeAsync (text, after) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(text), after)
    })
}

//  application-specific asynchronous procedure
async(function* (greeting) {
    let foo = yield makeAsync("foo", 300)
    let bar = yield makeAsync("bar", 200)
    let baz = yield makeAsync("baz", 100)
    return `${greeting} ${foo} ${bar} ${baz}`
}, "Hello").then((msg) => {
    console.log("RESULT:", msg) // "Hello foo bar baz"
})

마지막 async 함수에서 makeAsync 라는 함수들이 호출되는데 이들이 모두 Promise 를 리턴하는 것을 볼 수 있다.  promise 를 yield 시키게 되면 리턴된 promise 는 마치 syncronized 하게 코드가 동작하는 것을 볼 수 있다. 이러한 원리를 이용해 나오는 node.js library 가 바로 Co routine 이다.


'ECMAScript 2015, ECMAScript 6th Edition' 카테고리의 다른 글

11. Array Object  (0) 2016.09.27
10. Object assign  (0) 2016.09.27
9. for of  (0) 2016.09.25
8. Enhanced Object ProPerties  (0) 2016.09.15
7. destructuring  (0) 2016.09.13