모자딥 46장 제너레이터와 async/await

릿·2023년 2월 13일
0

46. 제너레이터와 async/await

46.1 제너레이터란?


  • 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재개할수 있는 특수한 함수

1. 제너레이터와 일반 함수의 차이

  1. 제너레이터 함수는 함수 호출자에게 함수 실행의 제어권을 양도할 수 있음
  2. 제너레이터 함수는 함수 호출자와 함수의 상태를 주고받을 수 있음
  3. 제너레이터 함수를 호추하면 제너레이터 객체를 반환함

46.2. 제너레이터 함수의 정의


  • 제너레이터 함수는 function* 키워드로 선언하고, 하나 이상의 yield 표현식을 포함함
// 제너레이터 함수 선언문
function* genDecFunc() {
  yield 1;
};

// 제너레이터 함수 표현식
const genExpFunc = function* () {
  yield 1;
};

// 제너레이터 메서드
const obj = {
  * genObjMethod() {
    yield 1;
  }
};

// 제너레이터 클래스 메서드
class MyClass {
  * genClsMethod() {
    yield 1;
  }
}
  • 애스터리스크(*)의 위치는 function키워드와 함수 이름 사이라면 어디든지 상관없지만 일관성 유지를 위해 function키워드 바로 뒤에 붙이는 것을 권장함
  • 제너레이터 함수는 화살표 함수와 new연산자와 함께 생성자 함수로 호출할 수 없음

46.3 제너레이터 객체


  • 제너레이터 함수를 호출하면 제너레이터 객체를 생성해 반환
  • 제너레이터 객체는 next메서드를 갖는 이터레이터이지만, 이터레이터에는 없는 return, throw메서드를 가짐
  • next메서드를 호출하면 제너레이터 함수의 yield표현식까지 코드 블록을 실행하고 yield된 값을 value프로퍼티 값으로, false를 done프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환함
  • return메서드를 호출하면 인수로 전달받은 값을 value프로퍼티 값으로, true를 done프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환함
  • throw메서드를 호출하면 인수로 전달받은 에러를 발생시키고, undefined를 value프로퍼티 값으로, true를 done프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환
function* genFunc() {
  try {
    yield 1;
    yield 2;
    yield 3;
  } catch (e) {
    console.error(e);
  }
}

const generator = genFunc();


// return메서드를 활용
console.log(generator.next()); // {value: 1, done: false}
console.log(generator.return('End!')); // {value: 'End!', done: true}

// throw메서드를 활용
console.log(generator.next()); // {value: 1, done: false}
console.log(generator.throw('Error!')); // {value: undefined, done: true}

46.4 제너레이터의 일시 중지와 재개


  • yield키워드는 제너레이터 함수의 실행을 일시 중지시키거나 yield키워드 뒤에 오는 표현식의 평가 결과를 제너레이터 함수 호출자에게 반환함
function* genFunc() {
  yield 1;
  yield 2;
  yield 3;
}

const generator = genFunc();

console.log(generator.next()); // {value: 1, done: false}
console.log(generator.next()); // {value: 2, done: false}
console.log(generator.next()); // {value: 3, done: false}
console.log(generator.next()); // {value: undefined, done: true}
  • 제너레이터 객체의 next메서드에 전달한 인수는 제너레이터 함수의 yield표현식을 할당받는 변수에 할당됨
function* genFunc() {
  const x = yield 1;
  const y = yield (x + 10);
  
  return x + y;
}

const generator = genFunc(0);

let res = generator.next();
console.log(res); {value: 1, done: false}

let res = generator.next(10);
console.log(res); {value: 20, done: false}

46.5 제너레이터의 활용

46.5.1 이터러블의 구현

  • 제너레이터 함수를 사용하면 간단히 이터러블을 구현할 수 있음
  • 예시) 이터레이션 프로토콜을 준수하여 무한 피보나치 수열을 생성하는 함수 구현
const infiniteFibonacci = (function () {
  let [pre, cur] = [0, 1];
  
  return {
    [Symbol.iterator]() { return this; },
    next() {
      [pre, cur] = [cur, pre + cur];
      
      return {value: cur};
    }
  };
}());

for (const num of infiniteFibonacci) {
  if (num > 10000) break;
  console.log(num); // 1 2 3 5 8...
}
  • 제네레이터를 사용하여 구현
const infiniteFibonacci = (function* () {
  let [pre, cur] = [0, 1];
  
  while (true) {
    [pre, cur] = [cur, pre + cur];
    yield cur;
  }
}());

for (const num of infiniteFibonacci) {
  if (num > 10000) break;
  console.log(num); // 1 2 3 5 8...
}

46.6 async/await (ES8)


  • async/await는 프로미스를 기반으로 동작하고, 후속 처리할 필요 없이 마치 동기 처리처럼 프로미스를 사용할 수 있음
const fetch = require('node-fetch');

async function fetchTodo() {
  const url = 'https://jsonplaceholder.typicode.com/todos/1';
  const response = await fetch(url);
  const todo = await response.json();
  console.log(todo);
}

fetchTodo();

46.6.1. async함수

  • async함수는 async키워드를 사용해 정의하며, 언제나 프로미스를 반환함

46.6.2 await 키워드

  • await키워드는 반드시 프로미스 앞에서 사용해야 하고, 프로미스가 settled상태가 될 때까지 대기하다가 settled상태가 되면 프로미스가 resolve한 처리 결과를 반환함

46.6.3 에러처리

  • async/await는 try...catch문을 사용하여 에러 처리를 할 수 있음
  • async함수 내에서 catch문을 통해서 에러 처리를 하지 않으면 async함수는 발생한 에러를 reject하는 프로미스를 반환함
profile
항상 재밌는 뭔가를 찾고 있는 프론트엔드 개발자

0개의 댓글