유초23 2024. 1. 22. 21:14
728x90

* [42장 비동기 프로그래밍]    >    [p.809 ~ p.815]

 

<42.1 동기 처리와 비동기 처리>

- 실행 컨텍스트 스택은 아래와 같은 순서로 실행된다.

 

- 콜스택은 아래와 같이 동작하는것을 볼 수 있다.

-> push 순서

-> pop 순서

 

- 실행 컨텍스트 스택에 함수 실행 컨텍스트가 푸시되는 것은 바로 함수 실행의 시작을 의미한다.

- 함수가 호출된 순서대로 순차적으로 실행되는 이유는 함수가 호출된 순서대로 함수 실행 컨텍스트가 실행 컨텍스트 스택에 푸시되기 때문이다.

- 이처럼 함수의 실행 순서는 실행 컨텍스트 스택으로 관리한다.

- 자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택을 갖는다. 

- 이처럼 자바스크립트 엔진은 한 번에 하나의 태스크만 실행할 수 있는 싱글 스레드 방식으로 동작한다. 그렇기 때문에 처리에 시간이 걸리는 태스크를 실행하는 경우, 블로킹(작업 중단)이 발생한다.

 

- 동기 처리란 ? 현재 실행 중인 태스크가 종료할 때까지 다음에 실행될 태스크가 대기하는 방식

- 동기 처리의 예시

// sleep 함수는 일정 시간(delay)이 경과한 이후에 콜백 함수(func)를 호출한다.
function sleep(func, delay) {
  // Date.now()는 현재 시간을 숫자(ms)로 반환한다.("30.2.1. Date.now" 참고)
  const delayUntil = Date.now() + delay;

  // 현재 시간(Date.now())에 delay를 더한 delayUntil이 현재 시간보다 작으면 계속 반복한다.
  while (Date.now() < delayUntil);
  // 일정 시간(delay)이 경과한 이후에 콜백 함수(func)를 호출한다.
  func();
}

function foo() {
  console.log('foo');
}

function bar() {
  console.log('bar');
}

// sleep 함수는 3초 이상 실행된다..
sleep(foo, 3 * 1000);
// bar 함수는 sleep 함수의 실행이 종료된 이후에 호출되므로 3초 이상 블로킹된다.
bar();
// (3초 경과 후) foo 호출 -> bar 호출

 

- 비동기 처리란 ? 현재 실행중인 태스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행하는 방식

- 비동기 처리의 예시

function foo() {
  console.log('foo');
}

function bar() {
  console.log('bar');
}

// 타이머 함수 setTimeout은 일정 시간이 경과한 이후에 콜백 함수 foo를 호출한다.
// 타이머 함수 setTimeout은 bar 함수를 블로킹하지 않는다.
setTimeout(foo, 3 * 1000);
bar();
// bar 호출 -> (3초 경과 후) foo 호출

- 타이머 함수인 setTimeout과 setInterval, HTTP 요청, 이벤트 핸들러는 비동기 처리 방식으로 동작한다.

 

<42.2 이벤트 루프와 태스크 큐>

- 자바스크립트의 동시성을 지원하는 것은 이벤트 루프이다. 이는 브라우저에 내장되어 있는 기능 중 하나이다. 

 

- 자바스크립트 엔진은 크게 [콜 스택]과 [힙] 2개의 영역으로 구분할 수 있다.

- [콜 스택] : 함수를 호출하면 함수 실행 컨텍스트가 순차적으로 콜 스택에 푸시되어 순차적으로 실행되고, 최상위 실행 컨텍스트(실행중인 실행 컨텍스트)가 종료되어 콜 스택에서 제거되기 전까지는 다른 어떤 태스크도 실행되지 않는다.

- [힙] : 객체가 저장되는 메모리 공간이다. 콜 스택의 요소인 실행 컨텍스트는 힙에 저장된 객체를 참조한다. 객체는 할당해야 할 메모리 공간의 크기를 런타임에 결정(동적 할당)해야 한다. 따라서 힙은 구조화되어 있지 않다는 특징이 있다.

 

