요즘에는 node.js에서 async/await, promise를 지원해줘서 주로 쓰지만 처음 입문하엿을 땐 지원이 안 되서 async 모듈을 주로 썻엇다. 지금도 종종 애용하는 중
순차적 처리 series, waterfall이 잇다.
series 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const async = require ('async' );const a = (cb ) => { setTimeout (() => { cb(null , 1 ); }, 4000 ); }; const b = (cb ) => { setTimeout (() => { cb(null , 2 ); }, 1000 ); }; const c = (cb ) => { setTimeout (() => { cb(null , 3 ); }, 2000 ); }; async .series([a, b, c], (err, results ) => { if (err) { console .log('err' , err); } else { console .log('results' , results); } });
함수의 실행 시간에 상관 업이 호출한 순서대로 실행 결과를 배열에 받는다.
함수의 콜백을 호출할 때 에러 처리를 할 경우 에러는 첫 인자에, 결과는 두 번째 인자에 넣어야 한다.
waterfall 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const async = require ('async' );const a = (cb ) => { setTimeout (() => { cb(null , 1 ); }, 4000 ); }; const b = (data, cb ) => { setTimeout (() => { cb(null , data + 2 ); }, 1000 ); }; const c = (data, cb ) => { setTimeout (() => { cb(null , data + 3 ); }, 2000 ); }; async .waterfall([a, b, c], (err, result ) => { if (err) { console .log('err' , err); } else { console .log('result' , result); } });
waterfall도 함수의 실행 시간과 상관 업이 호출한 순서대로 실행을 하는데
series와 다른 점은 각 함수의 결과를 다음 함수에 파라미터로 넘길 수가 잇다.
마찬가지로 각 함수의 콜백의 첫 인자는 에러, 두 번째 인자는 넘길 데이터이다.
병렬 처리 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const async = require ('async' );const a = (cb ) => { setTimeout (() => { cb(null , 1 ); }, 2000 ); }; const b = (cb ) => { setTimeout (() => { cb(null , 2 ); }, 3000 ); }; async .parallel([a, b], (err, results ) => { if (err) { console .log('err' , err); } else { console .log('results' , results); } });
동시에 호출한 함수들이 모두 완료되어야 호출한 순서대로 응답을 배열로 받는다.
반복 each와 eachSeries가 잇다.
each 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 const async = require ('async' );const arr = [];for (let i = 0 ; i < 10 ; i++) { arr.push(i); } const a = (_param, cb ) => { const random = Math .floor(Math .random() * 3 ) + 1 ; setTimeout (() => { cb(_param); }, random); }; const results = [];async .each(arr, (item, callback ) => { a(item, (data ) => { results.push(data); callback(); }); }, (err ) => { if (err) { console .log('err' , err); } else { console .log('results' , results); } });
each는 반복할 함수의 실행 시간에 따라 빨리 처리되는 순서대로 응답을 한다.
1 results [ 0, 6, 7, 8, 1, 4, 5, 2, 3, 9 ]
eachSeries 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 const async = require ('async' );const arr = [];for (let i = 0 ; i < 10 ; i++) { arr.push(i); } const a = (_param, cb ) => { const random = Math .floor(Math .random() * 3 ) + 1 ; setTimeout (() => { cb(_param); }, random); }; const results = [];async .eachSeries(arr, (item, callback ) => { a(item, (data ) => { results.push(data); callback(); }); }, (err ) => { if (err) { console .log('err' , err); } else { console .log('results' , results); } });
eachSeries는 무조건 반복할 함수의 실행 시간과 상관 업이 요청한 순서대로 응답을 한다.
단 그 만큼 데이터가 클 수록 실행 시간이 늘어난다.
1 results [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
여기 적은 건 내가 주로 쓰던 거들이고 이외에도 많은 기능 등이 잇으므로 한 번씩 봐두도록 하자.
주의점 예로 series를 쓸 때 이러한 경우가 잇을 수 잇다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 const async = require ('async' );let x = 100 ;const a = (cb ) => { setTimeout (() => { x += 10 ; cb(null , 1 ); }, 4000 ); }; const b = (cb ) => { setTimeout (() => { cb(new Error ('ㅠㅠ' )); }, 1000 ); }; const c = (cb ) => { setTimeout (() => { cb(null , 3 ); }, 2000 ); }; async .series([a, b, c], (err, results ) => { if (err) { console .log('err' , err, 'x' , x); } else { console .log('results' , results); } });
첫 함수는 잘 동작햇지만 두번 째 함수에선 처리 중에 에러가 발생햇다고 치자.
이러면 실행 결과가 어떠케 될까?
1 2 3 4 5 6 err Error: ㅠㅠ at Timeout.setTimeout [as _onTimeout] (/Volumes/Seagate Slim Drive/project/nodejs/async-example/error.js:15:8) at ontimeout (timers.js:436:11) at tryOnTimeout (timers.js:300:5) at listOnTimeout (timers.js:263:5) at Timer.processTimers (timers.js:223:10) x 110
그렇다. 첫 함수는 정상적으로 작동되엇기에 x는 증가가 되버렷다.
만약 각 함수마다 db에 뭔가 갱신을 하는 코드라면 좀 골치가 아파질수도 잇다.
예외 처리를 잘 생각하자.