본문 바로가기
프로그래밍 개발/JS ES6+

Javascript ES6+ Promise

by Jinseok Kim 2020. 12. 22.
반응형

 

 

 

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

댓글