320x100
320x100

제너레이터

: 일반 함수는 하나의 값만을 반환

: 제너레이터를 사용하면 여러 개의 값을 필요에 따라 하나씩 반환 (yield) 가능

: 제너레이터와 이터러블 객체를 함께 사용하면 손쉽게 데이터 스트림을 만들 수 있음

 

 

 

 

제너레이터 함수

: function* 을 통해 생성

: 제너레이터 함수를 호출하면 코드가 실행되지 않고

  대신 실행을 처리하는 특별 객체인 제너레이터 객체가 반환 됨

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

// '제너레이터 함수'는 '제너레이터 객체'를 생성합니다.
let generator = generateSequence();
alert(generator); // [object Generator]

 

- next()

: 제너레이터의 주요 메서드

: 가장 가까운 yield <value>문을 만날 때 까지 실행이 지속

: value를 생략할 경우 undefined가 됨

: yield <value>문을 만나면 value가 바깥 코드로 반환됨

 

- next()의 프로퍼티

: value (산출 값)

: done (함수 코드 실행이 끝났으면 true, 아니면 false)

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

let generator = generateSequence();

let one = generator.next();

alert(JSON.stringify(one)); // {value: 1, done: false}

 

※ function* f()와 function *f()는 같다

 

 

 

 

제너레이터와 이터러블

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

let generator = generateSequence();

for(let value of generator) {
  alert(value); // 1, 2가 출력됨
}
function* generateSequence() {
  yield 1;
  yield 2;
  yield 3;
}

let sequence = [0, ...generateSequence()];

alert(sequence); // 0, 1, 2, 3

 

 

 

 

 

이터러블 대신 제너레이터 사용하기

let range = {
  from: 1,
  to: 5,

  // for..of 최초 호출 시, Symbol.iterator가 호출됩니다.
  [Symbol.iterator]() {
    // Symbol.iterator는 이터레이터 객체를 반환합니다.
    // for..of는 반환된 이터레이터 객체만을 대상으로 동작하는데, 이때 다음 값도 정해집니다.
    return {
      current: this.from,
      last: this.to,

      // for..of 반복문에 의해 각 이터레이션마다 next()가 호출됩니다.
      next() {
        // next()는 객체 형태의 값, {done:.., value :...}을 반환해야 합니다.
        if (this.current <= this.last) {
          return { done: false, value: this.current++ };
        } else {
          return { done: true };
        }
      }
    };
  }
};

// 객체 range를 대상으로 하는 이터레이션은 range.from과 range.to 사이의 숫자를 출력합니다.
alert([...range]); // 1,2,3,4,5
let range = {
  from: 1,
  to: 5,

  *[Symbol.iterator]() { // [Symbol.iterator]: function*()를 짧게 줄임
    for(let value = this.from; value <= this.to; value++) {
      yield value;
    }
  }
};

alert( [...range] ); // 1, 2, 3, 4, 5

: 위 두 코드는 동일한 결과를 출력한다

 

 

 

 

 

제너레이터 컴포지션

: 제너레이터 안에 제너레이터를 임베딩 할 수 있게 해주는 제너레이터의 특별 기능

function* generateSequence(start, end) {
  for (let i = start; i <= end; i++) yield i;
}

function* generatePasswordCodes() {

  // 0..9
  yield* generateSequence(48, 57);

  // A..Z
  yield* generateSequence(65, 90);

  // a..z
  yield* generateSequence(97, 122);

}

let str = '';

for(let code of generatePasswordCodes()) {
  str += String.fromCharCode(code);
}

alert(str); // 0..9A..Za..z

 

 

 

 

 

yield를 사용해 제너레이터 안밖으로 정보 교환하기

function* gen() {
  // 질문을 제너레이터 밖 코드에 던지고 답을 기다립니다.
  let result = yield "2 + 2 = ?"; // (*)

  alert(result);
}

let generator = gen();

let question = generator.next().value; // <-- yield는 value를 반환합니다.

generator.next(4); // --> 결과를 제너레이터 안으로 전달합니다.
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

: next를 통해 value가 next의 값과 같은 yield의 다음 yield를 반환

 

 

 

 

generator.throw

: 에러 핸들링

function* generate() {
  let result = yield "2 + 2 = ?"; // Error in this line
}

let generator = generate();

let question = generator.next().value;

try {
  generator.throw(new Error("데이터베이스에서 답을 찾지 못했습니다."));
} catch(e) {
  alert(e); // 에러 출력
}

 

 

 

 

Refference

 

제너레이터

 

ko.javascript.info

 

300x250
728x90