프로미스는 비동기 상태를 값으로 다룰 수 있는 객체이다.
프로미스를 사용하면 비동기 프로그래밍을 할 때 동기 프로그래밍 방식으로 코드를 작성할 수 있다.
자바스크립트에서는 비동기 프로그래밍의 한가지 방식으로 콜백 패턴을 많이 사용했다.
콜백 패턴의 단점:
프로미스의 세 가지 상태 :
이행됨, 거부됨 상태를 처리됨(settled) 상태라고 부른다.
프로미스는 처리됨의 상태가 되면 더이상 다른 상태로 변경되지 않는다.
대기중 상태일 때만 이행됨 또는 거부됨 상태로 변할 수 있다.
첫번째 방법 : new 키워드를 사용해서 생성한다.
이 방법으로 생성된 프로미스는 대기중 상태가 된다.
생성자에 입력되는 함수는 resolve와 reject 라는 콜백 함수를 매개변수로 갖는다.
비동기로 어떤 작업을 수행후 성공했을 때는 resolve(이행됨), 실패했을 때 reject를 호출한다.(거부됨)
new 키워드를 사용해서 프로미스를 생성하는 순간 생성자의 입력 함수가 실행된다.
API 요청을 보내는 비동기 코드가 있다면 프로미스가 생성되는 순간에 요청을 보낸다.
const p1 = new Promise((resolve, reject)=>{
// ...
// resolve(data)
// or reject('error message')
});
두번째 방법 : Promise.reject를 호출한다.
Promise.reject를 호출하면 거부됨 상태인 프로미스가 생성된다.
const p2 = Promise.reject('error message');
세번째 방법 : Promise.resolve를 호출한다.
Promise.resolve를 호출하면 이행됨 상태인 프로미스가 생성된다.
입력값이 프로미스였다면 그 객체가 그대로 반환되고, 아니라면 이행됨 상태인 프로미스가 반환한다.

첫번째는 프로미스가 아닌 인수와 함께 Promise.resolve 함수를 호출하면 그 값 그대로 이행됨 상태인 프로미스가 반환된다.
두번째는 Promise.resolve 함수에 프로미스가 입력되면 그 자신이 반환된다.
then은 처리됨 상태가 된 프로미스를 처리할 때 사용되는 메서드이다.
프로미스가 처리됨 상태가 되면 then 메서드의 인수로 전달된 함수가 호출된다.

catch는 프로미스 수행 중 발생한 예외를 처리하는 메서드이다.
catch메서드는 then 메서드의 onReject와 같은 역할을 한다.
예외처리는 then 메서드의 onReject보다 catch메서드를 이용하는게 가독성 면에서 더 좋다.

then 메서드의 onResolve함수에서 발생한 예외 같은 then메서드의 onReject함수에서 처리되지 않는다.
Unhandled promise rejection 에러가 발생하는데 거부됨 상태인 프로미스를 처리하지 않았기 때문이다.

프로미스에서 예외 처리를 할 땐 then메서드의 onReject함수보다는 좀더 직관적인 catch메서드를 이용하는게 좋다.
then 메서드와 마찬가지로 catch 메서드도 새로운 프로미스를 반환한다.
catch 메서드 이후에도 계속해서 then메서드를 사용할 수 있다.
finally는 프로미스가 이행됨 또는 거부됨 상태일 때 호출되는 메서드다.
finally 메서드는 프로미스 체인의 가장 마지막에 사용된다.
finally 메서드는 .then(onFinally, onFinally) 코드와 유사 하지만 이전에 사용된 프로미스를 그대로 반환한다는 점이 다르다.
처리됨 상태인 프로미스의 데이터를 건드리지 않고 추가작업을 할때 유용히 사용될 수 있다.
Promise.all 은 여러 개의 프로미스를 병렬로 처리할때 사용하는 함수이다.
then 메서드를 이용하면 비동기 처리가 병렬로 처리되지 않는다.
비동기 함수 간에 서로 의존성이 없다면 병렬로 처리하는게 더 빠르다


Promise.all 함수는 프로미스를 반환한다.
Promise.all함수가 반환하는 프로미스는 입력된 모든 프로미스가 처리됨 상태가 되어야 마찬가지로 처리됨 상태가 된다.
만약 하나라도 거부됨 상태가 된다면 Promise.all함수가 반환하는 프로미스도 거부됨 상태가 된다.
Promise.race는 여러 개의 프로미스 중에서 가장 빨리 처리된 프로미스를 반환하는 함수다.
Promise.race 함수에 입력된 여러 프로미스 중에서 하나라도 처리됨 상태가 되면, Promise.race가 함수가 반환하는 프로미스도 처리됨 상태가 된다.

