Promise 잘 사용하기 (1) 기초개념

joonseokhu·2020년 4월 12일
4

Promise 잘 사용하기

목록 보기
1/2

Promise는 비동기 작업 결과값이 아니다. 하지만 그렇게 취급 가능하다.

현실세계로 비유하자면, Promise는 바우처와 비슷한 개념이다.

재화를 구매했지만 지금 당장은 바우처만 받았고 아직은 내 손에 재화가 없는 상태가 비동기이다. 하지만 재화 대신 받아서 가지고 있는 바우처는 내가 나중에 받게 될 재화와 동등하게 취급된다.

비동기 결과로 만들어지는 Promise 변수 그 자체는 비동기 코드 호출과 동시에 받을 수 있다. 즉 Promise를 받는 코드는 동기적인 코드이다. 실제로 우리가 기대하는 값 (예를들어 API 호출을 통해 받으려는 JSON)은 아직 실제로 받지 못한 상태이지만, 그 값 대신 받은 Promise를 가지고 그냥 쓰면 된다.

const getData = () => {
  const result = axios.get('https://sample.com/data') // result 는 실제 데이터가 아닌 Promise다.
  return result;
}

const data = getData() // 마치 진짜 데이터를 받은것처럼 이리저리 전달해도 된다. 맨 마지막에 실제로 값을 뽑아낼 때만 잘 처리하면 된다.

Promise chain

Promise의 메서드들 (then, catch, finally)도 Promise를 리턴한다.

그렇기 때문에, Promise 메서드 호출 후, 또다시 Promise 메서드를 호출할 수 있다. promise를 연결해서 작성하는건 무한히 가능하다. Promise메서드를 연결해가며 사용하는걸 Promise chain이라고 부른다.

Promise 메서드의 콜백에서 리턴된 값은 다음에 실행될 체인에서 콜백의 인자의 값이 된다.

Promise.resolve()
	.then(() => {
		return 12
	}).then(e => {
		// e === 12
	})

Promise 메서드 안쪽 콜백의 실행결과에 따라 Promise는 둘 중 하나의 상태로 귀결된다.

  • fulfilled: 비동기 처리가 성공적으로 진행되었다는 뜻이다.
  • rejected: 비동기 처리가 실패했다는 뜻이다.

Promise 메서드의 콜백에서 Promise가 아닌 값을 리턴한다면 (또는 아무것도 리턴하지 않아 undefined를 리턴한 셈이 되었다면), fulfilled 된 것으로 취급한다.

fulfilled 처리된 체인 다음에 오는 체인들 중 제일 처음으로 등장하는 then이 그것을 받아들이며, 리턴되었던 값을 인자로 받는다.

Promise.resolve()
	.then(() => {
		return 'hi'
	}).catch(() => {
		console.log('앞 체인이 fulfilled라면 catch는 무시된다.')
	}).then(e => {
  		// e === 'hi'
		console.log('fulfilled로 취급되어 이 코드가 실행된다.')
	})

Promise 메서드의 콜백에서 에러가 난다면 rejected된 것으로 처리한다.

rejected 처리된 체인 다음에 오는 체인들 중 제일 처음으로 등장하는 catch가 그것을 받아들이며, 발생한 에러를 인자로 받는다.

Promise.resolve()
	.then(() => {
		null.foo() // 에러가 난다.
	}).then(() => {
		console.log('앞 체인이 rejected라면 then은 무시된다.')
	}).catch(e => {
		console.log('이 코드가 실행된다.')
        console.error(e) // TypeError: Cannot read property 'foo' of null
	})

Promise 메서드의 콜백이 Promise를 리턴할 경우는 , 해당 Promise의 처리 결과가 해당 메서드의 Promise 결과인 것으로 처리된다.

Promise.resolve()
	.then(() => {
		const result = fetch('htttps://example.com/api') // promise를 받는다.
		return result;
	}).then(() => {
		console.log('앞에 있는 fetch의 promise가 fulfilled로 처리된다면 이 코드가 실행된다.')
	}).catch(() => {
  		console.log('앞에 있는 fetch의 promise가 rejected로 처리된다면 이 코드가 실행된다.')
	})

async/await

async/awaitPromise로 된 비동기 코드를 동기적으로 쓸수 있게 해주는 문법이다.

const getData1 = () => {
  const promise = fetch('htttps://example.com/api')
    .then(res => {
      return res.json()
    }).then(data => {
      console.log(data)
    });
  return promise
}

이런 코드는

const getData2 = async () => {
  const res = await fetch('htttps://example.com/api')
  const data = await res.json();
  console.log(data);
  return data;
}

async/await로 이렇게 고칠 수 있다.
함수 앞에 async 키워드를 붙이고, promise 값 앞에 await 키워드를 붙이기만 하면 promise 메서드 없이 값을 사용할 수 있게 된다.
비동기코드같지 않고 동기적 코드같다.

하지만 혼동하면 안되는데, 문법의 생김새가 동기적처럼 보일 뿐이지 실제로는 둘다 똑같은 비동기코드다.

getData1을 실행한 결과와, getData2를 실행한 결과 둘다 Promise 이다.

async 함수의 리턴결과는 항상 Promise이다.

profile
풀스택 집요정

0개의 댓글