-
Node.JS 디자인 패턴 및 바이블 (4)JS 2021. 7. 29. 23:12728x90
대부분의 개발자분들이 프로그래밍을 처음 배우실 때 동기식으로만 배우셔서, 저도 마찬가지고 비동기 및 CPS로 코드를 작성하는데 많이 어려움을 겪고 계실겁니다.
책에서는 저와 같은 기본기가 딸리는?? 개발자들을 위해 Callback을 활용한 비동기 제어 흐름 패턴에 대해서 설명해주네요
🚀 비동기 프로그래밍의 어려움
책에서 이런 저런 이야기를 하지만 비동기가 어려운 이유는 저를 포함한 많은 개발자들이 익숙하지 않아서 그럴겁니다.
🚀 콜백 패턴
책에선 웹 크롤링을 만들면서 콜백패턴과 이를 기반으로한 다양한 접근방법을 소개합니다.
초기에 작성한 웹 크롤링은 우리가 말하는 콜백지옥과 같은 모습을 보여줍니다.
export const spider = (url, cb) => { fs.access(filename, err => { if (err && err.code === 'ENOENT') { superagent.get(url).end((err, res) => { if (err) cb(err) else { mkdirp(path.dirname(filename), err => { if (err) cb(err) else { fs.writeFile(filename, res.text, err => { if (err) cb(err) else cb(null, filename, true) }) } }) } }) } else cb(null, filename, false) }) }
이와 같은 콜백지옥을 벗어나기 위해서 위 책에서는 규칙을 제안합니다.
너무나 당연하게 저는 코드를 이러한 규칙에 맞게 작성하고 있더군요.
1. 콜백을 정의할 때 in-place 함수를 남용하지 않는다.
2. 가능한 코드를 빨리 종료시킨다.
3. 콜백을 위해 명명된 함수를 생성하며 외부에 배치하여 관리합니다.
4. 코드를 모듈화합니다.
🚀 콜백 패턴 - 순차실행
우리가 비동기에 어려움을 겪는 대부분의 케이스는 순차실행입니다.
자바스크립트의 최신스펙?이라고 하기도 뭐한 iterator / generator를 활용하면 간단하게 작성가능합니다만,
이 책에서는 기본기를 다지기 위해 콜백 패턴을 기반으로 순차실행을 구현합니다.
구현방법은 간단합니다. task queue와 콜백을 활용합니다.
const tasks = [ (cb) => { console.log('Task 1'), setTimeout(cb, 1000) }, (cb) => { console.log('Task 2'), setTimeout(cb, 1000) }, (cb) => { console.log('Task 3'), setTimeout(cb, 1000) } ] function iterate (index) { if (index === tasks.length) return finish() const task = tasks[index] task(() => iterate(index + 1)) } function finish () { // iteration completed console.log('All tasks executed') } iterate(0)
🚀 콜백 패턴 - 병렬실행
병렬은 프로그래밍 언어적으로 프로미스라는 멋있는 개체를 제공해줘서 쉽게 코드로 작성할 수 있습니다만, 역시 책은 직접 구현합니다.
앞서와 마찬가지로 task queue를 활용하고 병렬실행 갯수 제한을 위해 concurrency 값을 활용합니다.
function makeSampleTask (name) { return (cb) => { console.log(`${name} started`) setTimeout(() => { console.log(`${name} completed`) cb() }, Math.random() * 2000) } } const tasks = [ makeSampleTask('Task 1'), makeSampleTask('Task 2'), makeSampleTask('Task 3'), makeSampleTask('Task 4'), makeSampleTask('Task 5'), makeSampleTask('Task 6'), makeSampleTask('Task 7') ] const concurrency = 2 let running = 0 let completed = 0 let index = 0 function next () { // [1] while (running < concurrency && index < tasks.length) { const task = tasks[index++] task(() => { // [2] if (++completed === tasks.length) { return finish() } running-- next() }) running++ } } next() function finish () { // all the tasks completed console.log('All tasks executed!') }
🧑🏻💻 연습문제
1. 파일 연결
2. 재귀적 파일 리스트
3. 재귀적 검색
'JS' 카테고리의 다른 글
Node.JS 디자인 패턴 및 바이블 (3) (0) 2021.07.25 Node.JS 디자인 패턴 및 바이블 (2) (0) 2021.07.24 Node.JS 디자인 패턴 및 바이블 (1) (0) 2021.07.24 [Typescript] 1. 개론 (0) 2021.04.25 [Javascript] 6. 이벤트 처리 (0) 2021.04.25