🙄제너레이터란
제너레이터란 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재개할 수 있는 특수한 함수입니다.
ES6에 도입되었으며 일반함수와의 차이점이 약간 있습니다.
1. 제너레이터 함수는 함수 호출자에게 함수 실행의 제어권을 양도할 수 있습니다.
일반 함수는 호출하면 제어권이 함수에게 넘어갑니다.
즉 함수 호출자는 함수를 호출한 이후 함수 실행을 제어할 수가 없습니다.
하지만 제너레이터 함수는 함수 실행을 호출자가 제어할 수 있습니다.
이것은 함수의 제어권을 함수가 독점하는게 아니라 함수 호출자에게 양도할 수 있다는 뜻입니다.
2. 제너레이터 함수는 함수 호출자와 함수의 상태를 주고 받을 수 있습니다.
일반 함수는 호출하면 매개변수를 통해 함수 외부에서 값을 주입 받고
함수 코드를 실행하여 결과값을 함수 외부로 반환합니다.
함수 실행 중에는 함수 외부에서 함수 내부로 값을 전달하여 함수의 상태를 변경할 수 없습니다.
제너레이터 함수는 함수 호출자와 양방향으로 함수의 상태를 주고 받을 수 있습니다.
제너레이터 함수는 함수 호출자에게 상태를 전달할 수도 있고
함수 호출자로부터 상태를 전달받을 수도 있습니다.
3. 제너레이터 함수를 호출하면 제너레이터 객체를 반환합니다.
일반 함수는 호출하면 함수 코드를 일괄 실행하고 값을 반환하지만
제너레이터 함수는 함수를 호출하면 함수 코드를 실행하는게 아니라
이터러블이면서 동시에 이터레이터인 제너레이터 객체를 반환합니다.
일반함수 | 제너레이터 함수 | |
함수 제어권 | 호출 시 제어권이 함수에게 넘어감 | 함수 제어권을 함수가 독점하는게 아닌 함수 호출자에게 양도할 수 있음 |
함수의 상태 | 매개변수를 통해 외부에서 값을 주입받고 함수코드를 "일괄" 실행하여 결과값을 외부에 반환함 |
함수 호출자와 양방향으로 함수 상태를 주고 받는게 가능 |
반환하는 값 | 리턴 값 | 제너레이터 객체 (이터러블이면서 이터레이터임) |
🙄 제너레이터 함수 어케 쓰나요?
이렇게요
제너레이터 함수는 위와같이 function* 키워드로 선언하며function* genDecFunc() { yield 1; } // 제너레이터 함수 선언문 const genExpFunc2 = function* () { yield 1; } // 제너레이터 함수 표현식 const obj = { * genObjMethod() { yield 1; } } // 제너레이터 메서드 class MyClass { * genClsMethod() { yield 1; } } //제너레이터 클래스 메서드
하나 이상의 yield 표현식을 포함해야합니다.
또한 화살표 함수로는 정의할 수 없고 new 연산자와 함께 호출할 수 없습니다.
🙄제너레이터 객체가 뭔가요?
위에서 제너레이터 함수는 제너레이터 객체를 반환한다고 했습니다.
제너레이터 객체가 뭘까용
제너레이터 객체는 Symbol.iterator 메서드를 상속받는 이터러블이면서
value, done 프로퍼티를 갖는 이터레이터 리절트 객체를 반환하는 next 메서드를 소유하는 이터레이터
제너레이터 객체는 next 메서드를 가지는 이터레이터이기 때문에 Symbol.iterator 메서드를 통해
별도로 이터레이터를 생성할 필요가 없습니다.
또한 제너레이터 객체는 next 메서드를 갖는 이터레이터지만
이터레이터에는 없는 return , throw 메서드를 가집니다.
next 제너레이터 함수의 yield 표현식까지 코드블록을 실행하고
yield 된 값을 value 프로퍼티 값으로 false를 done 프로퍼티 값으로 갖는
이터레이터 리절트 객체를 반환합니다.return 인수로 전달받은 값을 value 프로퍼티 값으로
true를 done 프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환합니다.throw throw 메서드는 호출하면 인수로 전달받은 에러를 발생시키고
undefined를 value 프로퍼티 값으로 갖고 true를 done 프로퍼티값으로 갖는
이터레이터 리절트 객체를 반환합니다.const genExpFunc2 = function* () { try { yield 1; yield 2; yield 3; } catch (e) { console.error(e) } } const generator = genExpFunc2(); console.log(generator.next()) // {value:1 , done: false} console.log(generator.next()) // {value:2 , done: false} console.log(generator.return('End!')) // {value:End! , done : true} console.log(generator.throw('Error!')) // {value: undefiend , done:true} /* next 메서드는 yield 표현식 까지 코드블록을 실행합니다 return 메서드는 인수로 전달받은 값을 value 프로퍼티 값으로 넣습니다. throw 메서드는 인수로 전달받은 에러를 발생시키고 undefined를 밸류 프로퍼티 값으로 넣습니다. */
🙄제너레이터의 일시 중지와 재개
제너레이터는 yield 키워드와 next 메서드를 통해 실행을 일시 중지했다가
필요한 시점에 다시 재개할 수 있습니다.
제너레이터 함수를 호출하면 제너레이터 함수의 코드 블록이 실행되는게 아니라
제너레이터 객체를 반환합니다. 이 제너레이터 객체는 next 메서드를 가지고
제너레이터 객체의 next 메서드를 호출하면 제너레이터 함수의 코드 블록을 yield 표현식까지만 실행합니다.
그래서 제너레이터 함수는 모든 코드를 한번에 다 실행하는게 아니라
yield 표현식 까지만 실행하는거죠!
const genExpFunc2 = function* () { try { yield 1; yield 2; yield 3; } catch (e) { console.error(e) } } const generator = genExpFunc2(); console.log(generator.next()) // {value:1 , done: false} console.log(generator.next()) // {value:2 , done: false} console.log(generator.next()) // {value:3 , done: false} console.log(generator.next()) // {value:undefined , done: true}
위 예제와 같이 yield 표현식까지 실행되고 일시중지됩니다.
그리고 더이상 실행할 yield 표현식이 없는데 next() 메서드를 사용하면
undefined가 반환되며 done 상태가 true로 변경됩니다.
1. yield 표현식까지 실행되고 일시중지되며 함수의 제어권이 호출자로 양도됨
이때 제너레이터 객체의 next 메서드는 value, done 프로퍼티를 가지는
이터레이터 리절트 객체를 반환함. value에는 yiled된 값 (yield 키워드 뒤의 값)이 할당되고
done 프로퍼티에는 끝까지 실행되었는지 여부를 불리언값으로 표현함
2. 제너레이터의 next 메서드에는 인수를 전달할 수 있음
여기에 전달한 인수는 제너레이터 함수의 yield 표현식을 할당받는 변수에 할당됨
function* genFunc() {
const x = yield 1
/*
(1) 첫번째 next 메서드를 호출 했을 때 첫번째 yield 표현식까지 실행되고 중지됨
이때 yield 값 1은 value 프로퍼티에 할당됨
x 변수에는 아무것도 할당되지 않았고 x 변수의 값은 next 메서드가 두번째 호출될 떄 결정 됨
첫번째 next 메서드에는 인수를 전달해도 무시됨
(2) 두번째 next 메서드가 호출 될 때 전달한 인수 10은 첫번째 yield 표현식을 할당받는 x 변수에 할당됨
즉 두번째 next 메서드에서 x = 10이 할당되는 것
yield된 값 (x+10)은 밸류프로퍼티에 할당됩니다 x에 10을 할당했으니 10+10 = 20이 할당됩니다
*/
const y = yield (x + 10)
/*
(3) 세번째 next 메서드가 호출 될 때 전달한 인수 20은 y에 할당되며
함수 끝까지 실행됩니다. 제너레이터 함수의 반환값 x + y 는 value 프로퍼티에 할당됩니다.
일반적으로 제너레이터의 반환값은 의미가 없기때문에 return은 종료의 의미로 사용합니다.
*/
return x+y
}
const generator = genFunc(0)
//제너레이터 함수를 호출하면 제너레이터 객체를 반환합니다.
let res = generator.next()
//처음 호출하는 next 메서드에는 인수를 전달하지 않습니다 인수를 전달하면 무시됩니다.
console.log(res)
//{ value: 1, done: false }
res = generator.next(10)
//genFunc 함수의 x 변수에 10이 할당됩니다.
console.log(res)
//{ value: 20, done: false }
res = generator.next(20)
//genFunc 함수의 y 변수에 20이 할당됩니다. 이후 x+y까지 실행됩니다.
console.log(res)
//{ value: 30, done: true }
위와 같이 제너레이터 함수는 함수 호출자와 함수의 상태를 주고받을 수 있습니다.
이런 제너레이터의 특성을 활용하면 비동기 처리를
마치 동기처리하는 것처럼 구현할 수 있을거에요!
🙄 제너레이터를 이용해 이터러블 구현하기
그냥 함수를 이용해서 구현
//무한 이터러블을 생성하는 함수 const infiniteFibonacci = (function() { let [pre,cur] = [0,1] return { [Symbol.iterator]() {return this}, next() { [pre,cur] = [cur , pre + cur] // 무한 이터러블이므로 done 프로퍼티를 생략 return {value : cur} } } }()) // infiniteFibonacci는 무한 이터러블입니다. for(const num of infiniteFibonacci) { if (num > 10000) break; console.log(num) } /* 출력결과 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 */
제너레이터함수를 이용해 구현
const infiniteFibonacci = (function* () { let [pre,cur] = [0,1] while(true) { [pre,cur] = [cur, pre+cur] yield cur } }()) for(const num of infiniteFibonacci) { if(num > 10000) break console.log(num) }
좀 더 간결하게 구현할 수 있네요
🙄 제너레이터 함수로 비동기처리
const fetch = require('node-fetch') const async = generatorFunc => { const generator = generatorFunc() //(2) //인자로 받은 함수를 변수에 할당 const onResolved = arg => { const result = generator.next(arg)//(5) return result.done ? result.value : //(9) result.value.then(res => onResolved(res) ) //(7) } //result 변수에 next에 arg를 인자로 담아줍니다. //next에 담은 인자는 yield식의 결과로 할당됩니다. //done 프로퍼티의 불린값에 따라 true면 value를 반환하고 아니라면 then 메서드를 호출합니다. return onResolved //(3) //만들어둔 onResolved 함수를 반환합니다. } (async(function* fetchTodo() { //(1) const url = 'https://jsonplaceholder.typicode.com/todos/1'; const response = yield fetch(url) //(6) const todo = yield response.json() //(8) console.log(todo) // {userId : 1 , id: 1 , title: 'delectus aut autem' , completed:false} })())//(4)
반응형
'javascript' 카테고리의 다른 글
요약 정리는 못 참지 않을까요? (20) 모듈 (1) | 2023.01.28 |
---|---|
요약 정리는 못 참지 않을까요? (19) async/await (1) | 2023.01.27 |
요약 정리는 못 참지 않을까요? (17) Rest API와 프로미스 (2) | 2023.01.20 |
요약 정리는 못 참지 않을까요? (16) ajax와 json (0) | 2023.01.20 |
요약 정리는 못 참지 않을까요? (15) 비동기 프로그래밍 (0) | 2023.01.20 |