제너레이터와 async/await

ken6666·2024년 5월 8일
0

JS

목록 보기
37/39

제너레이터란?

  1. 제네레이터 함수는 함수 호출자에게 함수 실행의 제어권을 양도할 수 있다.
    • 함수의 제어권을 함수가 독점하는 것이 아니라 함수 호출자에게 양도(yield)할 수 있다.
  2. 제네레이터 함수는 함수 호출자와 함수의 상태를 주고받을 수 있다.
    • 제네레이터 함수는 함수 호출자에게 상태를 전달할 수 있고 함수 호출자로부터 상태를 전달받을 수도 있다.
  3. 제네레이터 함수를 호출하면 제네레이터 객체를 반환한다.
    • 제너레이터 함수를 호출하면 함수 코드를 실행하는 것이 아니라 이터러블이면서 동시에 이터레이터인 제너레이터 객체를 반환한다.

제너레이터 함수의 정의

// 제너레이터 함수 선언문
function* genDecFunc() {
  yield 1;
}

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

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

// 제너레이터 클래스 메서드
class MyClass {
  * genClsMethod() {
    yield 1;
  }
}
  • (*)의 위치는 function 키워드와 함수 이름 사이라면 어디든지 상관없다.
const genArrowFunc = * () => {
  yield 1;
}; // SyntaxError: Unexpected token '*'


function* genFunc() {
  yield 1;
}

new genFunc(); // TypeError: genFunc is not a constructor
  • 화살표 함수로 정의할 수 없다.
  • new 연산자와 함께 생성자 함수로 호출할 수 없다.

제너레이터 객체

function* genFunc() {
  try {
    yield 1;
    yield 2;
    yield 3;
  } catch (e) {
    console.error(e);
  }
}

const generator = genFunc();

console.log(generator.next()); // {value: 1, done: false}
console.log(generator.return('End!')); // {value: "End!", done: true}

제너레이터 함수를 호출하면 일반 함수처럼 함수 코드 블록을 실행하는 것이 아니라 제너레이터 객체를 생성해 반환한다. 제너레이터 함수가 반환한 제너레이터 객체는 이터러블이면서 동시에 이터레이터다.

  • next 메서드를 호출하면 yield 표현식까지 코드블록을 실행하고 이터레이터 리절트 객체를 반환한다.
  • return 메서드를 호출하면 인수로 전달받은 값을 value 프로퍼티 값으로 ture를 done 프로퍼티 값으로 갖는 이터레이터 리적트 객체를 반환한다.
function* genFunc() {
  try {
    yield 1;
    yield 2;
    yield 3;
  } catch (e) {
    console.error(e);
  }
}

const generator = genFunc();

console.log(generator.next()); // {value: 1, done: false}
console.log(generator.throw('Error!')); // {value: undefined, done: true}
  • throw 메서드를 호출하면 인수로 전달받은 에러를 발생시키고 undifined를 value, true를 done 프로퍼티 값으로 값는 이터레이터 리절트 객체를 반환한다.

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

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}

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

res = generator.next(20);
console.log(res); // {value: 30, done: true}
  • yield 키워드는 제너레이터 함수의 실행을 일시 중지시키거나 뒤에 오는 표현식의 평과 결과를 함수 호출자에게 반환한다.

  • next 메서드를 호출하면 yield 표현식까지 실행되고 일시 중지된다. 이때 함수의 제어권이 호출자에게 양도된다.

  • 제너레이터 객체의 next 메서드에 전달한 인수는 제너레이터 함수의 yield 표현식을 할당받는 변수에 할당된다.

async/await

async 함수

// async 함수 선언문
async function foo(n) { return n; }
foo(1).then(v => console.log(v)); // 1

// async 함수 표현식
const bar = async function (n) { return n; };
bar(2).then(v => console.log(v)); // 2

// async 화살표 함수
const baz = async n => n;
baz(3).then(v => console.log(v)); // 3

// async 메서드
const obj = {
  async foo(n) { return n; }
};
obj.foo(4).then(v => console.log(v)); // 4

// async 클래스 메서드
class MyClass {
  async bar(n) { return n; }
}
const myClass = new MyClass();
myClass.bar(5).then(v => console.log(v)); // 5
  • await 키워드는 반드시 async 함수 내부에서 사용해야한다
  • 명시적으로 프로미스를 반환하지 않더라도 async 함수는 암묵적으로 반환값을 resolve 하는 프로미스를 반환한다.
  • 클래스의 construcor 메서드는 async 메서드가 될 수 없다.

await

const fetch = require('node-fetch');

const getGithubUserName = async id => {
  const res = await fetch(`https://api.github.com/users/${id}`); // ①
  const { name } = await res.json(); // ②
  console.log(name); // Ungmo Lee
};

getGithubUserName('ungmo2');
  • await 키워드는 프로미스가 settled 상태가 될때까지 대기하다가 settled 상태가 되면 프로미스가 resolve한 처리 결과를 반환한다
async function foo() {
  const res = await Promise.all([
    new Promise(resolve => setTimeout(() => resolve(1), 3000)),
    new Promise(resolve => setTimeout(() => resolve(2), 2000)),
    new Promise(resolve => setTimeout(() => resolve(3), 1000))
  ]);

  console.log(res); // [1, 2, 3]
}

foo(); // 약 3초 소요된다.
  • 3개의 비동기 처리는 서로 연관이 없이 개별적으로 수행되는 비동기 처리이므로 앞선 비동기 처리가 완료될 때까지 대기해서 순차적으로 처리할 필요가 없다.

에러처리

const fetch = require('node-fetch');

const foo = async () => {
  const wrongUrl = 'https://wrong.url';

  const response = await fetch(wrongUrl);
  const data = await response.json();
  return data;
};

foo()
  .then(console.log)
  .catch(console.error); // TypeError: Failed to fetch
  • async 함수 내에서 catch 문을 사용해서 에러 처릴르 하지 않으면 async 함수는 발생한 에러를 reject하는 프로미스를 반환한다.

0개의 댓글