일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- javscript
- backend
- HTML
- node.js
- Component
- Mongoose
- graphQL
- JavaScript
- 자바스크립트
- NextJs
- CSS
- form
- express
- clonecoding
- frontend
- pug
- Flutter
- ES6
- heroku
- API
- nodejs
- react
- DART
- ECMAScript
- GRID
- CLONE
- 리액트
- Session
- TypeScript
- MongoDB
- Today
- Total
Enjoy Programming
[ES6] Promises 본문
이미 promise에 대해 포스팅을 한적이 있지만 다시 한번 짚고 넘어가자.
promises에 대해 알아보기 전에 먼저 비동기성과 동기성에 대해 생각해보자
& Synchronous 동기식
동기.. 참 어려운 말인듯 하다. 검색을 하다보면 정말 각양각색으로 풀이를 해놨다.
대부분 현재 작업의 요청과 응답이 동시에 발생하는 것이라고 기술하고 있는데 필자가 이해하기에는
동시라고 하기엔 같은 시간에 함께 이루어져야 하므로 혼동이 올 수 밖에 없을 것 같다.
필자가 이해하기에는 현재 요청에 대한 응답이 발생함과 동시에 다음 작업을 요청하는 것?
그렇기에 전 후 순서가 있게 이루어지는 것이 동기식이라 생각된다.
& Asynchronous 비동기식
비동기란 다수의 작업이 동시에 일어날 수 있다는 의미이다.
동기와 다르게 결과가 주어지지 않은 상황이라도 결과가 올때까지 다른 작업을 할 수 있다.
앞서 말한 동기와 반대로 생각하자 현재 요청에 대한 응답과 다음 요청의 타이밍이 일치하지 않아도 된다
자 다시 정리하자 자바스크립트는 기본적으로 싱글스레드 방식의 동기식 언어이다.
하나의 작업이 샐행되는 동안 다른 작업은 멈춘상태를 유지하고 먼저의 작업에 대한 응답이 이루어지면 다른 작업이 이루어진다.
이와 반대로 비동기는 특정 코드의 연산이 끝날 때까지 기다리지 않고, 그동안 다른 코드를 실행할 수 있게 하는것.
그럼 비동기의 예를 하나 들어보자.


google.com을 fetch하는 코드하나와 그냥 something을 출력하는 코드이다.
일반적이라면 그저 위부터 아래로 실행이 되고 fetch를 하지못하면 에러코드가 먼저뜨고 something은 출력되지 않아야한다.
하지만 비동기로 작동을 하여 fetch에대한 요청이 이루어지고 응답이 오는 delay시간동안
something이 출력되고 그 뒤 fetch에 대한 응답이 이루어짐을 볼 수 있다.
이게 바로 비동기식이고 Promises의 기초이다.
그럼 promises는 무엇이고 어떻게 만들까?

mdn을 직역하자면 promise는 비동기식 연산의 최종 완료 또는 실패 그리고 그 결과 값을 나타낸다.
그럼 만들어서 이해해보자. 먼저 promise를 만들기 위해서는 실행할 수 있는 fucntion이 필요하다(excutor function)

이 function에는 두개의 파라미터가 필요한데 바로 resolve, reject이다.

단어 그대로 reject는 거부하는 객체 반환이며, resolve는 이행하는 객체를 반환.


아무 코드도 넣지 않고 이대로 실행해보면 대기중이다.
자바스크립트가 promise가 끝나길 기다리고 있는 것.
그렇다면 어떻게 끝낼 수 있을까. 바로 resolve function을 실행하는 것이다.
자 그럼 인터벌 함수를 활용해서 1초마다 devLte를 띄워주는 코드를 넣어보자

요렇게~ 해주면

먼저 console.log가 devLte를 출력하는데 대기상태인 Promise임을 나타내고 3초간 대기임을 띄우다가
3초가 지난후 매 1초마다 best promise를 출력하는 것을 볼 수있다.
그리고 fulfilled라고 뜨는데 이는 연산이 성공적으로 완료됨을 알려준다.
여기에 요점은 작업자가 아직 모르는 값과 함께 작업할 수 있다는 것이다.
자바 스크립트에게 한가지를 요청하고 약 3초의 시간이 걸리는 작업이 있다고하면 그동안 다른 작업을 하고 그 시간뒤에 그 작업에 대한 것을 알려주게할 수 있다.
그럼 저렇게 3초뒤의 값을 어떻게 빼서 쓸 수 있을까
자바스크립트에서 promise가 끝난 이후의 명령어를 전달하려면 언제 끝나는지는 중요하지 않다
데이터를 서버에서 가져오든 api를 통해 가져오든 시간은 중요치 않고 그것을 어떻게 활용 할 수 있느냐이다.
이제 then이 등장할 차례이다.

Promise.then()을 활용해서 받은 값을 콘솔창에 띄워줬다.

