Promise란

이연중·2021년 6월 18일

Javascript

목록 보기
5/6

프로미스는 자바스크립트 비동기 처리에 사용되는 객체이다.

Promise가 필요한 이유

프로미스는 주로 서버에서 받아온 데이터를 화면에 표시할 때 사용한다. 일반적으로 웹 어플리케이션을 구현할 때 서버에서 데이터를 요청하고 받아오기 위해 아래와 같은 API를 사용한다.

promise

$.get('url 주소/products/1',function(res){
    //...
});

위 API가 실행되면 서버에 데이터를 요청한다. 그런데 여기서 데이터를 받아오기도 전에 데이터를 다 받은 것처럼 화면에 표시하려고 하면 오류가 발생하거나 빈 화면이 뜬다. 이같은 문제를 해결하기 위한 방법 중 하나가 바로 프로미스이다.

프로미스 코드- 기초

ajax 통신 코드

function getData(callbackFunc){
    $.get('url 주소/products/1',function(res){
        callbackFunc(res);
    });
}

getData(function(tableData){
    console.log(tableData);
});

위 코드는 제이쿼리의 ajax 통신 API를 이용하여 지정된 url에서 1번 상품 데이터를 받아오는 코드이다. 비동기 처리를 위해 콜백 함수를 사용했다.

위 코드에 프로미스 적용

function getData(callback){
    return new Promise(function(resolve,reject){
        $.get('url 주소/products/1',function(res){
            resolve(res);
        });
    });
}

getData().then(function(tableData){
    console.log(tableData);
});

프로미스의 3가지 상태(states)

프로미스를 사용할 때 알아야 하는 가장 기본적인 개념이 바로 프로미스의 상태이다. 여기서의 상태란 프로미스의 처리 과정을 의미한다. new Promise()로 프로미스를 생성하고 종료될 때까지 3가지 상태를 갖는다.

  • Pending(대기): 비동기 처리 로직이 아직 완료되지 않은 상태
  • Fulfilled(이행): 비동기 처리가 완료되어 프로미스 결과 값을 반환해준 상태
  • Rejected(실패): 비동기 처리가 실패하거나 오류가 발생한 상태

Pending(대기)

new Promise()메서드를 호출하면 대기(Pending)상태가 된다.

new Promise();

new Promise() 메서드를 호출할 때 콜백 함수를 선언할 수 있고, 콜백 함수의 인자는 resolve, reject입니다.

new Promise(function(resolve, reject){
    //...
});

Fulfilled(이행)

콜백 함수의 인자 resolve를 아래와 같이 실행하면 이행(Fulfilled) 상태가 된다.

new Promise(function(resolve, reject){
	resolve();
});

이행 상태가 되면 아래와 같이 then()을 이용해 처리 결과 값을 받을 수 있다.

function getData(){
	return new Promise(resolve,reject){
		var data=100;
        resolve(data);
    });
}

getData().then(function(resolvedData){
	console.log(resolvedData)
});

※ 프로미스의 '이행' 상태를 좀 다르게 표현하면 '완료'이다.

Rejected(실패)

new Promise()로 프로미스 객체를 생성하면 콜백 함수 인자로 resolvereject를 사용할 수 있다. 여기서 reject를 아래와 같이 호출하면 실패(Rejected) 상태가 된다.

new Promise(function(resolve, reject){
	reject();
});

실패 상태가 되면 실패 처리 결과 값을 catch()로 받을 수 있다.

function getData(){
	return new Promise(function(resolve, reject){
        reject(new Error("Request is failed"));
    });
}

getData().then().catch(function(err){
	console.log(err);
});

출처: MDN- 프로미스 처리 흐름

프로미스 코드

ajax 통신 예제 코드에 프로미스 적용

function getData(){
	return new Promise(function(resolve, reject){
        $.get('url 주소/products/1',function(res){
            if(res){
				resolve(res);
            }
            reject(new Error("Request is failed"));
        });
    });
}

getData().then(function(data){
	console.log(data);
}).catch(function(err){
    console.error(err);
});

서버에서 응답을 받아오면 resolve() 메서드를 호출하고, 응답이 없으면 reject() 메서드를 호출한다. 호출 메서드에 따라 then()이나 catch()로 분기하여 응답 결과 또는 오류를 출력한다.

여러 개의 프로미스 연결하기(Promise Chaining)