- 비동기 처리에서 소스코드의 평가와 실행을 제외한 모든 처리는 자바스크립트 엔진을 구동하는 환경인 브라우저 또는 Node.js가 담당한다. 브라우저 환경은 [태스크 큐]와 [이벤트 루프]를 제공한다.

- [태스크 큐] : 비동기 함수의 콜백 함수 또는 이벤트 핸들러가 일시적으로 보관되는 영역이다. 

- [이벤트 루프] : 콜 스택에 현재 실행 중인 실행 컨텍스트가 있는지, 그리고 태스크 큐에 대기 중인 함수(콜백 함수, 이벤트 핸들러 등)가 있는지 반복해서 확인한다. 이는 순차적(FIFO 방식)으로 함수들을 이동시키고, 비동기 처리 방식으로 동작한다.

 

- 아래 예제의 설명을 읽는 것을 추천 ! 아주 잘 정리가 되어있다 !

function foo() {
  console.log('foo');
}

function bar() {
  console.log('bar');
}

setTimeout(foo, 0); // 0초(실제는 4ms) 후에 foo 함수가 호출된다.
bar();

 

- 자바스크립트 엔진은 싱글 스레드로 동작하지만, 브라우저는 멀티 스레드로 동작한다.

- 브라우저는 자바스크립트 엔진 외에도 렌더링 엔진과 Web API를 제공한다.


* [45장 프로미스]    >    [p.842 ~ p.869]

 

<45.1 비동기 처리를 위한 콜백 패턴의 단점>

- 비동기 함수를 호출하면 함수 내부의 비동기로 동작하는 코드가 완료되지 않았다 해도 기다리지 않고 즉시 종료된다.

- 비동기 함수 내부의 비동기로 동작하는 코드는 비동기 함수가 종료된 이후에 완료된다.

- 따라서 비동기 함수 내부의 비동기로 동작하는 코드에서 처리 결과를 외부로 반환하거나 상위 스코프의 변수에 할당하면 기대한 대로 동작하지 않는다.

- 첫번째 예시로는 setTimeout 함수가 있는데, setTimeout 함수가 비동기 함수인 이유는 콜백 함수의 호출이 비동기로 동작하기 때문이다. 비동기 함수인 setTimeout 함수의 콜백 함수는 setTimeout 함수가 종료된 이후에 호출되기 때문에 setTimeout 함수 내부의 콜백함수에서 처리 결과를 외부로 반환하거나 상위 스코프의 변수에 할당하면 기대한 대로 동작하지 않는다.

- 두번째 예시로는 GET 함수가 있는데, GET 함수가 비동기 함수인 이유는 GET 함수 내부의 onload 이벤트 핸들러가 비동기로 동작하기 때문이다. 비동기 함수인 GET 함수 내부의 onload 이벤트 핸들러는 GET 함수가 종료된 이후에 실행되기 때문에 GET 함수의 onload 이벤트 핸들러에서 서버의 응답 결과를 외부로 반환하거나 상위 스코프의 변수에 할당하면 기대한 대로 동작하지 않는다.

 

- 아래의 코드는 GET 요청을 위한 비동기 함수인데, 설명이 잘 이해가 되지는 않는다 ㅠ

// GET 요청을 위한 비동기 함수
const get = url => {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.send();

  xhr.onload = () => {
    if (xhr.status === 200) {
      // ① 서버의 응답을 반환한다.
      return JSON.parse(xhr.response);
    }
    console.error(`${xhr.status} ${xhr.statusText}`);
  };
};

// ② id가 1인 post를 취득
const response = get('https://jsonplaceholder.typicode.com/posts/1');
console.log(response); // undefined

- 여기에서 xhr.onload 이벤트 핸들러 프로퍼티에 바인딩한 이벤트 핸들러의 반환문은 GET 함수의 반환문이 아니고, GET 함수는 반환문이 생략되었으므로 암묵적으로 undefined를 반환한다. 그리고 이 코드에서 onload 이벤트 핸들러의 반환값은 캐치할 수 없다.

 

- 다음 예시는 서버의 응답을 상위 스코프의 변수에 할당한 것이다.

let todos;

