자바스크립트 시리즈:
[JavaScript] 🛒JSON, 어디까지 알아보고 오셨어요?
[JavaScript] 동기적인(Synchronous) 콜백(callback)함수도 있을까?
[JavaScript] 기다리는 자에게 복이 있나니, Promise
[JavaScript] 비동기 이기는 법, Async와 Await.
저번 글 요약:
다음과 같이 할 수 있게 해준다.
const a = promiseFunction()
a.then(()=>console.log("Do Something"));
promiseFunction
은 promise를 return하는 어떤 함수다.
그니까 asyncrhonous한 함수가 promise를 return하게 만들면, .then
뒤에 그 함수가 끝나면 실행할 코드를 넣을 수 있다. 순차적으로 실행할 수 있게 됐다!
순차적으로 실행해야하는 코드가 많으면 어떨까? Callback지옥같은 일이 또 생기는 건 아닐까..?
const a = promiseFunction()
a.then(()=>console.log("first"))
.then(()=>console.log("second"))
.then(()=>console.log("third"))
.then(()=>console.log("fourth"))
훨씬 깔끔해졌다!
카페나 음식점에 가서 키오스크에서 주문을 하면, 돈을 받고 번호표가 나온다. 실제로 음식이 나온 건 아니지만, 그렇다고 음식이 완성되서 나올때까지 다음 주문을 기다리지는 않는다. 나중에 음식이 나오게 되면 번호표를 건내주면 음식을 받을 수 있다.
Promise는 번호표 같은 역할을 한다.
또 한 가지 특징이 있다. 프로미스는 synchronous한 내용도 asynchronous하게 실행한다. 따라서 고민할 필요가 없다. 이 부분은 뒤의 프로미스의 장점에서 자세히 보자.
“asyncrhonous한 함수가 promise를 return하게 만들면” 이라고 했는데, 어떻게 그렇게 만들 수 있을까?
2단계로 나눌 수 있다.
일단 첫 번째 단계부터 해결하자.
new Promise((resolve, reject) => {
//asynchronous한 무언가를 한다.
})
.then(
//그 다음에 무언가를 한다.
)
Promise키워드 앞에 new를 붙여서 만들면 된다!
근데 그 옆에 있는resolve
와 reject
는 뭐하는 아이들일까?
promise가 resolve될 경우에 아까 봤던 .then()
을, reject될 경우에는 .catch()
를 실행시켜준다.
이게 뭔 소릴까?
그럼 언제 resolve되고 언제 reject된다는 걸까?
답은 우리가 정해줄 때다.
코드로 나타내면 다음과 같다.
new Promise((resolve, reject)=>{
//async한 무언가
if(//잘 해결되었다고 믿을만한 조건){
resolve(//return하고 싶은 것)
}
else{
reject(//return하고 싶은 것)
}
})
.then(//resolve에서 return한 값으로 무언가를 한다.)
.catch(//reject에서 return한 값으로 무언가를 한다.)
new Promise로 만든 이 함수도 무언가 실행의 결과가 있을 것이다. 그걸 resolve
나 reject
안에 적어준다.
.then
이나 .catch
에서 이 값을 받아서 그 다음에 실행하고 싶은 코드를 실행해주면 된다.
2번째 단계였던, 우리의 함수가 Promise를 return하게 만드는 건 간단하다.
function ourFunction(arg1, arg2){
const workDone = someAsyncWork(arg1, arg2); //이 부분이 asynchronous한 작업이라고 가정하자.
return new Promise((resolve, reject)=>{
if(잘해결됐다면){resolve(workDone);}
else{reject('무언가 잘못됐어!')}
})
}
비동기 처리를 하고 Promise를 만들어서 return하면 된다!
근데 Promise를 return한다는 게 무슨 뜻일까?
위의 ourFunction
을 불러보자.
ourFunction(someArg1, someArg2)
.then((result) => console.log(`Result: ${result}`))
.catch((error) => console.log (`Error/: ${error}`))
ourFunction
은 result나 error를 반환하는 게 아니다.
그것들을 반환하겠다는 promise, 약속을 반환한다.
그건 바로 .then()도 새로운 promise를 반환하기 때문이다. .then() 뒤의 .then()은 바로 그 새로운 promise에 대한 .then()이다.
promise를 더 편하게 쓸 수 있게 해주는 기능들도 있다.
그 중 하나는 resolve가 되든, reject가 되든 실행되는 finally
다. 공통된 부분을 담아둘 수 있어 코드 반복을 피할 수 있다.
new Promise((resolve, reject) => {
//resolve, reject
}))
.then(() => { console.log("success") })
.catch(() => { console.log("fail") })
.finally(res => { console.log("finally") });
또, 여러 promise를 순차적으로가 아닌 동시에 쓰고 싶을 때도 있을 거다.
asynchronous한 코드를 여러 개 작동시키는데, 전부 다 끝나는 시점에 무언가를 하고 싶다면
Promise.all([promise1, promise2]).then(function(results) {
// Both promises resolved
})
.catch(function(error) {
// One or more promises was rejected
});
배열에 넣어서 Promise.all
로 거대한 promise를 만들어주자!
마지막으로 여러 promise 중 가장 빨리 끝나는 결과를 받고 싶다면 Promise.race
를 쓸 수 있다. 여기서는 Promise의 배열에서 하나의 Promise만 resolve되면 .race
로 묶은 커다란 Promise도 resolve된다.
Callback에는 크게 2가지 문제점이 있었다.
”흐름을 제어하기가 어렵다: 알아보기 어렵고, 에러 처리에도 문제가 있다”.
“뿐만 아니라, 함수의 주도권이 넘어가기 때문에 무슨 짓을 할 지 모른다.”
일단 Promise는 .then()
또는 .catch()
로 Promise가 해결된(Resolved) 시점을 받아온다. 따라서 이미 받아온 시점을 가정하고 걱정없이 코드를 작성할 수 있다.
다시 말해, asynchronous한 함수의 언제 끝날지 모른다는 점을 캡슐화했다. 그렇기 때문에 알아보기도, 작성하기도 더 편하다.
또 어떤 부분이 async한지, 어떤 부분이 sync한지 알 수 없는 문제점이 있었다.
Promise는 모든 것을 async하게 만들어버리기 때문에 그런 고민을 할 필요가 없다. 이는 함수가 async할지, sync할지 모른다는 Callback의 문제점도 해결해준다.
Error Handling도 더 편하다. .catch()
로 받아 올 수 있다. 심지어 여러 개의 .then()
으로 Promise의 chaining이 일어나 있는 경우에도 쉽게 처리할 수 있다. 몇 번째 Promise에서 rejected됐든, 이후의 가장 가까운 .catch()
를 찾아서 전달되기 때문에 마지막에만 .catch()
를 붙여주면 된다.
Promise는 함수가 끝나는 시점을 받아와서 그 이후의 작업을 내가 정의한다. 즉, Promise는 자기가 끝난 후 무슨 일이 일어날지 알 수 없다. 그 이후 .then()
에 넣어주는 Callback Function이 자기 자신에 대한 주도권을 가지고 있다. 따라서 너무 늦게 불리거나 안불리는 문제도 일어나지 않는다.
Promise는 한 번만 resolve되고, 따라서 .then()에 넣어주는 Callback Function도 1번만 실행되기 때문에 여러 번 불리는 문제도 없다.
async와 await를 이용해 비동기처리를 할 수도 있다.
다음 글에서는 그에 대해 더 알아보자.🍰
자바스크립트 시리즈:
[JavaScript] 🛒JSON, 어디까지 알아보고 오셨어요?
[JavaScript] 동기적인(Synchronous) 콜백(callback)함수도 있을까?
[JavaScript] 기다리는 자에게 복이 있나니, Promise
[JavaScript] 비동기 이기는 법, Async와 Await.
참고:
https://davidwalsh.name/promises
https://github.com/getify/You-Dont-Know-JS/tree/1st-ed
https://www.freecodecamp.org/news/javascript-es6-promises-for-beginners-resolve-reject-and-chaining-explained/