[JS] Promise, 비동기 처리하기

2023. 1. 21. 10:00
반응형

Promise란

앞장의 콜백 지옥을 해결하기 위한 방법으로 Promise를 언급하였었다. Promise는 지금 당장에는 어떤 결과가 나올지 모르나 추후에 어떠한 결과를 제공하겠다는 약속(Promise)의 개념이다.

주로 Javascript의 비동기 처리에 사용하며, 이것을 사용하면 비동기 연산이 종료된 이후의 결과를 받아 추가 연산을 하는 등 동기 메서드처럼 값을 반환받을 수도 있다.

Promise의 상태는 다음 세 가지이다. 

  • 대기(pending): 이행 및 거부가 이루어지지 않은 초기 상태.
  • 이행(fulfilled): 연산이 완료됨.
  • 거부(rejected): 연산이 실패함.

일련의 비동기 연산이 이루어지는 과정은 Pending, 연산이 성공했을 경우 Fulfilled, 오류 등이 일어났을 경우 Rejected 상태가 되며, 이행 및 거부 이후의 콜백함수와 같은 개념의 추가 행동을 작성할 수 있다.

 

Promise 객체

const p = new Promise((resolve, reject) => {
    //pending

    //비동기 연산...

    const success = false;   //성공 Or 실패
    setTimeout(() => {
        if(success){
            resolve("Complate");
        }
        else{
            reject(new Error("Error Reason"));
        }     
    }, 3000);   //3초 후 이행상태 돌입

});

 Promise 객체는 다음과 같이 생겼다. 생성자에 익명 함수가 들어간다. 익명 함수 안에서 일련의 연산을 마친 후

성공했을 경우 resolve()를, 실패나 에러가 났을 경우 reject()를 호출한다. 

resolve가 호출되는 시점이 fulfilled된 시점, reject가 호출되는 시점이 rejected된 시점이다.

 

p.then((x) => {
    console.log('callback', x);
})
.catch((e) => {
    console.log('catch', e);
})

다음처럼 프로미스에 then과 catch를 연결할 수 있다. 

then은 resolve()이후의 액션을, catch는 reject()이후의 액션을 넣을 수 있다.

 

프로미스 체이닝

콜백지옥 함수를 Promise를 통해 해결해보자. 콜백함수 남용 시 발생하는 가독성 문제를 Promise를 통해 가독성 있고 명확한 코드 작성을 할 수 있다.

// ======= 콜백 지옥 함수 =============
function add(x, callback){
    let sum = x + x;
    console.log(sum);
    callback(sum);
}

add(3, function(result){
    add(result, function(result2){
        add(result2, function(result3){
            add(result3, function(result4){
                console.log("fin")
            })//4) result3 + result3, callback으로 fin log 출력
        })//3) result2 + result2 (= result3), callback으로 4) 수행
    })//2) result + result  (= result2), callback으로 3) 수행
}) //1) 3 + 3 (= result), callback으로 2) 수행
//==== 콜백 지옥 함수를 Promise를 이용하여 구현하기 ====

function add2(x){
    let sum = x + x;
    console.log(sum);
    return new Promise((resolve, reject) => {
        resolve(sum);
    })
}

add2(3) //1) 3 + 3 (= result), callback으로 2) 수행
.then((result) => add2(result)) //2) result + result  (= result2), callback으로 3) 수행
.then((result2) => add2(result2)) //3) result2 + result2 (= result3), callback으로 4) 수행
.then((result3) => add2(result3)) //4) result3 + result3 
.then((result4) => {    //4) callback으로 fin log 출력
    console.log('fin');
})

콜백 지옥 함수와 비교해보니 가독성이 훨씬 좋아졌다. 이처럼 계속 then()으로 비동기 메서드와 콜백을 연결해 줄 수 있는데 이를 프로미스 체이닝이라고 부른다. 

 

프로미스 함수

Promise.resolve(value)

어떠한 값이 프로미스 객체인지 아닌지 알 수 없는 경우 사용한다.

프로미스 객체인 경우 resolve된 결과를 받아 then이 실행된다.

프로미스 객체가 아닌 경우 리턴값을 받아 then이 실행된다.

//1. 프로미스 객체일 경우 resolve된 then 메서드 실행,
const prom = new Promise((resolve, reject) => {
setTimeout(() => {
	resolve('this is data');
	}, 1000);
});

Promise.resolve(prom).then((data) => {
	console.log('프로미스 객체인 경우 resolve된 결과를 받아 then이 실행됩니다.', data);	//this is data
});

//2. 프로미스 객체가 아닌 경우 value를 인자로 보내면서 then 메서드 실행
const func = () => {
    for(let i = 0; i< 10000; i++){
        for(let j = 0; j < 100000; j++){
            //...복잡한 연산
        }
    }
    return 'COMPLATE'
}
Promise.resolve(func()).then(data => {
	console.log('then 메서드가 없는 경우 fufilled됩니다.', data);	//COMPLATE
});

Promise.resolve(reason)

Reason으로 인해 거부된 Promise를 반환한다. 

Promise.reject(new Error('reason'))
.then(x => {
	console.log('여기는 실행되지 않음');
})
.catch(error => {
	console.log('catch error', error);
});

Promise.all(Promise[])

인수로 프로미스 배열이 들어가며, 모든 프로미스들이 fulfilled된 이후 resolve된 결과의 집합을 반환한다.

function p(ms){
    return new Promise((resolve, reject) => {
        setTimeout(() => {
        	resolve(ms);
    	}, ms)
    });
};

Promise.all([p(1000), p(2000), p(3000)]).then((message) => {
	console.log('모두 fulfilled된 이후 실행된다.', message) //[1000,2000,3000]
});
 

Promise.race(Promise[])

인수로 프로미스 배열이 들어가며, 가장 먼저 fulfilled된 Promise의 resolve된 결과를 반환한다.

Promise.race([p(1000), p(2000), p(3000)]).then((message) => {
	console.log('가장먼저 fulfilled된 Resolve값이 반환된다.', message) //1000
});



반응형

BELATED ARTICLES

more