// GET 요청을 위한 비동기 함수
const get = url => {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.send();

  xhr.onload = () => {
    if (xhr.status === 200) {
      // ① 서버의 응답을 상위 스코프의 변수에 할당한다.
      todos = JSON.parse(xhr.response);
    } else {
      console.error(`${xhr.status} ${xhr.statusText}`);
    }
  };
};

// id가 1인 post를 취득
get('https://jsonplaceholder.typicode.com/posts/1');
console.log(todos); // ② undefined

- 여기에서는 xhr.onload 이벤트 핸들러 프로퍼티에 바인딩한 이벤트 핸들러는 언제나 ② console.log가 종료한 이후에 호출되기 때문에 기대한 대로 결과값이 나오지 않는다. 

- xhr.onload 이벤트 핸들러는 load 이벤트가 발생하면 일단 태스크 큐에 저장되어 대기하다가, 콜 스택이 비면 이벤트 루프에 의해 콜 스택으로 푸시되어 실행된다.

 

- 비동기 함수를 범용적으로 사용하기 위해 비동기 함수에 비동기 처리 결과에 대한 후속 처리를 수행하는 콜백 함수를 전달하는것이 일반적이다.

- 콜백 헬 이란 ? 콜백 함수를 통해 비동기 처리 결과에 대한 후속 처리를 수행하는 비동기 함수가 비동기 처리 결과를 가지고 또다시 비동기 함수를 호출해야 한다면 콜백 함수 호출이 중첩되어 복잡도가 높아지는 현상이 발생하는 것

- 콜백 헬이 발생하는 전형적인 사례

get('/step1', a => {
  get(`/step2/${a}`, b => {
    get(`/step3/${b}`, c => {
      get(`/step4/${c}`, d => {
        console.log(d);
      });
    });
  });
});

 

- 에러 처리를 구현하는 방법으로 try...catch...finally문이 있다.

- 콜백 패턴은 콜백 헬이나 에러 처리가 곤란하다는 문제가 있기 때문에 그를 극복하기 위해 프로미스 함수가 도입되었다.

 

<45.2 프로미스의 생성>

- Promise 생성자 함수의 예시

// 프로미스 생성
const promise = new Promise((resolve, reject) => {
  // Promise 함수의 콜백 함수 내부에서 비동기 처리를 수행한다.
  if (/* 비동기 처리 성공 */) {
    resolve('result');
  } else { /* 비동기 처리 실패 */
    reject('failure reason');
  }
});

 

- 프로미스의 상태

프로미스의 상태 정보 의미 상태 변경 조건
pending 비동기 처리가 아직 수행되지 않은 상태 프로미스가 생성된 직후 기본 상태
fulfilled 비동기 처리가 수행된 상태(성공) resolve 함수 호출
rejected 비동기 처리가 수행된 상태(실패) reject 함수 호출

- 이처럼 프로미스의 상태는 resolve 또는 reject 함수를 호출하는 것으로 결정된다.

 

- fulfilled  또는 reject 상태를 settled 상태라고 하고, 이는 pending이 아닌 상태로 비동기 처리가 수행된 상태를 말한다.

- 프로미스는 비동기 처리 상태와 처리 결과를 관리하는 객체다.

 

<45.3 프로미스의 후속 처리 메서드>

- 프로미스는 후속 메서드 then, catch, finally를 제공한다.

- 프로미스의 비동기 처리 상태가 변화하면 후속 처리 메서드에 인수로 전달한 콜백 함수가 선택적으로 호출되고, 모든 후속 처리 메서드는 프로미스를 반환하며, 비동기로 동작한다.

 

- then 메서드는 두 개의 콜백 함수를 인수로 전달받는다.

// fulfilled
new Promise(resolve => resolve('fulfilled'))
  .then(v => console.log(v), e => console.error(e)); // fulfilled

// rejected
new Promise((_, reject) => reject(new Error('rejected')))
  .then(v => console.log(v), e => console.error(e)); // Error: rejected

 

- catch 메서드는 한 개의 콜백 함수를 인수로 전달받는다. 아래 두 예시는 동일하게 동작한다.

