Javascript Promise 객체 활용 – Value 처리

Javascript 코딩을 할 때 Promise를 사용하여 비동기 함수를 체계적으로 활용 할 수 있다. Promise를 잘 사용하면 Async 보다 깔끔하게 코드 정리가 가능하다. 예제 코드는 여기에서 확인 할 수 있다.

Promise 객체

new Promise()를 선언할 때 지시된 함수가 실행되기 때문에 Promise 객체는 함수로 Wrapping 하여 사용한다.

'use strict'

let add = (arg1, arg2)=> new Promise((resolve)=> {
setTimeout(()=> {
console.log('add executed');
resolve({result: arg1+arg2});
}, 1000);
});

let sub = (arg1, arg2)=> new Promise((resolve)=> {
setTimeout(()=> {
console.log('sub executed');
resolve({result: arg1-arg2});
}, 500);
});

위의 코드는 비동기 함수인 setTimeout를 Promise를 통해 간단하게 구현해본 코드이다.

add, sub 함수는 각각 1000ms, 500ms 후에 arg1, arg2를 더하거나 뺀 값을 돌려준다.

add(1, 2);
sub(3, 4);

위와 같이 두 함수를 실행하면 sub는 500ms 후, add는 1000ms 후에 결과를 돌려주기 때문에 sub가 먼주 출력되고 add가 출력된다.

add와 sub를 순차적으로 실행하기 위해서는 아래와 같이 사용한다.

add(1, 2)
.then((data)=> sub(data.result, 4))
.then((data)=> {
console.log(data);
});

add 함수가 실행된 후 sub 함수를 실행하기 위해서는 add 함수를 호출한뒤 then 함수를 호출하여 순차적으로 작업을 진행 할 수 있다.

then의 콜백 함수에서는 promise의 결과값을 반환해 주고 return을 통해 다음 작업을 지정 할 수 있다.

Promise 결과값 처리

Promise A, B, C를 선언 한 후, C에서 A의 결과값을 필요로 할 때가 있다. 이러한 경우 Promise에서 이전 결과에 대한 접근을 제공하지 않기 때문에 전역으로 활용할 수 있는 변수를 선언하여 각각을 저장해 놓아야한다. 하지만 전역 변수로 선언하면 다른 변수와 overwrite되는 등의 문제가 발생한다.

Promise.values = [];
Promise.id = 0;
Promise.exec = (promise)=> {
let thisId = Promise.id;
if(promise) {
promise.then((data)=> {
Promise.values[thisId] = data;
resolve(data);
});
Promise.id++;
return promise;
}
Promise.id = 0;
return new Promise((resolve)=> resolve());
}

이 글에서는 이러한 문제를 Promise에 변수 및 함수를 추가하여 해결하였다.

Promise 함수를 Promise.exec를 통해 wrapping하여 사용하고, 이 때 각각의 결과를 id를 지정하여 Promise.value에 저장한다.

let A = (arg1, arg2)=> new Promise((resolve)=> {
console.log('A Executed');
setTimeout(()=> {
resolve({result: arg1 + arg2});
}, 500);
});

let B = (arg1, arg2)=> new Promise((resolve)=> {
console.log('B Executed');
setTimeout(()=> {
resolve({result: arg1 - arg2});
}, 500);
});

let C = (arg1, arg2)=> new Promise((resolve)=> {
console.log('C Executed');
setTimeout(()=> {
resolve({result: arg1 * arg2});
}, 500);
});

함수 실행을 위해 A, B, C 함수를 선언하였다. 각각 setTimeout 후에 파라미터를 +, -, * 로 계산하여 {result: } 의 형태로 반환해주는 Promise 객체이다.

선언한 A, B, C 함수를 순차적으로 실행하기 위해서는 아래와 같이 코드를 사용하면 된다.

Promise.exec()
.then(()=> Promise.exec(A(1, 2)))
.then((data)=> Promise.exec(B(data.result, 4)))
.then((data)=> Promise.exec(C(Promise.values[0].result, Promise.values[1].result)))
.then((data)=> {
// Promise A result
console.log(Promise.values[0]);
// Promise B result
console.log(Promise.values[1]);
// Promise C result
console.log(data); // or console.log(value[2]);
});

Promise.exec 함수에 Promise 객체를 지정하지 않고 실행하면 Promise.id를 0으로 초기화하고 Dummy Promise 객체를 반환한다.

이 후 A, B, C를 각각 Promise.exec를 통해 실행하면 Promise.values에 0부터 순차적으로 값이 대입된다.

3번째로 실행되는 C에서 이전 두개의 결과값을 사용하기 위해서는 Promise.values[0], Promise.values[1]을 사용해서 이전 변수값을 불러 올 수 있다.

P.S.

Promise를 사용할 때, 맨 처음 실행시 사용하려는 Promise 객체를 바로 호출하기보다는 Dummy Promise 객체를 생성하여 실행하는 것이 좋다.

Dummy 객체를 사용하지 않으면 A, B, C의 함수를 순차적으로 실행하도록 하였다가, B, C, A의 순으로 변경하여 실행할 때 코드를 바꾸기가 다소 번거롭다.

하지만 시작시 Dummy 객체를 사용하면 .then 의 순서만 변경하여 손쉽게 순서를 변경 할 수 있다.

댓글 남기기