Async



node.js의 장점으로 꼽는 점 중 하나가 non-Blocking으로써 비동기적으로 작동한다는 점이다.


그렇기 때문에 node.js의 대부분의 기능들은 콜백 패턴을 이용한 비동기 처리를 사용는데, 이러한 점 때문에 실제 개발에 콜백 지옥으로 인해 난관을 겪곤 한다.


콜백 지옥이란 콜백 패턴을 이용하는 함수에, 연달아 추가 기능을 사용할 경우 콜백이 계속해서 중첩되는 상태를 말한다.


task1(a, function(err, result1){     task2(b, function(err, result2){         task3(c, function(err, result3){             task4(d, function(err, result4){                 //함수 실행             });         });     }); });


위 예제는 err에 대한 처리와 각 파라미터에 대한 알고리즘을 베재한 코드이다. 

4중첩이지만 실제 코드를 node.js로 코딩할땐 흔히 4중첩이상은 흔히 볼 수 있다.


이러한 콜백 지옥을 해결하기 위해서 다양한 모듈이 있다. 

자바스크립트의 Promise 패턴을 이용한 방법(대부분의 모듈은 Promise를 지원한다.), 혹은 Async나 Step이라는 모듈로 흐름을 제어하는 방법이다.


여기서는 Async모듈을 사용하는 방법을 정리하고자 한다.


async : https://github.com/caolan/async

docs : http://caolan.github.io/async/

설치 : npm install async --save



async 모듈의 메소드는 크게 콜렉션, 흐름제어, 유틸 3종류로 나뉘어진다. 주로 사용하는건 콜렉션과 흐름제어이고, 이 포스팅 자체는 흐름제어가 주제이므로 이를 주로 다루겠다.



흐름 제어 메서드


async의 흐름 제어 메서드는 정말 다양한 종류가 있지만, 내가 주로 사용한 메서드는 다음과 같다.


- 순차 실행 : series, waterfall

- 병렬 실행 : parallels



순차 실행

순차 실행은 이름 그대로 메서드들을 순차적으로 실행하는 메서드이다. 여기엔 인자를 전달하지 않고 순차적으로만 실행하는 메서드인 series와, 

다음 메서드에 인자를 전달할 수 있는 waterfall 메서드가 있다.


1. series


시리즈 메서드는 다음과 같은 형태를 가진다.

async.series([task1,task2,task3], function(err, results){ // series 완료 콜백 });

첫번째 파라미터는 실행할 함수들을 순서대로 배열에 넣어 삽입한다, 두번째 메서드는 이 serise가 완료되었을때 실행되는 콜백 함수를 넣는데,


이 콜백에는 실행 메서드들 중 실패하는 경우 err에 인자를 전달하며 그 뒤 테스크들의 실행을 중단하고 콜백 함수를 호출한다.


모두 성공할 경우 콜백 함수의 results에 배열에 있는 각 테스크들의 실행 결과를 배열로 전달받는다.


배열에 들어가는 메서드들은 callback을 인자로 가지는 함수 형태로 만들어야 한다.




function task1(callback){     //실패시     if(err){         callback(err);     }     //성공시     callback(null, '성공1'); }


성공 시에는 callback인자를 함수로 호출하는데, 첫 인자를 null로 전달하면 되고


실패 시에는 첫 null에 err를 전달하면 된다.


async.series([
    function (callback) {
        if (err) {
            callback('실패1');
        }
        callback(null, '성공1');
    }, 
    function (callback) {
        if (err) {
            callback('실패2');
        }
        callback(null, '성공2');
    },
    function (callback) {
        if (err) {
            callback('실패3');
        }
        callback(null, '성공3');
    }],
    function(err, results) {
        // serise 완료 콜백
        if(err){
            //err시 err난 테스크에서 전달한 err값을 전달받는다
            console.log(err);
        }
        //모두 성공시, 성공 값들을 전달받는다
        //예) ['성공1','성공2','성공3']
        console.log(reuslts);
});



2. waterfall


serise와 waterfall은 둘다 순차 실행이지만

serise는 테스크들이 독립적으로 실행되어 모든 결과를 모아 배열로 콜백에 전달하는 반면에, 

waterfall은 각 테스크들의 값을 다음 인자로 전달한다는 점에서 다르다.


async.waterfall([task1,task2,task3], function(err, result){ // waterfall 완료 콜백 });

메서드의 형태는 searise와 얼핏 비슷하나, task에서 다음 콜백을 호출 할 때 인자를 전달 할 수 있다.



function task1(callback){ //실패 시 if(err){ callback(err); } //성공 시 callback(null, '성공', '1'); } function task2(arg1, arg2, callback){ //실패 시 if(err){ callback(err); } //성공 시 callback(null,'성공2'); }

async.waterfall([ function (callback) { if (err) { callback('실패1'); } callback(null, '성공','1'); }, function (arg1, arg2, callback) { if (err) { callback('실패2'); } //arg1 : '성공', arg2 : 1 console.log(arg1, arg2); callback(null, '성공2'); }, function (arg1, callback) { if (err) { callback('실패3'); } //arg1 : '성공2' console.log(arg1); callback(null, '성공3'); }], function(err, result) { // waterfall 완료 콜백 if(err){ //err시 err난 테스크에서 전달한 err값을 전달받는다 console.log(err); } //모두 성공시, 마지막에 결과 값을 전달 받는다. //result : '성공3' console.log(reuslt); });




병렬 실행


parallel


parallel도 앞서 본 메서드들과 같이 task의 배열과 콜백을 인자로 받는다. 다만 순차 실행이 아닌 전달 받은 task들을 병렬, 즉 동시에 실행한다.


그리고 모든 테스크들이 전부 다 끝난 다음에서야 콜백 함수가 실행된다.

async.parallel([task1,task2,task3], function(err, results){
// parallel 완료 콜백
});


동시 실행이기 때문에 각 task들은 serise와 같이 독립적으로 실행되며, results에는 모든 함수의 결과가 저장된다.


메서드의 형태는 serise와 비슷하다.

async.parallel([
    function (callback) {
        if (err) {
            callback('실패1');
        }
        callback(null, '성공1');
    }, 
    function (callback) {
        if (err) {
            callback('실패2');
        }
        callback(null, '성공2');
    },
    function (callback) {
        if (err) {
            callback('실패3');
        }
        callback(null, '성공3');
    }],
    function(err, results) {
        // parallel 완료 콜백
        if(err){
            //err시 err난 테스크에서 전달한 err값을 전달받는다
            console.log(err);
        }
        //모두 성공시, 성공 값들을 전달받는다
        //예) ['성공1','성공2','성공3']
        console.log(reuslts);
});







node.js를 이용한 프로젝트를 진행하면서 비동기 처리에 따른 콜백 지옥을 벗어나고자 많은 고민이 있었다. 


async 모듈, 그리고 promise 만으로도 대부분의 콜백 지옥을 해소 할 수 있다고 하므로 반복해서 숙지하도록 노력해야겠다.

'Javascript > node.js' 카테고리의 다른 글

node.js 모듈  (0) 2016.03.30
node.js 시작하기  (0) 2016.03.01

+ Recent posts