if (!response.ok)
오늘은 콜백 지옥을 극복하기 위해 도입된 비동기 기능 중 Promise와 async, await에 대해 배웠다.
또한 네트워크 요청을 보낼 수 있는 API인 fetch의 사용법을 알게 되었다.
기존에 사용하던 콜백 기반의 XMLHttpRequest를 편하게 사용할 수 있도록 Promise 기반으로 개선한 대체제이다.
첫 번째 인자로는 url을, 두 번째 인자로는 객체의 형태로 각종 옵션을 전달할 수 있다.
옵션에 아무것도 넘기지 않으면 자동으로 요청이 GET
으로 진행된다.
응답은 두 단계로 진행된다.
먼저 서버에서 응답 헤더를 받으면 fetch 호출 시 반환받은 promise가 Response
객체와 함께 resolve된다.
다음엔 추가 메서드를 호출해서 본문을 받아 처리한다.
첫 번째 단계에서는 헤더의 status
나 ok
값을 보고 요청의 성공 여부를 판단할 수 있다.
fetch는 네트워크 오류나 서버의 CORS 설정이 잘못된 경우에만 reject한다.
status code 300 이상과 같이 원하는 응답이 아닌 경우에도 resolve를 해서 넘겨버린다.
어쨌든 응답이죠
때문에 헤더의 값을 보고 성공 여부를 판단해서 에러 처리를 해주는 게 필요하다.
ok
는 status 코드가 200번대일 경우에만 true로 나타나는 속성이다.
두 번째 단계에서는 Response
객체에서 본문을 뽑아내서 사용해야한다.
사용하고 싶은 형태에 따라 .text()
, .json()
, .blob()
등의 메서드를 호출한다.
메서드를 한번 호출하면 본문은 처리된 상태가 되기 때문에 다시 호출할 수 없다.
두 단계 모두 비동기적 처리가 필요한데 두 개의 .then
으로 처리할 수도 있고, 두 개의 await
로 처리할 수도 있다.
비동기 작업을 제어하기 위해 나온 개념으로 Callback에 비해 depth 조절이 용이하다.
new Promise(함수)
문법의 생성자로 만들 수 있는데 전달되는 함수는 executor라고 한다.
executor는 인자로 resolve
와 reject
라는 자체적으로 제공되는 콜백을 가진다. executor가 결과를 내면 상황에 맞게 두 콜백 중 하나는 호출되어야 한다.
resolve
의 경우 일이 성공적으로 처리된 경우 결과 값과 함께 호출되고, reject
의 경우 에러가 발생했을 때 에러 객체와 함께 호출된다.
생성자가 반환한 promise
객체는 내부적으로 state
와 result
라는 속성을 갖는다.
처음에는 각각 "pending"
, undefined
의 값을 가지다가 resolve
가 호출되면 "fulfilled"
와 결과 값이 되고, reject
가 호출되면 "rejected"
와 에러 객체가 된다.
executor의 결과로 변화된 두 속성은 아래의 소비함수들을 통해 사용할 수 있다.
.then
의 경우 일반적으로 첫 번째 인자로 함수를 받고, 그 함수는 resolve
를 통해 온 결과 값을 인자로 받는다. 이 함수는 핸들러라고 부른다.
이를 통해 이전 작업이 성공했을 때 수행할 작업을 등록할 수 있다.
두 번째 인자도 함수로 지정해주면 reject
이후의 예외처리 작업도 등록할 수 있다.
.catch
는 .then
에서 두 번째 인자만 전달한 것과 완전히 동일하다.
.finally
는 resolve나 reject 여부와 관계없이 무조건 실행할 작업을 등록하는데 사용한다.
따라서 핸들러가 인자를 받지않아 결과 값이나 에러 객체를 접근할 수는 없다. 다만 뒤로 전달은 해준다.
pass thru~
소비함수도 생성자와 마찬가지로 promise
객체를 반환하므로 쭉 이어서 작업을 처리할 수 있다. 이러한 과정을 promise chaining이라고 한다.
이는 비동기 작업들이 순차적으로 실행되어야 할 때 유용하게 사용할 수 있다.
Callback은 이러한 경우에 depth가 늘어나며 지옥이 열리지만 promise는 뒤로 쭉 늘어쓰면 돼서 depth가 늘어나지 않는다.
chaining이 되어있을 때 reject
로 에러가 발생한 경우 이어진 소비함수 중 이를 처리할 수 있는 가장 가까운 함수로 이동한다. 만약 그런 함수가 없다면 전역 에러로 넘어가서 프로그램이 죽는다.
all
이나 race
같은 Promise 메서드를 통해 여러개의 promise 객체들을 묶어서 처리할 수도 있다.
fetch는 멋모를 때 써본적은 있는 것 같은데 주의할 점이 있다는 건 몰랐었다.
Promise는 콜백보다 낫긴 하지만 여전히 좀 복잡하긴 한 것 같다. catch는 원래 뒤에 하나만 달 수 있는 줄 알았는데 then이랑 섞어서 쓸 수 있다는 건 처음 알았다.
짤 부자 호원님 ㅋㅋ 항상 재미있게 보고 있습니다 ㅎㅎ