2023.04.09
자바스크립트 스터디 12회차
공부 사이트: https://poiemaweb.com/
12. 제너레이터
ES6에서 도입된 제너레이터 함수는 이터러블을 생성하는 함수이다.
→ 이터레이션 프로토콜을 준수하여 이터러블을 생성하는 방식보다 간편하게 이터러블을 구현할 수 있다.
→ 비동기 처리에 유용하게 사용된다.
1) 제너레이터
// 이터레이션 프로토콜을 구현하여 무한 이터러블을 생성하는 함수
const createInfinityByIteration = function() {
let i = 0;
return {
[Symbol.iterator]() { return this; },
next() {
return { value: ++i };
}
};
};
for(const n of createInfinityByIteration ()){
if (n > 5) break;
console.log(n);
}
// 무한 이터러블을 생성하는 제너레이터 함수
function* createInfinityByGenerator() {
let i = 0;
while(true) { yield ++i; }
}
for(const n of createInfinityByGenerator()){
if (n > 5) break;
console.log(n);
}
ㅇ 일반 함수 호출 : return문으로 반환 값 리턴
ㅇ 제너레이터 함수 호출 : 제너레이터 반환
→ 제너레이터는 이터러블이면서 이터레이터인 객체
→ 제너레이터는 Symbol.iterator 메소드를 소유한 이터러블이며, 가지고 있는 next 메소드 호출 시 value/done 프로퍼티를 갖는 이터레이터 결과 객체를 반환하는 이터레이터이다.
function* counter() {
for(const v of [1,2,3]) yield v;
}
let generatorObj = counter();
console.log(Symbol.iterator in generatorObj); //true
console.log('next' in generatorObj); //true
2) 제너레이터 함수의 정의
제너레이터 함수는 function* 키워드로 선언한다.
또한 하나 이상의 yield 문을 포함한다.
// 제너레이터 함수 선언식
function* genDecFunc(){
yield 1;
}
// 제너레이터 함수 표현식
const genExpFunc() = function* (){
yield 1;
};
// 제너레이터 메소드
const obj = {
* generatorObjMethod(){
yield 1;
}
};
// 제너레이터 클래스 메소드
class MyClass{
* generatorClsMethod(){
yield 1;
}
}
3) 제너레이터 함수의 호출
제너레이터 함수를 호출하면 함수 코드 블록이 실행되는 것이 아니라, 제너레이터 객체를 반환한다.
function* counter() {
console.log('TEST 1');
yield 1; // 첫번째 next 메소드 호출 시 여기까지 실행
console.log('TEST 2');
yield 2; // 두번째 next 메소드 호출 시 여기까지 실행
console.log('TEST 3');
yield 3; // 세번째 next 메소드 호출 시 여기까지 실행
console.log('TEST 4'); // 네번째 next 메소드 호출 시 여기까지 실행
}
// 제너레이터 함수 호출 시 제너레이터 객체 반환
const generatorObj = counter();
// 첫 번째 next 메소드 호출 시 첫 yield문까지 실행되고 일시 중단
// 함수 내 모든 yield문이 실행되면 done 프로퍼티 값이 true가 됨.
console.log(generatorObj.next());
4) 제너레이터의 활용
① 이터레이션 프로토콜을 준수하여 이터러블을 생성하는 방식보다 간편하게 이터러블 구현이 가능하다.
② 제너레이터를 사용하여 비동기 처리를 동기 처리처럼 구현할 수 있다.
→ 비동기 처리 함수가 처리 결과를 반환하도록 구현 가능
// 원격 api 호출하는 fetch 함수 사용 위해 node-fetch 패키지 불러옴
const fetch = require('node-fetch');
function getUser(genObj, username){
fetch(`https://api.github.com/users/${username}`)
.then(res => res.json())
// 제너레이터 객체에 비동기 처리 결과를 전달
.then(user =>genObj.next(user.name));
}
// 제너레이터 객체 g
const g = (function* () {
let user;
// 비동기 처리 함수가 결과를 반환함. (비동기 처리 중 순서 보장 가능)
user = yield getUser(g, 'jeresig');
console.log(user);
user = yield getUser(g, 'ahejlsberg');
console.log(user);
}());
// 제너레이터 함수 시작
g.next();
[코드 설명]
- `https://api.github.com/users/사용자이름` 으로 요청 시 깃허브 user 정보가 들어있는 json을 제공- 비동기 처리가 완료되면 next 메소드 통해 제너레이터 객체에 비동기 처리 결과를 전달- 제너레이터 객체에 전달된 비동기 처리 결과는 user 변수에 할당됨
※ 코드 실행 이슈: node-fetch 설치 시 v2로 설치해야 정상 작동한다.
npm install node-fetch@2
제너레이터를 통해 비동기처리를 동기 처리처럼 구현 가능하나, 코드가 꽤 복잡하기에..
ES7에서 async/awat이 도입되었다.
const fetch = require('node-fetch');
// Promise를 반환하는 함수 (비동기 처리 시, 콜백 패턴 대신 사용하는 객체)
function getUser(username){
return fetch(`https://api.github.com/users/${username}`)
.then(res => res.json())
.then(user => user.name);;
}
async function getUserAll() {
let user;
user = await getUser('jeresig');
console.log(user);
user = await getUser('ahejlsberg');
console.log(user);
}
getUserAll();
'프로그래밍 > js' 카테고리의 다른 글
ES lessons 13-14. Babel, Webpack (0) | 2023.04.09 |
---|---|
ES lessons 11. 이터레이션 & for of문 (0) | 2023.04.05 |
ES6 lessons 10. 심볼 (0) | 2023.04.03 |
ES6 lessons 9. 프로미스 (0) | 2023.04.03 |
ES6 lessons 8. 모듈 (0) | 2023.04.03 |