// rejected
new Promise((_, reject) => reject(new Error('rejected')))
  .catch(e => console.log(e)); // Error: rejected
// rejected
new Promise((_, reject) => reject(new Error('rejected')))
  .then(undefined, e => console.log(e)); // Error: rejected

 

- finally 메서드는 한 개의 콜백 함수를 인수로 전달받는다. 이는 프로미스의 상태와 상관없이 공통적으로 수행해야 할 처리 내용이 있을 때 유용하다.

new Promise(() => {})
  .finally(() => console.log('finally')); // finally

 

<45.4 프로미스의 에러 처리>

- 에러 처리는 then 메서드에서 하지 말고 catch 메서드에서 하는 것을 권장한다.

promiseGet('https://jsonplaceholder.typicode.com/todos/1')
  .then(res => console.xxx(res))
  .catch(err => console.error(err)); // TypeError: console.xxx is not a function

 

<45.5 프로미스 체이닝>

- 프로미스 체이닝 이란 ? then, catch, finally 후속 처리 메서드는 언제나 프로미스를 반환하므로 연속적으로 호출 할 수 있다는 뜻이다.

- 프로미스는 프로미스 체이닝을 통해 비동기 처리 결과를 전달받아 후속 처리를 하므로 비동기 처리를 위한 콜백 패턴에서 발생하던 콜백 헬이 발생하지 않는다. 다만 프로미스도 콜백 패턴을 사용하므로 콜백 함수를 사용하지 않는것은 아니다.

- 콜백 패턴에서 발생하는 문제는 async/await에서 해결할 수 있다.

 

=> 여기에서 4주차 테스트에 나왔던 '글자 읽기' 문제가 생각나서 다시 한번 찾아보면 좋을 것 같다 !

 

<45.6 프로미스의 정적 메서드>

- Promise는 5가지 정적 메서드를 제공한다.

 

- 1. Promise resolve

const resolvedPromise = new Promise(resolve => resolve([1, 2, 3]));
resolvedPromise.then(console.log); // [1, 2, 3]

 

- 2. Promise.reject

const rejectedPromise = new Promise((_, reject) => reject(new Error('Error!')));
rejectedPromise.catch(console.log); // Error: Error!

 

- 3. Promise.all : 여러 개의 비동기 처리를 모두 병렬 처리할 때 사용한다.

const requestData1 = () => new Promise(resolve => setTimeout(() => resolve(1), 3000));
const requestData2 = () => new Promise(resolve => setTimeout(() => resolve(2), 2000));
const requestData3 = () => new Promise(resolve => setTimeout(() => resolve(3), 1000));

Promise.all([requestData1(), requestData2(), requestData3()])
  .then(console.log) // [ 1, 2, 3 ] ⇒ 약 3초 소요
  .catch(console.error);

- Promise.all 메서드는 인수로 전달받은 배열의 모든 프로미스가 모두 fulfilled 상태가 되면 종료한다.

- 위 예제의 경우 모든 처리에 걸리는 시간은 가장 늦게 fulfilled 상태가 되는 첫 번째 프로미스의 처리 시간인 3초보다 조금 더 소요된다.

 

- Promise.all 메서드는 인수로 전달받은 배열의 프로미스가 하나라도 rejected 상태가 되면 나머지 프로미스가 fulfilled 상태가 되는 것을 기다리지 않고 즉시 종료한다.

Promise.all([
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 1')), 3000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 2')), 2000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 3')), 1000))
])
  .then(console.log)
  .catch(console.log); // Error: Error 3

 

- 4. Promise.race

- Promise.all 메서드와 동일하게 프로미스를 요소로 갖는 배열 등의 이터러블을 인수로 전달받는다.

- 하지만 모든 프로미스가 fulfilled 상태가 되는 것을 기다리는 것이 아니라 가장 먼저 fulfilled 상태가 된 프로미스의 처리 결과를 resolve하는 새로운 프로미스를 반환한다.

Promise.race([
  new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
  new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
  new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
])
  .then(console.log) // 3
  .catch(console.log);

 

