async 모듈을 이용한 비동기 처리 패턴 정리.



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




series(tasks, [callback])

주어진 함수 배열(혹은 object)을 순서대로 실행 시킴.

모든 함수 실행이 끝나면 callback이 호출됨.

함수 실행 중 err가 있으면 그 이후로는 실행 중단.


// 함수를 배열로 전달

// __________________________________________________

async.series([

    // 1st

    function(callback){

        callback(null, 1);

    },

    // 2nd

    function(callback){

        callback(null, 2);

    }

], 

// callback (final)

function(err, results){

    console.log(err); // null

    console.log(results); // [1, 2]

});


// 함수를 object로 전달. final callback의 result가 좀 더 가독성 있음

// __________________________________________________

async.series({

    func1: function(callback){

        callback(null, 1);

    },

    func2: function(callback){

        callback(null, 2);

    }

}, 

// callback (final)

function(err, results){

    console.log(err); // null

    console.log(results); // {func1: 1, func2: 2} <- 여기가 가독성..

});



// setTimeout으로 실행순서 확인

// __________________________________________________

// func1의 timeout이 1초로 func2의 0.5초보다 길지만 func1이 먼저 출력되고, func2가 출력됨

async.series({

    func1: function(callback){

        setTimeout(function(){

            console.log('func 1');

    callback(null, 1);

        }, 1000);

    },

    func2: function(callback){

        setTimeout(function(){

            console.log('func 2');

            callback(null, 2);

        }, 500);

    }

},

// callback (final)

function(err, results){

    console.log(results); // {func1: 1, func2: 2}

});



// func1에 error가 있을 경우 func2는 실행되지 않음 

// __________________________________________________

async.series({

    func1: function(callback){

        callback('error', 1);

    },

    func2: function(callback){

        callback(null, 2);

    }

},

// callback (final)

function(err, results){

    console.log(err); // 'error'

    console.log(results); // {func1: 1}

});








parallel(tasks, [callback])

주어진 함수 배열(혹은 object)을 동시에 실행 시킴. (함수실행순서를 알 수 없음)

모든 함수 실행이 끝나면 callback이 호출됨.

함수 실행 중 err가 있으면 그 이후로는 실행 중단.


// 전역변수 카운터

var i = 0;

// task로 사용할 함수

var f = function(callback){

    ++i;


    // 2의 배수일 경우 1초 후 callback 호출  

    if (i%2===0) {

        console.log('delay = '+i);

        setTimeout(function(){

            callback(null, i);

            return;

        }, 1000);

    }

    // 2의 배수가 아닐 경우 즉시 callback 호출

    else {

        console.log('no delay = '+i);

        callback(null, i);

    }

}


// 할당할 tasks 세팅

var tasks = {};

for (var j=0; j<5; j++) {

    tasks['func'+j] = f;

}


// parallel!

async.parallel(tasks,

// callback

function(err, results){

    console.log(results);

});


/*

[실행결과]

먼저 tasks로 지정된 함수 내부에서 console.log로 출력한 

아래의 5라인이 주루룩 나온다. i 값을 1씩 증가시킨 정상적인 출력이다.

no delay = 1

delay = 2

no delay = 3

delay = 4

no delay = 5


그리고 대략 1초 후 final callback 함수에서 호출한 console.log 의 결과는 다음과 같다.

{func0: 1, func2: 3, func4: 5, func1: 5, func3: 5}}

++i 값이 2의 배수가 아닌 func0, func2, func4 함수의 callback result가 앞부분에 있고,

++i 값이 2의 배수인 func1, func3 함수의 callback result가 뒷부분에 있는 것을 확인할 수 있다.

그리고 func1, func3의 callback result인 i값이 둘 다 i의 최대값이 5인 것을 확인할 수 있다.

setTimeout 으로 지연되고 있는 동안 전역변수 i 는 이미 5가 되어 있기 때문이다.

*/








parallelLimit(tasks, limit, [callback])

주어진 함수 배열(혹은 object)을 동시에 실행 시킴. (함수실행순서를 알 수 없음)

parallel과 다른 점은 동시 실행되는 task의 숫자를 limit를 통해 조절할 수 있는 것.

I/O 등을 조절하는데 사용가능.

모든 함수 실행이 끝나면 callback이 호출됨.

함수 실행 중 err가 있으면 그 이후로는 실행 중단.


async.parallelLimit({

    func1: function(callback){

        console.log('func1');

        setTimeout(function(){

            callback(null, 1);

        }, 1000);

    },

    func2: function(callback){

        console.log('func2');

        setTimeout(function(){

            callback(null, 2);

        }, 1000);

    },

    func3: function(callback){

        console.log('func3');

        setTimeout(function(){

            callback(null, 3);

        }, 1000);

    }

},

// limit. 동시 실행 task수는 2로 지정

2,

// callback (final)

function(err, results){

    console.log(results);

});


/*

[실행결과]

각 task에서 실행한 console.log 중 

func1

func2 

가 출력된 다음,

limit에 지정된 task수 2개가 이미 실행 중이므로 대기하고 있다가, 

func1 또는 func2 가 callback을 호출하고 한자리가 비면, 

func3 이 실행되면서 

func3 

이 출력되고,

또 다시 1초 가량 지연되다가 func3까지 모든 task가 callback을 호출하면,

final callback에서 호출한 console.log가 실행됨.

{func1: 1, func2: 2, func3: 3}

*/








waterfall(tasks, [callback])

기본적으로는 task가 순서대로 실행된다는 점에서 series와 같지만 다른 점은 다음과 같음.

1. result가 final callback에 전부 모이는 게 아니라 실행되는 각 task들 사이로 전달됨.

2. tasks는 object가 아닌 array만 가능

간단하게 표현하자면 args 전달이 자유로운 method chain.


async.waterfall([

    // func1

    function(callback){

        // '111', 'one'이란 문자열을 인자로 다음함수 func2(callback) 호출

        callback(null, '111', 'one');

    },

    // func2 (args 2개 지정)

    function(arg1, arg2, callback){

        console.log('func2 args = '+arg1+', '+arg2);

        // '222'란 문자열을 인자로 다음함수 func3(callback) 호출

        callback(null, '222');

    },

    // func3

    function(arg, callback){

        console.log('func3 args = '+arg);

        // 'three'란 문자열을 인자로 final callback 호출

        callback(null, 'three');

    }

], 

// callback (final)

function(err, result){

    console.log(result); // results가 아니고 result임

});


/*

[실행결과]

func2 args = 111, one

func3 args = 222

'three'

*/

















Posted by bloodguy
,