promise자체를 가져온게 아닌 promise가 넘겨준 resolve값을 반환했다.
많이 헷갈렸던 부분인데 console.log에 집착 하지말자. 저부분은 다른 어떠한 작업이든 대체 될 수 있다.
가져와서 사용할 수 있다는 것에 요점을 두자.
이번엔 reject를 사용해서 에러를 띄워보자


best promise라는 에러를 띄웠는데 Uncaugth이라고 뜬다. 잡아 내지 못한 에러라는 뜻이다.
이때는 catch를 써준다.


catch구문을 써서 콘솔창에 띄워주니 --;; 값이 뜬다.. 뭐야 이거... 에러라는 겨 아닌겨
아.. 이해가 되었다....
위에서 내가 이해를 잘 못한거다. catch를 안쓰고 하니~ reject를 하지 못한것이다.
그래서 catch를 써서 잡아내니까 저 구문이 나온거~
코드를 수정해서 가독성이 좋게 만들어보자


해당 promise가 성공적으로 resolve되면 resolve: value값을 띄워주고
만약 에러가 있으면 catch를 이용해 reject : value를 띄워준다.
reject를 사용했으므로 에러로 인식해 reject:value가 뜬다.
오해 하지말자 then이 실행되고서 catch가 실행되는게 아니고 then이 실행되면 다시말해 성공적으로 resolve되면
catch는 절대 실행되지 않는다. 반대로 catch가 실행되면 then부분은 실행되지 않은 것이다.
-----------------------------------------------------------------------------------------------------------
chaning promise
이번엔 여러개의 promise를 chaining하는 것에 대해 알아보자.
mdn에 따르면 보통 하나나 두 개 이상의 비동기 작업을 순차적으로 실행해야 하는 상황을 흔히 본다.
순차적으로 각각의 작업이 이전 단계 비동기 작업이 성공하고 나서 그 결과값을 이용하여 다음 비동기 작업을 실행해야 하는 경우를
의미한다. 이런 상황에서 promise chain을 이용하여 해결하기도 한다.
예를 들어 db에서 정보를 가져오는 promise를 하고 그 데이터가 암호화 되어 있다면 암호를 푸는 promise를 또 작성한다거나
또 그 암호를 푼 data를 다시 파일로 저장해야 한다면 then().then()을 이어주는 것이다.
원하는 만큼 then을 써줄 수 있다. 모든 then은 앞의 순서가 끝나길 기다린다.

연습 코드로 2를 resolve해주는 promise가 있다.
resolve가 성공적으로 완료되면 2*2를 콘솔창에 띄워주고 이것이 또 완료되면 넘겨받은 값에 *2를 해준다.

근데.. 안뜬다.. ㅋㅋ 바로 return해주지 않았기 때문이다.

return해주면 이렇게 잘 뜬다.
chain은 서로 연결 되어있기 때문에 앞선 값을 벨류로 넘겨 받는 것. 그때 return 해줘야 넘겨 받을 수 있다.
만약 이렇게 chain된 promise에서 error가 생기면?

숫자에 2를 곱해주는 함수를 만들고
여러개의 then에 넣어준다 return받은 값을 계쏙 다음으로 넘겨주고 중간에 Error를 발생시키면
uncaught 에러가 발생하는데 앞서 배운데로
catch구문을 넣어주자~ 그럼~

이렇게 에러를 반환한다. 어느 위치 인지도 나오고~
--------------------------------------------------------------------------------------------------------------
Promise.all
이번에는 promise.all을 살펴본다.
promise.all() 메서드는 순회가능한 (iterable)한 객체에 주어진 모든 프로미스가 이행한 후 ,
혹은 프로미스가 주어지지 않았을 때 이행하는 Promise를 반환한다. 주어지니 프로미스중 하나가 거부하는 경우
첫 번째로 거절한 프로미스의 이유를 사용해 자신도 거부한다
다시말해 주어진 모든 Promise를 실행한 후 진행되는 하나의 Promise를 반환한다.
예를 들어 몇개의 api에서 데이터를 받아야 할 때가 있다.
지금 하고 있는 movie app의 경우에도 api에서 movie의 popaular데이터, tv의 rated top데이터라던지
여러개를 불러오는 경우 여러개의 api에서 각각 받아와야 하는데
각각의 promise를 만들고 각각 then을 작성해 받는 것 보다
Promise.all을 사용해 모든 promise가 전부 resolve되고 나면 마지막 promise를 리턴값으로 받아올 수 있다는 것이다.

p1,p2,p3라는 각각 작업시간이 다른 promise가 세개가 있다.
promise.all을 사용해 array에 담아주고 해당 resultPromise를
then을 사용해 값을 출력해주면

