ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 46장. 제너레이터와 async/await
    책/모던 자바스크립트 딥다이브 2022. 5. 15. 18:47

    46장. 제너레이터와 async/await

    46-1. 제너레이터란?

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

    46-2. 제너레이터 함수의 정의

    • function* 키워드로 선언, 하나 이상의 yield 표현식 포함, 나머지는 일반 함수와 같다.
    // ex
    function* genDecFunc() {
      yield 1;
    }
    
    const genExpFunc = function* () {
      yield 1;
    };
    
    const obj = {
      * getObjMethod() {
        yield 1;
      }
    };
    
    class MyClass {
      * genClsMethod() {
        yield 1;
      }
    }
    
    // (*) 의 위치는 function 키워드와 함수 이름 사이면 상관 없다.
    // 하지만 function 키워드 바로 뒤에 붙이는 것을 권장한다.
    function* genFunc() { yield 1; }
    function * genFunc() { yield 1; }
    function  *genFunc() { yield 1; }
    function *genFunc() { yield 1; }
    function*genFunc() { yield 1; }
    
    // 화살표 함수로 정의할 수 없음.
    const genArrowFunc = * () => { yield 1; } ; // SyntaxError
    
    // new 연산자와 함께 생성자 함수로 호출할 수 없음.
    function* genFunc() {
      yield 1;
    }
    
    new genFunc(); // TypeError
    

    46-3. 제너레이터 객체

    • 제너레이터 함수 호출시 일반 함수처럼 코드 블록 실행하는 것이 아니라 제너레이터 객체를 생성해 반환한다.
    • 제너레이터 객체는 iterable 이면서 동시에 iterator 이다.
    function* genFunc() {
      yield 1;
      yield 2;
    }
    
    const generator = genFunc();
    
    // Symbol.iterator 메서드를 직접 구현하거나 프로토타입 체인을 통해 상속받음.
    console.log(Symbol.iterator in generator); // true
    
    // 이터레이터는 next 메서드를 가짐.
    console.log('next' in generator); // true
    
    • iterator 에는 없는 return, throw 메서드를 갖는다.
    • next 호출:
      1. 제너레이터 함수의 yield 표현식까지 코드 블록 실행
      2. return iterator result: { value: yield된 값, done: false}
    • return 호출:
      1. return iterator result: { value: 인수, done: true}
    • throw 호출:
      1. 인수로 전달 받은 에러 발생시킴
      2. return iterator result: { value: undefined, done: true}
    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}
    console.log(generator.throw('Error')); // {value: undefined, done: true}
    

    46-4. 제너레이터의 일시 중지와 재개

    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}
    
    // 남은 yield 표현식이 없으므로 제너레이터 함수의 마지막까지 실행함.
    console.log(generator.next()); // {value: undefined, done: true}
    
    function* genFunc() {
      // 처음 next 메서드 호출시 첫 번째 yield 표현식까지 실행되고 일시 중지됨.
      // x 변수에는 아직 아무것도 할당되지 않았음. next 메서드가 두 번째 호출될 때 결정됨.
      const x = yield 1;
    
      // 두 번째 next 메서드 호출하며 전달한 인수 10은 x변수에 할당됨.
      // 즉, const x = yield 1; 은 두 번째 next 메서드 호출시 완료됨.
      const y = yield (x + 10);
    
      // 세 번째 next 메서드 호출하며 전달한 인수 20은 y변수에 할당됨.
      // 즉, const y = yield (x + 10); 은 세 번째 next 메서드 호출시 완료됨.
      // 이때 함수의 반환값 x+y 는 next 메서드가 반환한 이터레이터 리절트 객체의 value에 할당됨
      // 제너레이터에서는 값을 반환할 필요가 없고, return은 종료의 의미로만 사용해야함.
      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}
    

    46-5. 제너레이터의 활용

    이터러블의 구현

    // 이터레이션 프로토콜 준수해 생성하는 방식보다 간단히 구현할 수 있음.
    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); // ...
    }
    

    비동기 처리

    • 제너레이터를 활용해서 비동기 처리를 동기처럼 동작하게 하는 코드 예제가 있지만 다음 장에서 async/await 에서 다루므로 생략함.

    46-6. async/await

    • ES8에서 제너레이터보다 간단하고 가독성 좋게 비동기 처리를 동기 처럼 동작하도록 구현할 수 있는 async/await 가 도입되었다.
    • 프로미스를 기반으로 동작한다. 프로미스의 후속 처리 메서드 없이 마치 동기 처리 처럼 프로미스가 처리 결과를 반환하도록 구현할 수 있다.

    async 함수

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

    await 함수

    • await 키워드는 프로미스가 settled 상태가 될 때까지 대기하다가 settled 상태가 되면 프로미스가 resolve한 처리 결과를 반환한다.
    • await 키워드는 반드시 프로미스 앞에서 사용해야 한다.
    • 모든 프로미스에 await 키워드 사용하는 것을 주의해라. 서로 연관이 없이 개별적으로 수행되는 비동기 처리에서는 순차적으로 처리할 필요가 없다. 하지만 비동기 처리의 순서가 보장되어야 할 때는 모든 프로미스에 await 키워드를 사용하여 순차적으로 처리한다.

    에러 처리

    • async/await 에서 에러처리는 try catch 문을 사용할 수 있다.
    // ex. try catch
    const foo = async () => {
      try {
        const wrongUrl = '...';
    
        const response = await fetch(wrongUrl);
        const data = await response.json();
      } catch (e) {
        console.error(e); // fail to fatch
      }
    };
    
    foo();
    
    // ex. 후속처리 메서드 사용
    const foo = async () => {
      const wrongUrl = '...';
    
      const response = await fetch(wrongUrl);
      const data = await response.json();
      return data;
    };
    
    foo()
      .then(console.log)
      .catch(console.error) // fail to fatch
    

    ' > 모던 자바스크립트 딥다이브' 카테고리의 다른 글

    42장. 비동기 프로그래밍  (0) 2022.05.22
    41장. 타이머  (0) 2022.05.22
    45장. 프로미스  (3) 2022.05.14
    44장. REST API  (0) 2022.05.14
    22장. this  (0) 2022.05.09
킹수빈닷컴