참고영상 https://youtu.be/3Ao3OroqQLQ
참고문헌 https://ko.javascript.info/promise-basics
https://learnjs.vlpt.us/async/01-promise.html

프로미스란?

동기 처리는 한 작업이 끝날 때까지 기다렸다가 순차적으로 작업을 처리하는 것을 의미하고 비동기 처리는 한 작업이 진행되는 중에 다른 작업도 진행할 수 있다.

프로미스는 비동기 처리를 위한 기능으로 new Promise 형식으로 객체를 만들어 사용하고 실행함수(실행자, excutor)로 resolve와 reject가 전달 된다.

let promise = new Promise(function(resolve, reject) {
  // executor (제작 코드)
});

기존에는 콜백함수를 통해 비동기 처리를 해 콜백함수를 중첩하여 쓰면서 '콜백 지옥'에 빠지는 경우가 있었지만 프로미스로 해소할 수 있게 되었다.

프로미스 객체는 프로퍼티로 프로미스의 상태를 나타내는 state와 프로미스의 결과를 나타내는 result를 갖는다.

state에는 pending(대기) 이었다가 resolve 호출 시 fulfilled(성공), reject 호출 시 rejected(실패)로 값이 변한다.

resultundefined에서 resolve(value)가 호출되면 value로, reject(error)가 호출되면 error로 변한다.
(실행자에 인자로 전달된 값이 result의 값으로 들어가는 것)

소비함수(소비자): then, catch, finally 의 사용

try~catch와 비슷한 면이 있다.
소비함수는 제작코드(실행함수)의 결과를 인자로 받는다.
이 제작코드와 소비코드를 이어주는 것이 promise 이다.

.then 사용

promise.then(
  function(result) { /* 결과(result)를 다룹니다 */ },
  function(error) { /* 에러(error)를 다룹니다 */ }
);

이렇게 되면 promise 객체의 resolve, reject 둘 다에 들어갈 결과 값을 실행할 수 있게 된다.
(성공시 윗줄의 result, 실패 시 아랫줄의 error 실행)

ex1)

let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve("done!"), 1000);
});

// resolve 함수는 .then의 첫 번째 함수(인수)를 실행합니다.
promise.then(
  result => alert(result), // 1초 후 "done!"을 출력
  error => alert(error) // 실행되지 않음
);

ex2)

let promise = new Promise(function(resolve, reject) {
  setTimeout(() => reject(new Error("에러 발생!")), 1000);
});

// reject 함수는 .then의 두 번째 함수를 실행합니다.
promise.then(
  result => alert(result), // 실행되지 않음
  error => alert(error) // 1초 후 "Error: 에러 발생!"를 출력
);

작업이 성공적으로 처리된 경우만 다루고 싶다면 .then에 인수를 하나만 전달하면 된다.

let promise = new Promise(resolve => {
  setTimeout(() => resolve("done!"), 1000);
});

promise.then(alert); // 1초 뒤 "done!" 출력

.catch 사용

위에서 .then에 인자를 전달하면 resolve로 인식되는 것처럼 .then 없이 .catch에 값을 전달하게 되면 .then에 null을 전달한 것과 동일하게 reject를 작동한다.

let promise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error("에러 발생!")), 1000);
});

// .catch(f)는 promise.then(null, f)과 동일하게 작동합니다
promise.catch(alert); // 1초 뒤 "Error: 에러 발생!" 출력

then에 resolve, reject 둘 다 전달해도 되지만 .then().catch() 로 쓰는 것이 가독성도 좋고 then에서 에러 발생시 catch로 잡아줄 수 있어서 이렇게 쓰는 것이 더 좋다.
then에 resolve, reject를 둘 다 넣게 되면 resolve 동작 시 발생하는 에러는 잡아내지 못한다.

.finally 사용

finally에 들어간 값은 성공이든 실햄함수의 결과에 상관 없이 promise 실행시 무조건 실행된다.


프로미스 체이닝

순차적으로 처리해야 하는 비동기 작업이 여러 개일 경우 콜백함수가 아닌 프로미스로 처리해보자.

const f1 = () => {
	return new Promise((res, rej)=>{;
    	setTimeout(()=>{
        	res("1번 주문 완료");
        }, 1000);
    })
}

const f2 = (message) => {
	console.log(message)
	return new Promise((res, rej)=>{;
    	setTimeout(()=>{
        	res("2번 주문 완료");
        }, 3000);
    })
}

const f3 = () => {
	return new Promise((res, rej)=>{;
    	setTimeout(()=>{
        	res("3번 주문 완료");
        }, 2000);
    })
}

console.log('시작');
f1()
.then((res) => f2(res))
.then((res) => f3(res))
.then((res) => console.log(res))
.catch(console.log)
.finally(() => {
	console.log("끝");
})

callback 함수를 쓰면 callback 안에 다음에 부를 callback 함수를 또 넣어줘야 하지만 promise는 then을 통해 프로미스를 전달하는 식으로 진행할 수 있다.
이렇게 프로미스들을 연결하는 것을 프로미스 체이닝이라고 부른다.

중간에 reject 가 동작하여 실패를 반환하면 실패한 부분에서 동작이 끝난다.


Promise APIs

Promise.all

Promise.all([f1(), f2(), f3()]).then((res) => {
	console.log(res);
});

전달된 배열 안의 함수들이 모두 실행 되어야 then이 실행된다.
단, 중간에 reject가 실행되어 실패 값이 전달되면 거기서 동작이 멈추는 게 아니라 에러가 발생하여 어떤 값도 얻지 못한다.
따라서 하나의 정보라도 누락되면 안되는 경우에 사용할 수 있다.

Promise.allSettled
Promise.allSettled는 Promise.all 과 달리 reject를 동작하여 실패 해도 프라미스의 결과들을 반환한다. 모든 프라미스가 처리될 때까지 기다리고 반환되는 배열은 다음과 같은 요소를 갖는다.

응답이 성공할 경우 – {status:"fulfilled", value:result}
에러가 발생한 경우 – {status:"rejected", reason:error}

Promise.race
Promise.all과 사용법이 완전히 같은데 말 그대로 race다. 가장 먼저 끝나는 Promise 값 하나만 반환한다.
위의 예시 코드를 입력할 경우 f1()만 반환 되는 것.

profile
하고 싶은 게 너무 많습니다.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN