비동기 (Promise, Async / Await)

Taehye.on·2023년 3월 17일
0

코드스테이츠 44기

목록 보기
35/89
post-thumbnail

D-23

👨‍🏫 promise

비동기로 작동하는 코드를 제어하는 또다른 방법, 그리고 Callback Hell을 방지하는 역할을 하는
Promise에 대해 알아보자.

📌 new promise

promise는 class이기 때문에 new키워드를 통해 Promise객체를 생성한다.
promise는 비동기 처리를 수행할 콜백 함수(executor)를 인수로 전달받는데
이 콜백 함수는 resolve, reject 함수를 인수로 전달받는다.

promise 객체가 생성되면 executor는 자동으로 실행되고 작성했던 코드들이 작동된다.
정상적으로 처리 되었다면 resolve함수를 호출하고
에러가 발생했을 경우에는 reject함수를 호출하면된다.


정상적으로 처리된 경우의 프로미스 객체


에러가 발생한 경우의 프로미스 객체


📌 promise 객체 내부 프로퍼티

promise 객체는 stateresult 내부 프로퍼티를 가진다.

    state
    기본 상태는 `pending`(대기)이다. 비동기처리를 수행할 콜백 함수(`executor`)가 성공적으로 작동했다면 `fulfilled`로 변경되고, 에러가 발생하면 `rejected` 된다.
    result
    기본 상태는 `undefined`이다. 비동기 처리를 수행할 콜백 함수(`executor`)가 성공적으로 작동해 `resolve(value)`가 호출되면 `value`로, 에러가 발생하여 `reject(error)`가 호출되면 `error`로 변한다.

이 두가지 내부 프로퍼티직접 접근은 불가능하며,
.then, .catch, .finally의 메서드를 사용해야 접근할 수 있다.


📌 .then

콜백 함수(executor)에 작성했던 코드들이 정삭처리 되었다면 resolve함수를 호출하고 .then 메서드로 접근 가능하다.

또한 .then 안에서 리턴한 값이 promise일 경우
내부 프로퍼티인 result를 다음 .then의 콜백 함수의 인자로 받아오고
.then 안에서 리턴한 값이 promise가 아닐 경우
리턴한 값을 .then의 콜백 함수의 인자로 받아올 수 있다.

let promise = new Promise((resolve, reject) => {
	resolve("성공");
});

promise.then(value => {
	console.log(value);
	// "성공"
})

📌 .catch

콜백 함수(executor)에 작성했던 코드들이 에러가 발생했을 경우 reject 함수를 호출하고
carch 메서드로 접근 가능하다.

let promise = new Promise(function(resolve, reject) {
	reject(new Error("에러"))
});

promise.catch(error => {
	console.log(error);
	// Error: 에러
})

📌 .finally

콜백 함수(executor)에 작성했던 코드들의 정상 처리 여부와 상관없이 .finally메서드로 접근 가능하다.

let promise = new Promise(function(resolve, reject) {
	resolve("성공");
});

promise
.then(value => {
	console.log(value);
	// "성공"
})
.catch(error => {
	console.log(error);
})
.finally(() => {
	console.log("성공이든 실패든 작동!");
	// "성공이든 실패든 작동!"
})

🔍 Promise chaining

Promise chaining이 필요한 경우는 비동기 작업을 순차적으로 진행해야 하는 경우다.
Promise chaining이 가능한 이유는 위에 살펴본 세가지 메서드들이 promise를 리턴하기 때문이다.
따라서 .then을 통해 연결할 수 있고, 에러가 발생할 경우에는 .catch로 처리하면 된다.

let promise = new Promise(function(resolve, reject) {
	resolve('성공');
	...
});

promise
  .then((value) => {
    console.log(value);
    return '성공';
  })
  .then((value) => {
    console.log(value);
    return '성공';
  })
  .then((value) => {
    console.log(value);
    return '성공';
  })
  .catch((error) => {
    console.log(error);
    return '실패';
  })
  .finally(() => {
    console.log('성공이든 실패든 작동!');
  });

👨‍🏫 promise chaining 예제


🔍 promise.all()

promise.all() 은 여러 개의 비동기 작업을 동시에 처리하고 싶을 때 사용한다.
인자로는 배열을 받고 해당 배열에 있는 모든 promise에서 executor 안에 작성했던 코드들이
정상적으로 처리되었다면 결과를 배열에 저장해 새로운 promise 를 반환해준다.

promise chaining을 사용할 경우 코드들이 순차적으로 동작되고 같은 코드가 중복되는 현상이있다.

// promise chaining
const result = [];
promiseOne()
  .then(value => {
    result.push(value);
    return promiseTwo();
  })
  .then(value => {
    result.push(value);
    return promiseThree();
  })
  .then(value => {
    result.push(value);
   console.log(result);  
	 // ['1초', '2초', '3초']
  })

이러한 문제들을 promise.all()을 사용해 해결할 수 있다.
이는 비동기 작업들을 동시에 처리해 promise chaining보다 간결하다.

// promise.all()
Promise.all([promiseOne(), promiseTwo(), promiseThree()])
  .then((value) => console.log(value))
  // ['1초', '2초', '3초']
  .catch((err) => console.log(err));
    💡 `promise.all()`은 인자로 받는 배열에 있는 promise 중
    하나라도 에러가 발생되면 promise의 state와 상관없이 즉시 종료된다.

👨‍🏫 promise.all() 예제


🔍 promise Hell

Callback Hell 처럼 promise Hell도 존재한다.
promise를 통해 비동기 코드의 순서를 제어할 수 있지만,
코드가 길어질 수록 복잡해지고 가독성이 낮아진다.
ex> promise Hell


🔍 async / await

async / await 를 이용해 복잡한 promise 코드를 간결하게 작성할 수 있게 되었다.
사용법은 함수 앞에 async 키워드를 사용하고 async 함수 내에서만 await 키워드를 사용하면 된다.
이렇게 작성된 코드는 await 키워드가 작성된 코드가 동작한 후에 다음 순서의 코드가 동작한다.

// 함수 선언식
async function funcDeclarations() {
	await 작성하고자 하는 코드
	...
}

// 함수 표현식
const funcExpression = async function () {
	await 작성하고자 하는 코드
	...
}

// 화살표 함수
const ArrowFunc = async () => {
	await 작성하고자 하는 코드
	...
}

👨‍🏫 async / await 예시

0개의 댓글