requestData 함수가 3초안에 데이터를 받으면 then메서드가 호출되고 그렇지 않으면 catch메서드가 호출된다.
처리됨 상태가 되면 그 상태를 유지하는 프로미스의 성질을 이용해서 데이터를 캐싱할 수 있다.

getData() 함수를 처음 호출할 때만 requestData가 호출된다.
데이터를 가져오는 작업이 끝나면 cachedPromise에 저장된다.
then 메서드가 반환하는 프로미스 객체의 데이터는 내부함수가 반환한 값이다.
return 키워드를 사용하지 않으면 프로미스 객체의 데이터는 undefined가 된다.


프로미스는 불변 객체이다.


프로미스를 중첩해서 사용하면 콜백 패턴처럼 코드가 복잡해지므로 사용을 권하지 않는다.
Promise.all 함수를 사용하면 프로미스를 중첩하지 않고도 해결할 수 있다.
Promise.all 함수로 입력하는 배열에 프로미스가 아닌 값을 넣으면 그값 그대로 이행됨 상태인 프로미스처럼 처리된다.
프로미스를 동기(sync) 코드와 같이 사용할 때는 예외처리에 신경 써야 한다.
doSync() 함수가 반드시 fetch전에 호출되어야 하는게 아니라면 then 메서드 안쪽으로 넣어주는 게 좋다.
doSync에서 발생하는 예외는 catch 메서드에서 처리가 된다.
async await는 비동기 프로그래밍을 동기 프로그래밍처럼 작성할 수 있도록 함수에 추가된 기능이다.
프로미스의 then 메서드를 체인형식으로 호출하는 것보다 가독성이 좋아진다.
하지만 async await가 프로미스를 완전히 대체하는 것은 아니다.
프로미스는 객체로 존재하지만 async await은 함수에 적용되는 개념이다.
async키워드를 이용해서 정의된 함수는 async await 함수이고 항상 프로미스를 반환한다.
함수호출후 then메서드를 사용할 수 있다.
프로미스의 then 메서드처럼 async await 함수 내부에서 프로미스를 반환하는 값이 프로미스라면 그 객체를 그대로 반환한다.
async await 함수 내부에서 예외가 발생하는 경우에는 거부됨 상태인 프로미스가 반환된다.
await 키워드는 async await 함수 내부에서 사용된다.
await 키워드 오른쪽에 프로미스를 입력하면 그 프로미스가 처리됨 상태가 될때까지 기다린다.
await 키워드로 비동기 처리를 기다리면서 순차적으로 코드를 작성할 수 있다
requestData 함수가 반환하는 프로미스가 처리됨 상태가 될때까지 console.log(data1, data2)는 출력되지 않는다.
await 키워드는 async 키워드 없이는 사용할 수 없다.
async await와 프로미스는 비동기 프로그래밍을 동기 프로그래밍 방식으로 작성할 수 있게 해준다.
위에는 프로미스로 밑에는 async await으로 작성한 함수다.
async await 함수는 then 메서드를 호출할 필요가 없기 때문에 더 간결하다.
비동기 함수간의 의존성이 높아질 수록 async await와 프로미스의 가독성 차이가 더 선명하게 드러난다.

두 함수 사이에 의존성이 없다면 동시에 실행하는게 더 좋다.
두개의 프로미스를 먼저 생성하고 await 키워드를 나중에 사용하면 병렬로 실행하는 코드가 된다.


async await 함수 내부에서 발생하는 예외는 try catch문으로 처리하는게 좋다.
비동기와 동기 함수에서 발생하는 모든 예외가 catch문에서 처리된다
getData가 async await 함수가 아니었으면 doAsync 함수에서 발생하는 예외는 catch문에서 처리되지 않는다. => doAsync함수의 처리가 끝나는 시점을 알 수 없기 때문이다.
Thenable은 프로미스처럼 동작하는 객체다.
async await는 ES6 프로미스가 아니더라도 then 메서드를 가진 객체를 프로미스처럼 취급한다.
ES6의 프로미스가 아니더라도 then 메서드를 가진 객체를 Thenable이라고 부른다.

템플릿 리터럴은 변수를 이용해서 동적으로 문자열을 생성할 수 있는 문법이다.
탬플릿 리터럴은 백틱(``)을 이용한다. 표현식을 사용할때는 ${expression}형식으로 입력한다.

태그된 템플릿 리터럴은 템플릿 리터럴을 확장한 기능이다.
테그된 템플릿 리터럴은 함수로 정의된다.
사용할 땐 함수명과 함께 템플릿 리터럴을 붙여서 작성한다.