가독성 개선과 에러핸들링 등과 같은 초창기 비동기 프로그래밍의 흐름을 효율적으로 개선하기 위한 고민은 현재까지 계속되고있다.
이중
Promise
와 Async / Await
가 가장 대표적인 방법이라 할 수 있다.
Promise는 JavaScript 비동기 작업을 도와주는 객체로 비동기 작업의 상태와 결과, 에러 핸들링 등을 도와줄 수 있다.
사실 많은 사람들이 Promise를 콜백지옥의 해결책이라 생각하지만, 그보다는 에러핸들링과 가독성 향상에 대한 이점을 갖는 방식이라고 봐야 한다.
const promise = new Promise(function(resolve, reject) {
// 작업 수행시 resolve() 호출
// 에러 시 reject() 호출
})
프로미스 객체를 생성하면 곧바로 인자로 전달한 비동기 함수가 실행된다.
곧바로 호출되는 비동기 함수는 resolve
와 reject
라는 함수를 인자로 받아야한다. 위 코드에 인자로 받는 함수들은 대기상태인 Pending이 된다.
const promise = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(20)
}, 3000)
})
promise.then(result => {
console.log(result)
})
// 3초 뒤 20이 출력된다.
이처럼 비동기 작업을 완료 후에 resolve(결과값)
으로 호출하면 Promise객체의 상태는 Fullfilled가 된다.
그리고 아래와 같이 then()
을 통해 위 Promise객체 생성시 인자로 넣은 비동기 함수에서 호출한 resolve(결과값)
을 콜백함수처럼 사용할 수 있다.
Promise.then(function calledResolve(result) {
// resolve(결과값)으로 실행되는 콜백함수
})
그리고 이 then()
메서드를 호출하고 나면 새로운 프로미스 객체가 반환된다.
return 값은 다음 then 메서드 콜백함수의 결과로 전달
이를 통해 Promise Chaning이 가능해진다.
프로미스의 특징은 여러개의 프로미스를 연결해서 사용할 수 있다.
then
을 호출하면 새로운 Promise객체가 호출된다. 이를 통해 then()
의 콜백함수에서 또 다시 비동기 호출을 할 수 있으면 return 값은 다음 then()
메서드 콜백함수의 결과로 전달된다.
new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1)
}, 2000)
})
.then(function(result) {
console.log(result) // 1
return result + 10
})
.then(function(result) {
console.log(result) // 11
return result + 20
})
.then(function(result) {
console.log(result) // 31
})
const Promise = new Promise(function(resolve, reject) {
setTimeout(() => {
reject(new Error('reject 호출'))
}, 1000)
setTimeout(() => {
resolve(20)
}, 3000)
})
promise
.then(result => {
console.log(result)
})
.catch(err => {
console.log(err)
})
// 1초 뒤 Error : reject 호출 출력
위와 같이 reject(에러)
로 호출하면 Promise 객체의 상태는 Rejected가 된다. 그리고 아래와 같이 catch
를 통해 위 Promise 객체 생성시 인자로 넣은 비동기함수에서 호출한 reject(에러)
를 콜백함수처럼 사용할 수 있다.
Promise.catch(function calledReject(err) {
// reject (err)으로 실행되는 콜백함수
})
비동기 처리 중에 알 수 없는 애러처리가 발생해서 reject
도 못쓰는 경우가 발생하면 어떻게 될까?
const promise = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(20)
}, 3000)
})
getData()
.then(function(result) {
console.log(result) // 3초 뒤 20 출력
throw new Error('첫번째 then에서 알 수 없는 에러 발생!') // 첫번째 then에서 에러 발생
.catch(function(err) {
console.log(err) // Error : 첫번째 thedn에서 알 수 없는 에러 발생! 출력
})
이 처럼 catch()
를 이용하면 비동기 처리 중에 알 수 없는 에러처리가 발생하더라도 에러 핸들링을 할 수 있다.
또 4번에서 봤던 Promise Chaning으로 이루어진 비동기 처리라하더라도 catch
만 쓴다면 어떤 then()
에서 reject()
나 알 수 없는 에러가 발생하더라도 모두 catch()
가 가능해지는 우아한 비동기 에러 핸들링이 가능해진다.
Promise 객체는 javaScript에서 Object
타입으로 1급 객체이다.
이 말인 즉슨 함수의 인자값으로 전달 가능하다는 말이다.
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(30)
}, 3000)
})
function func(promiseProp) {
let value = 100
promiseProp
.then(result => {
console.log(result)
console.log(100)
})
.catch(err => {
console.log(err)
})
}
func(promise) //promise객체를 인자로 전달
이처럼 프로미스 객체를 다른 함수로 전달해 그 함수의 함수 스코프를 이용한 콜백처리가 가능해진다.