[Javascript] Synchronous, Asynchronous - 4 (Generator/Yield)

Dongjun Ahn·2022년 7월 14일


Javascript에서 비동기 처리를 다루는 방법에는 여러가지가 있다. 주로 Callback, Promise, Async/Await, Generator/Yield를 활용한다.

Generator

일반 함수는 하나의 값(혹은 0개의 값)만을 반환한다.
하지만 제너레이터(generator)를 사용하면 여러 개의 값을 필요에 따라 하나씩 반환(yield)할 수 있다. generator와 iterable객체를 함께 사용하면 손쉽게 데이터 스트림을 만들 수 있다.

Iterable

Symbol.iterator 심볼을 속성으로 가지고 있고, 이터레이터 객체를 반환하는 객체

iterator

next() 메서드를 구현하고 있고, done과 value 속성을 가진 객체를 반환하는 객체이고,Symbol.iterator 메소드를 호출하여 이터레이터 객체를 얻은 후, 순차적으로 next() 메소드를 호출하면서 하나씩 순회하며, done 값이 true 이면 순회를 멈춘다.

사용법

Generator Funtion

제너레이터(generator)를 만들려면 '제너레이터 함수(generator function)’라 불리는 특별한 문법 구조, function* 이 필요하다.
제너레이터 함수를 호출하면 코드가 실행되지 않고, 대신 실행을 처리하는 특별 객체, '제너레이터 객체’가 반환된다.

function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}

// '제너레이터 함수'는 '제너레이터 객체'를 생성.
let generator = generateSequence();
// 아직 실행되지 않은 상태

next()

next()는 제너레이터의 주요 메서드이다. next()를 호출하면 가장 가까운 yield 문을 만날 때까지 실행이 지속된다(value를 생략할 수도 있는데, 이 경우엔 undefined). yield 문을 만나면 실행이 멈추고 value가 바깥 코드에 반환된다.

next()는 항상 두 프로퍼티를 가진 객체를 반환

  • value: 산출 값
  • done: 함수 코드 실행이 끝났으면 true, 아니라면 false
function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}

let generator = generateSequence();

let one = generator.next();        // 첫 yield를 반환
console.log(one);                  // {value: 1, done: false}

let two = generator.next();        // 다음 yield를 반환
console.log(JSON.stringify(two));  // {value: 2, done: false}
  
let three = generator.next();      // 다음 yield없음 함수 종료
console.log(JSON.stringify(three));// {value: 3, done: true}

let four = generator.next();       // 종료 상태
console.log(JSON.stringify(four)); // {done: true}

for..of 반복문

제너레이터는 iterable객체이기 때문에 for..of반복문을 사용해 값을 얻을수 있다.

function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}

let generator = generateSequence();

for(let value of generator) {
  alert(value); // 1, 2
}

for..of 이터레이션이 {done: true}일 때 마지막 value를 무시하기 때문에 1,2 만 출력 된다. 그러므로 for..of를 사용했을 때 모든 값이 출력되길 원한다면 yield로 값을 반환해야 한다.

  function* generateSequence() {
  yield 1;
  yield 2;
  yield 3;
}

let generator = generateSequence();

for(let value of generator) {
  alert(value); // 1, 2, 3
}

yield의 양방향 전달

yield는 결과를 바깥으로 전달할 뿐만 아니라 값을 제너레이터 안으로 전달하기까지 한다.

function* gen() {
  let ask1 = yield "2 + 2 = ?";
  alert(ask1); // 4
    
  let ask2 = yield "3 * 3 = ?"
  alert(ask2); // 9
}

let generator = gen();

alert( generator.next().value ); // "2 + 2 = ?"
alert( generator.next(4).value ); // "3 * 3 = ?"
alert( generator.next(9).done ); // true

정리

  1. 제너레이터는 제너레이터 함수 function* f(…) {…}을 사용해 만든다.
  2. yield 연산자는 제너레이터 안에 있어야 한다.
  3. next/yield 호출을 사용하면 외부 코드와 제너레이터 간에 결과를 교환할 수 있다.

Reference

https://ko.javascript.info/async-iterators-generators

profile
Front-end Developer

0개의 댓글