배열에 담긴 순서대로 값을 반환한다.
작업 시간에 상관없이 내가 지정한 배열로 담긴다.
원래대로라면 1초가 걸리는 second , 3초가 걸리는 third, 4초가 걸리는 first가 마지막에 반환되어야 한다.
하지만 각각의 작업시간에 상관없이 세개의 promise가 최종적으로 전부 완료되는 타이밍에 맞춰
p1,p2,p3의 순서로 배열에 담아 return해줬다.
만약 두번째 프로미스를 reject해주면?


에러 발생... 역시 catch를 써줘보자


4초뒤 에러발생시 반환값이 나온다. 어찌보면 promise에서 resolve와 reject는 필수 인가 싶다.
3개의 프로미스중 하나라도 reject되면 최종 promise도 reject된다.
-----------------------------------------------------------------------------------------------------------------
Promise.race()
promise.race() 메서드는 promise객체를 반환한다. 이 프로미스 객체는 iterable 안에 있는 프로미스 중에서
가장 먼저 완료된 것의 결과값으로 그대로 resolve or reject한다.
promise.all과 사용법은 같으나 promise.all은 모든 promise에 대해 return하는 반면
race는 몇개의 프로미스중 하나라도 resolve되거나 reject되면 return한다.


시간값을 조금 바꾸고 all -> race로 바꿔주었다.
all의 경우 하나라도 reject되면 resultPromise도 reject되었다.
하지만 race의 경우 reject가 되더라도 먼저 완료된 promise들이 있다면 그중 제일 먼저 된 promise를 resolve해준다.
어떤 작업을 요청할때 어떤 것이 먼저 되든지 상관없으면 race를 사용하면 되겠다.
-------------------------------------------------------------------------------------------------------------
finally
finally() 메서드는 promise객체를 반환한다. 프로미스가 처리되면 resolve or reject 여부에 관계 없이 지정된 콜백 함수가 실행된다.
이것은 promise가 성공적으로 수행 되었는지 거절 되엇는지에 관계없이 promise가 처리 된 후에 코드가 무조건 한번은 실행되는것을
제공한다. 이것은 프로미스의 then과 catch핸들러에서의 코드 중복을 피하게 한다.
음~~ try catch finally구문인가? python의 try except finally같은거 어쨌든 니가 에러가 있던 resolve되었든
최후엔 이코드를 실행할거야! 이건가 싶다.


위코드는 resolve되었더라도 마지막에 Im done을 출력한다~
reject되어도 마찬가지이다. 무조건 실행하는 함수이다.


혹시 몰라reject 시켰다. reject되었어도 역시 finally를 실행한다.
예제를 하나 더 다루면 fetch를 사용해보자 fetch는 promise객체를 리턴해준다.
기본적으로 google은 fetch가 허용되지 않으니 reject될것이다.


구글에서 fetch가 blocked되었다는 둥 에러가 발생하고
err문구를 return 해줬다.
이번에는 vscode에서 띄운 liveserver를 fetch해보자


response를 리턴했다. body를 보면 축소되어있는데 ReadableStream이라고 적혀있다.
stream은 이진스트림(0,1)로 읽을 수 있다는 말이다.
response를 가져와서 body를 읽을텐데 json형태로 읽어보자.


reject되었다고 나온다.. 그리고 에러 뿜.
reject되었는데 왜 catch되지 않은거지?
다른 Promise를 console.log한것이다. response가 josn()이라는 promise를 리턴하는 함수를 가지고 있기 때문이다.
json대신 text를 써보자,

또다른 promise가 pending중인 promise, fulfilled되었고 대기중이다~
API에 요청을 하면 api는 response를 준다. 그럼 response를 다시 text로 바꾸는 걸 시도하고
이건 또 프로미스를 준다.
그럼 또다른 then을 써야 한단 말이다.


response.text()를 리턴해주고 다시 then을 써서 값을 출력해주니~~ html document를 불러왔다.
한가지 더 실험해보면 yts api에서 영화 데이터를 받아와보자.

json은 console.log하면 또다른 promise가 발생해서 err가 발생하니 response만 콘솔출력해주고 response.json()의 promise를 리턴해준뒤
value를 콘솔에 나타내면

response도 정상 출력되었고
데이터도 정상적으로 출력되었다~
전에 보통 직접 promise를 만들거나 하지 않고 남이 만든것을 가져다 쓴다는 말이 무슨말인가 했는데
여기서 fetch를 사용한 것 처럼 fetch는 누군가 만들어 놓은 promise이다.
이전에 fetch를 사용할때는 then을 쓰지않고 async await을 썼기에 then의 쓰임을 잘 몰랐는데 어느정도 이해가 된다.
'JavaScript > Vanilla Js' 카테고리의 다른 글
Array.prototype.reduce() && (0) | 2021.06.15 |
---|---|
class static method & freeze() & values() & keys() (0) | 2021.06.14 |
[ES6] For ...of (0) | 2021.06.11 |
[ES6] rest + spread + destructure (0) | 2021.06.06 |
[ES6] Rest (0) | 2021.06.06 |