- 프로미스가 rejected 상태가 되면 Promise.all 메서드와 동일하게 처리된다.

Promise.race([
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 1')), 3000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 2')), 2000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 3')), 1000))
])
  .then(console.log)
  .catch(console.log); // Error: Error 3

 

- 5. Promise.allSettled

- 프로미스를 요소로 갖는 배열 등의 이터러블을 인수로 전달받는다.

- 그리고 전달받은 프로미스가 모두 settled 상태(비동기 처리가 수행된 상태, 즉 fulfilled 또는 rejected 상태)가 되면 처리 결과를 배열로 반환한다.

Promise.allSettled([
  new Promise(resolve => setTimeout(() => resolve(1), 2000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error!')), 1000))
]).then(console.log);
/*
[
  {status: "fulfilled", value: 1},
  {status: "rejected", reason: Error: Error! at <anonymous>:3:54}
]
*/

- Promise.allsettled 메서드가 반환한 배열에는 fulfilled 또는 rejected 상태와는 상관없이 Promise.allsettled 메서드가 인수로 전달받은 모든 프로미스들의 처리 결과가 모두 담겨있다.

 

<45.7 마이크로태스크 큐>

- 아래의 예제는 2 -> 3 -> 1의 순서로 출력된다.

setTimeout(() => console.log(1), 0);

Promise.resolve()
  .then(() => console.log(2))
  .then(() => console.log(3));

- 마이크로태스크 큐에는 프로미스의 후속 처리 메서드의 콜백 함수가 일시 저장된다. 그 외의 비동기 함수의 콜백 함수나 이벤트 핸들러는 태스크 큐에 일시 저장된다.

- 마이크로태스크 큐는 태스크큐보다 우선순위가 높다.

 

<45.8 fetch>

- HTTP 요청 전송 기능을 제공하는 클라이언트 사이드 Web API다.

const promise = fetch(url, [, options])

- fetch 함수는 HTTP 응답을 나타내는 Response 객테를 래핑한 Promise 객체를 반환한다.

- fetch 함수를 사용할 때는 fetch 함수가 반환한 프로미스가 resolve한 불리언 타입의 ok 상태를 확인해 명시적으로 에러를 처리할 필요가 있다.

 

- 1. GET 요청

request.get('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => {
    if (!response.ok) throw new Error(response.statusText);
    return response.json();
  })
  .then(todos => console.log(todos))
  .catch(err => console.error(err));
// {userId: 1, id: 1, title: "delectus aut autem", completed: false}

 

- 2. POST 요청

request.post('https://jsonplaceholder.typicode.com/todos', {
  userId: 1,
  title: 'JavaScript',
  completed: false
}).then(response => {
    if (!response.ok) throw new Error(response.statusText);
    return response.json();
  })
  .then(todos => console.log(todos))
  .catch(err => console.error(err));
// {userId: 1, title: "JavaScript", completed: false, id: 201}

 

- 3. PATCH 요청

request.patch('https://jsonplaceholder.typicode.com/todos/1', {
  completed: true
}).then(response => {
    if (!response.ok) throw new Error(response.statusText);
    return response.json();
  })
  .then(todos => console.log(todos))
  .catch(err => console.error(err));
// {userId: 1, id: 1, title: "delectus aut autem", completed: true}

 

- 4. DELETE 요청

request.delete('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => {
    if (!response.ok) throw new Error(response.statusText);
    return response.json();
  })
  .then(todos => console.log(todos))
  .catch(err => console.error(err));
// {}

* [46장 제너레이터와 async/await]    >    [p.870 ~ p.885]

 

<46.1 제너레이터란?>

- 제너레이터 함수는 함수 호출자에게 함수 실행의 제어권을 양도할 수 있다.

- 제너레이터 함수는 함수 호출자와 함수의 상태를 주고받을 수 있다.

- 제너레이터 함수를 호출하면 제너레이터 객체를 반환한다.

 

<46.2 제너레이터 함수의 정의>

- 제너레이터 함수는 function* 키워드로 선언하고, 하나 이상의 yield 표현식을 포함한다.

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

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

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

