Promise
Promise의 상태
- unnsettled (미확정) 상태: pending. thenable하지 않다.
- settled (확정) 상태: resolved. thenable한 상태다.
- fulfilled (성공)
- rejected (실패)
const promiseTest = param => new Promise((resolve, reject)=> {
setTimeout(()=> {
if(param) {
resolve("해결")
} else {
reject(Eroor("실패"))
}
}, 1000)
})
const testRun = param => promiseTest(param)
.then(text => { console.log(text)}) //.then은 resolve 의미로 성공했을 때 실행
.catch(error => {console.error(error)}) //.catch는 reject 의미로 실패했을 때 실행
const a = testRun(true) // 해결
const b = testRun(false)// 실패
Promise 문법
- new Promise(function)
- .then(), .catch()는 언제나 promise를 반환한다.
new Promise((resolve, reject) => { ... })
.then(res => { ... })
.catch(err => { ... })
const simplePromiseBuilder = value => {
return new Promise((resolve, reject) => {
if(value) { resolve(value) }
else { reject(value) }
})
}
simplePromiseBuilder(1)
.then(res => { console.log(res) }) // 1의 값이 들어가 resolve의 의미로 .then 실행
.catch(err => { console.error(err) })
simplePromiseBuilder(0)
.then(res => { console.log(res) })
.catch(err => { console.error(err) }) //0의 값이 들어가 reject의 의미로 .catch의 에러 값 실행
// 1
// 오류 0
↓
중복을 없애 더 깔끔한 코드로 바꾸었다.
const simplePromiseBuilder2 = value => {
return new Promise((resolve, reject) => {
if(value) { resolve(value) }
else { reject(value) }
})
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
}
simplePromiseBuilder2(1)
simplePromiseBuilder2(0)
const prom = new Promise((resolve, reject) => {
resolve()
reject()
console.log('Promise')
})
prom.then(() => {
console.log('then')
})
prom.catch(() => {
console.log('catch')
})
console.log('Hi!')
//Promise
//Hi!
//then
전체소스가 실행되는 과정에서 Promise 인스턴스의 함수도 같이 실행되며 전체소스의 실행이 끝나고서야 .then 함수가 실행되고 reject는 무시되었다는 것을 결과를 보고 알 수 있다.
↓
reject()와 resolve() 위치를 변화시켜보았다.
const prom = new Promise((resolve, reject) => {
reject()
resolve()
console.log('Promise')
})
prom.then(() => {
console.log('then')
})
prom.catch(() => {
console.log('catch')
})
console.log('Hi!')
//Promise
//Hi!
//catch
위의 두 코드를 비하여 알 수 있는 것은
1. then이나 catch구문은 실행 큐에서 후순위이다.
2. promise 인스턴스에 넘긴 함수 내부에서는, resolve나 reject 둘 중에 먼저 호출된 것만 실제로 실행된다.
3. 사실은 실제로 실행되는 것이 앙니라 실행은 둘 다 되는데 pending상태일 때만 의미가 있기 때문에 reject()와 resolve() 위치를 변화시켜도 같은 결과를 볼 수 있다.
확장 Promise 만들기
Promise.resolve, Promise.reject
Promise.resolve(42) //이와 같이 .resolve을 해주면 바로 .then으로 접근한다.
.then(res => { console.log(res) }) // 42
.catch(err => { console.error(err) })
Promise.reject(12) //마찬가지로 .reject해주면 바로 .catch으로 접근한다.
.then(res => { console.log(res) })
.catch(err => { console.error(err) }) //12
thenable 객체
const thenable = {
then (resolve, reject) { //객체안에 then 메소드를 넣으면 thenable한 객체를 만들 수 있다.
resolve(33)
//reject(33)도 가능, 대신 에러표시 뜸
}
}
const prom = Promise.resolve(thenable)
//resolve 메소드로 thenable한 객체을 인자로 담으면 then 메소드 안의 resolve 값을 thenable한 객체에서
//가져오고 혹은 reject메소드로 thenable한 객체을 인자로 담으면 reject 값을 가져온다.
prom.then(res => { console.log(res) })
//33
Promise Chaning
.then과 .catch 안에서
1. return promise 인스턴스 : promise 인스턴스가 리턴된 것. // return new promise(), return promise.resolve()
2. return 일반값 : promise 객체에 resolved 상태로 반환됨. 그 안에 값이 담김 // promise {<<resolved>>: 값}
3. return 안하면 : return undefined (원래 js 동작이 이러함) 즉 2.과 같다.
4. promise.resolve() or promise.reject() : return 해주지 않은 이상 의미없다.
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('첫번째 프라미스')
}, 1000)
}).then(res => {
console.log(res)//'첫번째 프라미스' 받아냄
return '두번째 프라미스' // promise 객체에 resolved 상태로 반환
}).then(res => {
console.log(res) //'두번째 프라미스' 받아냄
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('세번째 프라미스') //promise 인스턴스가 리턴되었다.
}, 1000)
})
}).then(res => {
console.log(res)//'세번째 프라미스' 받아냄
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('네번째 프라미스') //reject으로 바뀜, promise 인스턴스가 리턴됨.
}, 1000)
})
}).then(res => {
console.log(res)// '네번째 프라미스' 못 받아냄. 그냥 넘어감
}).catch(err => {
console.error(err)//여기서 reject의 넘어갔던 '네번째 프라미스' 받아내어 에러 메세지형식으로 나옴
return new Error('이 에러는 then에 잡힙니다.') //new Error도 일반값이니 promise 객체에 resolved 상태로 반환
}).then(res => {
console.log(res)//new Error('이 에러는 then에 잡힙니다.')을 받아냄
throw new Error('이 에러는 catch에 잡힙니다.')//마찬가지 promise 객체에 반환
//하지만 throw 특성상 reject 상태로 객체 반환한다.
}).then(res => {
console.log('출력 안됨') // throw 특성상 new Error('이 에러는 catch에 잡힙니다.') 넘어감
}).catch(err => {
console.error(err)// 여기서 new Error('이 에러는 catch에 잡힙니다.')을 받아내고 에러 메세지형식으로 나옴
})
Error Handling
asyncThing1()//차례대로 위에서 아래로 resolve와 reject 결과에 따라 접근하며 내려가게 된다.
.then(asyncThing2)//resolve하면 다음 then으로, reject하면 가장가까운 .catch로
.then(asyncThing3)//resolve하면 다음 then으로, reject하면 가장가까운 .catch로
.catch(asyncRecovery1)
.then(asyncThing4, asyncRecovery2)//resolve하면 다음 then으로, reject하면 가장가까운 .catch로
.catch(err => { console.log("Don't worry about it") })
.then(() => { console.log("All done!") })
Multi Handling
Promise.all()
- iterable의 모든 요소가 fulfilled되는 경우: 전체 결과값들을 배열 형태로 then에 전달.
- iterable의 요소 중 일부가 rejected되는 경우: 가장 먼저 rejected 되는 요소 '하나'의 결과를 catch에 전달.
const arr = [
1,
new Promise((resolve, reject) => {
setTimeout(()=> {
resolve('resolved after 1000ms') //만약 resolve가 reject이었다면 .catch로 접근하여
// arr 안의 모든 요소들 중 reject 요소 하나만 호출시킴.
}, 1000)
}),
'abc',
() => 'not called function',
(() => 'IIFE')()
]
Promise.all(arr)
.then(res => { console.log(res) })// arr 객체안의 모든 요소가 fullfiill이므로 모두 배열 형태로 호출된다.
.catch(err => { console.error(err) })
//[1, "resolved after 1000ms", "abc", ƒ, "IIFE"]
Promise.race()
- terable의 요소 중 가장 먼저 fulfilled / rejected되는 요소의 결과를 then / catch에 전달.
const arr = [
new Promise(resolve => {
setTimeout(()=> { resolve('1번요소, 1000ms') }, 1000)
}),
new Promise(resolve => {
setTimeout(()=> { resolve('2번요소, 500ms') }, 500) //제일 빠르게 fulfilled 되므로 이것이 선택.
}),
new Promise(resolve => {
setTimeout(()=> { resolve('3번요소, 750ms') }, 750)
})
]
Promise.race(arr)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
//2번요소, 500ms
const arr = [
new Promise(resolve => {
setTimeout(()=> { resolve('1번요소, 0ms') }, 0)
}),
'no queue' //setTimeout으로 타임을 0으로 지정해도 자바스크립트에서 인식할 수 있는 최소 단위는
// 10이기 때문에 사실상 아무 것도 설정안한 no queue가 제일 빠른 순서이다.
]
Promise.race(arr)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
// no queue
Promise의 활용
Promise을 이용하면 버튼을 클릭시 이미지가 등장하게 하는 작동 코드를 callback을 쓴 것보다 더 간단하게 적용할 수 있다.
document.body.innerHTML = '<button id="btn">클릭</button>'
document.getElementById('btn').addEventListener('click', function (e) {
fetch('https://api.github.com/users?since=1000')
// fetch는 HTML5의 API이다. URL을 인자에 적어주면 get동작을 한다.
.then(function (res) { return res.json() })// 데이터를 json으로 바꿔준다.
.then(function (res) {
var target = res[2]
return fetch('https://api.github.com/user/' + target.id)//클릭한 데이터의 id 값 붙여준다.
})
.then(function (res) { return res.json() })
.then(function (res) {
var _id = 'img' + res.id
document.body.innerHTML += '<img id="' + _id + '" src="' + res.avatar_url + '"/>'
document.getElementById(_id).addEventListener('click', function (e) {
this.remove()
})
})
.catch(function (err) {
console.error(err)
})
})
'프로그래밍 개발 > JS ES6+' 카테고리의 다른 글
Javascript ES6+ Class (0) | 2020.12.21 |
---|---|
Javascript ES6+ Generator (0) | 2020.12.18 |
Javascript ES6+ Iterator (0) | 2020.12.18 |
Javascript ES6+ Iterable (0) | 2020.12.18 |
Javascript ES6+ Map (0) | 2020.12.16 |
댓글