자바스크립트의 제너레이터

Sheryl Yun·2022년 10월 8일
0
post-thumbnail

제너레이터

자바스크립트에도 제너레이터라는 개념이 있다. 원하는 만큼 코드를 시작 또는 중지할 수 있는 함수이다. yield로 값을 반환하고 기본적으로 일시중지되었다가, .next()를 통해 yield 값 반환을 계속 이어갈 수 있다.

// 제너레이터 함수 (function*로 선언)
function* fruitList() {
	yield 'Banana';
    yield 'Apple';
    yield 'Orange';
}

// 제너레이터 함수를 실행
const fruits = fruitList();

// 제너레이터 함수를 실행한 것을 가지고 next()로 yield값 호출
// value에 yield 값이 있는 한(= undefined가 아닌 한) done은 계속 false
fruits.next(); // { value: "Banana", done: false }
fruits.next(); // { value: "Apple", done: false }
fruits.next(); // { value: "Orange", done: false }

// 반환값을 모두 반환했는데도 또 next()를 호출하면 done이 true가 됨
fruits.next(); // { value: undefined, done: true }

제너레이터 실행을 시작한 후 각 next() 사이에서 일시중지되어 있다가 yield 값이 모두 반환되면 실행이 종료(done: true)된다.

제너레이터로 배열 반복하기

for-of 반복문을 통해 제너레이터를 반복하고 결과값을 반환할 수 있다.

const fruitList = ['Banana', 'Apple', 'Orange', 'Melon', 'Cherry'];

// 제너레이터 반복문 함수 생성
function* loop(arr) {
	for (const item of arr) {
    	yield `I like to eat ${item}s`;
    }
}

// 제너레이터 함수 실행
const fruitGenerator = loop(fruitList);

// next()로 for-of문의 yield값 차례차례 반환
fruitGenerator.next(); // { value: "I like to eat Bananas", done: false }
fruitGenerator.next(); // { value: "I like to eat Apples", done: false }

// 특정 차례에 value만 출력할 수도 있음
fruitGenerator.next().value; // "I like to eat Orange"

.return() 메서드로 제너레이터 종료하기

.return() 메서드의 기능은 두 가지이다.

  1. 제너레이터를 종료하고,
  2. return() 메서드의 인자에 전달된 값을 반환
    (아무 인자도 전달하지 않으면 value는 undefined)
function* fruitList() {
	yield 'Banana';
    yield 'Apple';
    yield 'Orange';
}

const fruits = fruitList();

// 아무 next() 없이 바로 return (종료 + 인자값 반환)
fruits.return(); // { value: undefined, done: true }
// - return 메서드에 인자로 아무 것도 전달하지 않아서 value에 undefined 반환

throw()로 오류 잡기

// 제너레이터 함수 생성 (try/catch 포함)
function* gen() {
	try {
    	yield "Trying...";
        yield "Trying harder...";
        yield "Trying even harder...";
    }
    catch(err) {
    	console.log("Error: " + err);
    }
}

// 제너레이터 함수 실행
const myGenerator = gen();

// next()로 yield 값 반환
myGenerator.next(); // { value: "Trying...", done: false }
myGenerator.next(); // { value: "Trying harder...", done: false }

// 오류 발생시켜 catch문으로 이동하게 함
myGenerator.throw("웁스..!");

// 두 가지가 반환된다. 
// '웁스..!' -> catch문의 err 인자인 '웁스..!' 출력,
// { value: undefined, done: true } -> 오류가 났으므로 value에 undefined 반환 후 '종료'
// - '종료'하면 뒤에 yield 값이 남아 있어도 출력하지 않고 그대로 마침

제너레이터와 프로미스 같이 사용하기

제너레이터를 프로미스와 함께 사용하면 마치 동기인 것처럼 비동기 코드를 작성할 수 있다.

const myPromise = () => new Promise((resolve) => {
	resolve("The value is ");
});

// 비동기 제너레이터 함수 생성 (프로미스 결과값을 반환)
function* gen() {
	let result = '';
    
    yield myPromise().then((data) => { result = data }); // { } 부분 = Promise
    yield result + 2;
};

// 제너레이터 함수 실행
const asyncFunc = gen();

// next()로 첫 번째 yield 실행
const val1 = asyncFunc.next();

// 첫 번째 yield 값 출력
console.log(val1); // { value: Promise, done: false } -> Promise는 { result = data } 부분

// 프로미스가 완전히 완료('반환')되길 기다렸다가
// 반환된 프로미스(객체)의 value(= result)를 가지고(= then()) 두 번째 yield문 실행 (result + 2)
val1.value.then(() => {
	console.log(asyncFunc.next()); // { value: "The value is 2", done: false }
});
profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글