// 제너레이터 클래스 메서드
class MyClass {
  * genClsMethod() {
    yield 1;
  }
}

- 제너레이터 함수는 화살표 함수로 정의할 수 없고, new 연산자와 함께 생성자 함수로 호출할 수 없다.

 

<46.3 제너레이터 객체>

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

- next 메서드, return 메서드, throw 메서드의 결과값이 어떻게 나오는지 알 수 있다.

 

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

- yield 키워드는 제너레이터 함수의 실행을 일시 중지시키거나 yield 키워드 뒤에 오는 표현식의 평가 결과를 제너레이터 함수 호출자에게 반환한다.

- 제너레이터 객체의 next 메서드를 호출하면 yield 표현식까지 실행되고 일시중지된다. 이때 함수의 제어권이 호출자로 양도된다.

// 제너레이터 함수
function* genFunc() {
  yield 1;
  yield 2;
  yield 3;
}

// 제너레이터 함수를 호출하면 제너레이터 객체를 반환한다.
// 이터러블이면서 동시에 이터레이터인 제너레이터 객체는 next 메서드를 갖는다.
const generator = genFunc();

// 처음 next 메서드를 호출하면 첫 번째 yield 표현식까지 실행되고 일시 중지된다.
// next 메서드는 이터레이터 리절트 객체({value, done})를 반환한다.
// value 프로퍼티에는 첫 번째 yield 표현식에서 yield된 값 1이 할당된다.
// done 프로퍼티에는 제너레이터 함수가 끝까지 실행되었는지를 나타내는 false가 할당된다.
console.log(generator.next()); // {value: 1, done: false}

// 다시 next 메서드를 호출하면 두 번째 yield 표현식까지 실행되고 일시 중지된다.
// next 메서드는 이터레이터 리절트 객체({value, done})를 반환한다.
// value 프로퍼티에는 두 번째 yield 표현식에서 yield된 값 2가 할당된다.
// done 프로퍼티에는 제너레이터 함수가 끝까지 실행되었는지를 나타내는 false가 할당된다.
console.log(generator.next()); // {value: 2, done: false}

// 다시 next 메서드를 호출하면 세 번째 yield 표현식까지 실행되고 일시 중지된다.
// next 메서드는 이터레이터 리절트 객체({value, done})를 반환한다.
// value 프로퍼티에는 세 번째 yield 표현식에서 yield된 값 3이 할당된다.
// done 프로퍼티에는 제너레이터 함수가 끝까지 실행되었는지를 나타내는 false가 할당된다.
console.log(generator.next()); // {value: 3, done: false}

// 다시 next 메서드를 호출하면 남은 yield 표현식이 없으므로 제너레이터 함수의 마지막까지 실행한다.
// next 메서드는 이터레이터 리절트 객체({value, done})를 반환한다.
// value 프로퍼티에는 제너레이터 함수의 반환값 undefined가 할당된다.
// done 프로퍼티에는 제너레이터 함수가 끝까지 실행되었음을 나타내는 true가 할당된다.
console.log(generator.next()); // {value: undefined, done: true}

 

<46.5 제너레이터의 활용>

- 제너레이터 함수를 사용하면 이터레이션 프로토콜을 준수해 이터러블을 생성하는 방식보다 간단히 이터러블을 구현할 수 있다.

- 제너레이터 함수는 프로미스의 후속 처리 메서드 then/catch/finally 없이 비동기 처리 결과를 반환하도록 구현할 수 있다.

 

<46.6 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);
  // {userId: 1, id: 1, title: 'delectus aut autem', completed: false}
}

fetchTodo();

- await 키워드는 반드시 async 함수 내부에서 사용해야 한다.

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

- await 키워드는 프로미스가 settled 상태(비동기 처리가 수행된 상태)가 될 때까지 대기하다가 settled 상태가 되면 프로미스가 resolve한 처리 결과를 반환한다. 

- async/await에서 에러 처리는 try...catch 문을 사용할 수 있다.

- async 함수 내에서 catch문을 사용해서 에러 처리를 하지 않으면 async 함수는 발생한 에러를 reject하는 프로미스를 반환한다.

 

 

728x90