프로미스의 또 다른 특징은 여러 개의 프로미스를 연결하여 사용할 수 있다는 것이다. then() 메서드를 호출하고 나면 새로운 프로미스 객체가 반환된다

function getData(){
    return new Promise({
       //... 
    });
}

getData()
    .then(function(data){
    
	})
	.then(function(){

	})
	.then(function(){
	});

setTimeout() API 사용 예제

new Promise(function(resolve, reject){
	setTimeout(function(){
		resolve(1);
    },2000);
})
.then(function(result){
	console.log(result);
    return result+10;
})
.then(function(result){
	console.log(result);
    return result+20;
})
.then(function(result){
	console.log(result);
});

2초 후에 resolve()가 호출되면 프로미스가 대기 상태에서 이행 상태로 넘어가기 때문에 첫 번째 .then()의 로직으로 넘어간다. 첫 번째 .then()에서 이행된 결과 값 1을 받아서 10을 더한 후 그다음 .then()으로 넘겨준다. 두 번째 .then()에서도 이전 프로미스 결과 값 11을 받아 20을 더하고 다음 .then()으로 넘겨준다. 마지막 .then()에서 최종 결과 값 31을 출력한다.

프로미스 연결 사례

실제 웹 서비스에서 있을 법한 사용자 로그인 인증 로직에 프로미스를 여러 개 연결 해보았다.

getData(userInfo)
    .then(parseValue)
	.then(auth)
    .then(display);

페이지에 입력된 사용자 정보를 받아와 파싱, 인증 등의 작업을 거치는 코드이다. userInfo는 사용자 정보가 담긴 객체이고, parseValue, auth, display는 각각 프로미스를 반환해주는 함수이다.

객체 userInfo, 함수 parseValue() auth() display()

var userInfo={
    id:'test@abc.com',
    pw:'****'
};

function parseValue(){
	return new Promise({

    });
}
function auth(){
	return new Promise({

    });
}
function display(){
	return new Promise({
        
    });
}

프로미스의 에러 처리 방법

실제 서비스를 구현하다 보면 네트워크 연결, 서버 문제 등으로 인해 오류가 발생할 수 있다.

에러 처리 방법에는 2가지 방법이 있다.

1.then()의 두 번째 인자로 에러를 처리하는 방법

getData().then(
	handleSuccess,
    handleError
);

2.catch()를 이용하는 방법

getData().then().catch();

2가지 방법 모두 프로미스의 reject() 메서드가 호출되어 실패 상태가 된 경우에 실행된다. 즉, 프로미스의 로직이 정상적으로 돌아가지 않는 경우 호출된다.

실패 상태 예

function getData(){
    return new Promise(function(resolve, reject){
        reject('failed');
    });
}

getData().then(function(){

}, function(err){
	console.log(err);
});

getData().then().catch(function(err){
	console.log(err);
});

프로미스 에러 처리는 가급적 catch()를 사용할 것

catch() 사용이 더 효율적인 이유

function getData(){
    return new Promise(function(resolve, reject){
		resolve('hi');
    });
}

getData().then(function(result){
	console.log(result);
    throw new Error("Error in then()");
}, function(err){
	console.log('then error : ',err);
});

getData() 함수의 프로미스에서 resolve() 메서드를 호출하여 정상적으로 로직을 처리했지만, then()의 첫 번째 콜백 함수 내부에서 오류가 나는 경우 오류를 제대로 잡아내지 못한다.

getData()에서 오류가 발생하면 두번째 콜백 함수로 넘어가게 된다. 이 방식을 쓸 경우 getData()에서 발생한 오류에 대해서만 다루는 것이다. 즉, 첫 번째 콜백 함수에서 발생한 오류에 대해서는 다루지 않기 때문에 오류가 발생하게 되는 것이다.

실행하면 아래와 같은 오류가 발생한다.

하지만 똑같은 오류를 catch()로 처리하면 다른 결과가 나온다.

catch로 오류 처리

function getData(){
	return new Promise(function(resolve, reject){
		resolve('hi');
    });
}

getData().then(function(result){
	console.log(result);
    throw new Error("Error in then()");
}).catch(function(err){
	console.log('then error : ',err);
});

결과는 다음과 같다.

따라서, 더 많은 예외 처리 상황을 위해 프로미스의 끝에 가급적 catch()를 붙이는게 좋다.

참고

profile
Always's Archives

0개의 댓글