본문 바로가기

Ecmascript/Javascript

[비동기 처리] generator의 활용 -> function*

generator

  • 함수 실행 중지와 실행 재개가 컨트롤이 가능한 함수
  • function으로 구현하며 함수명 앞에 *이 붙는다.
  • return이 아닌 yield로 값을 반환한다.(중단점 + 값 반환 역할)
  • next()를 호출하면 yield 앞까지의 값이 반환된다.
  • next()의 반환값은 {value: 반환값, done: 제너레이터 함수 끝까지 실행여부}
function * counter() {
 yield 1
 yield 2
 yield 3
}

const g = counter();
console.log(g.next()); // {value: 1, done: false}
console.log(g.next()); // {value: 2, done: false}
console.log(g.next()); // {value: 3, done: false}
console.log(g.next()); // {value: undefined, done: true}

yeild를 활용한 무한루프

  • true로 while을 돌려도 yield라는 중단점때문에 무한루프에 빠지지 않음
function* genAddNum() {
  let i = 0;
  while(true) {
    yield ++i;
  }
}
const gen = genAddNum();
gen.next(); // {value: 1, done: false}
gen.next(); // {value: 2, done: false}
gen.next(); // {value: 3, done: false}
// ... 무한 실행 가능

피보나치 수열 구현

function fnFibonacci(_num){
  function * genFibonacci(_num) {
    let a = 0;
    let b = 1;
    while(true){
      let c = a;
      a = b;
      b = c + a;
      // 위의 3줄을 1줄로 표현하면 [a, b] = [b, a+b];
      yield a
    }
  }

  const fib = genFibonacci();
  const arr = [];
  for(const num of fib) {
    if(num > _num) break;
    arr.push(num)
  }
  return arr;
}

console.log(fnFibonacci(50));

generator 활용한 비동기 처리

  • 제너레이터 함수 내부에서 yield까지만 실행되는 원리를 이용해서 비동기를 순차적으로 실행가능

const fs = require('fs')

function * gen() {
  const a = yield read_gen(g, 'a.txt')
  console.log(a)
  const b = yield read_gen(g, 'b.txt')
  console.log(b)
  const c = yield read_gen(g, 'c.txt')
  console.log(c)
}

// 비동기 처리 완료를 기다리고, 다음 함수를 연속해서 호출하는 함수
function read_gen (_g, fname) {
  fs.readFile(fname, 'utf-8', (err, data) => {
    _g.next(data)
  })
}

const g = gen();
read_gen (gen(), '');

async/await와 비교

  • 그냥 이거 쓰는게 가독성 좋고 난거 같다.

function read_promise(fname) {
  return new Promise((resolve, reject) => {
    fs.readFile(fname, 'utf-8', (err, data) => {
      resolve(data);
    });
  });
}

(async function readAll () {
  const a = await read_promise('a.txt');
  console.log(a);
  const b = await read_promise('b.txt');
  console.log(b);
  const c = await read_promise('c.txt');
  console.log(c);
})();