7월 21, 2016

비동기 함수를 다루는 방법 : Promise

Express로 웹을 만들다보면 mysql 통신을 위해 비동기 함수를 쓸 일이 자주 생긴다.
예를 들어서 다음과 같은 코드를 쓰고 싶을 때가 있다.


router.get('/search', function(req, res){
    var result = getSomethingFromDatabase(req.query.keyword);
    
    /* do something with result */
}

function getSomethingFromDatabase(keyword){
    var sql = 'SELECT * from TABLE' +
        'WHERE column LIKE \'%' + keyword + '%\'';
    
    conn.query(sql, function (err, results) {
        return results;
    });
}

하지만 conn.query 가 호출되고 results 를 반환하기 전에 이미 search 메서드는 비어있는 변수 result 로 나머지 부분을 실행하게 되므로 원하는 결과는 나오지 않는다.

conn.query 메서드 안에 원하는 로직을 전부 넣으면 동작이 되지만,
웬지 그런방식으로 코드를 작성하고 싶지 않아서 열심히 구글링을 한 결과 async 나 promise 같은 것들이 있다는 걸 알게되었다.
그러면 둘의 차이는 무엇일까?

알아본 결과, Async 는 러닝 커브가 작으며 코드가 좀 더 깔끔해지는 장점이 있고, Promise 는 ECMA6 표준으로 채택되었다고 한다.
주목할 점은 Promise 를 사용해 작성한 코드가 동기 프로그래밍 방식과 상당히 닮아있다는 점인데, 이에 관해서는 내가 찾은 어느 블로그에 상세히 설명되어 있다.
결국 Promise 는 Async 에 비교하여 단순히 스타일이 다른 비동기 프로그래밍 방식이 아닌 동기 프로그래밍에 가깝게 작성하는 방법이고, 그 다음 구현체가 ES7의 async/await 라고 볼 수 있겠다.

나는 우선 둘 중에 표준인 Promise 로 구현해 보기로 했다.
ES6 를 사용중이라면 아무런 준비과정 없이 바로 Promise 를 사용할 수 있고
아니라면 npm 으로 설치해야 한다.

> npm install promise
그리고 MDN의 promise 문서를 참고해서 기존의 코드를 수정했다.

router.get('/search', function (req, res) {
    /* create new promise object */
    var promise = new Promise(
        function (resolve, reject) {
            var sql = 'SELECT * from TABLE' +
                'WHERE column LIKE \'%' + keyword + '%\'';
            conn.query(sql, function (err, results) {
                if (err) {
                    console.error(err);
                    reject(err);
                }
                resolve(results);
            });
        }
    );

    /* do something with result */
    promise.then(function (results) {
        res.render('view/result', result);
    }, function (err) {
        throw err;
    });
});

Promise 객체를 생성하면서 비동기 함수가 성공적으로 수행되었을 때(resolve), 또는 실패하였을 때(reject)의 경로를 정의해준다.
그리고  then( OnFullfilled, OnRejected )을 사용한 부분이 실제 비동기 함수를 호출하는 부분이다.
결론적으로 썩 내가 원하던 코드의 모습은 아니지만(데이터 불러오는 루틴을 밖으로 빼고 싶었음) 방식은 비슷하게 구현된 것 같다.
나중에 ES7 의 async/await 를 사용하면 코드가 훨씬 간결해질 듯 하다.

댓글 없음:

댓글 쓰기

댓글