JS Async Functionality 1 - Intro
이 글은 자바스크립트에서 비동기를 다룰 때 마주치는 개념들인 Promise, Generator, Async-Await을 큰 범위에서 다룬다. 중간 중간에 재밌는 패턴들도 수록했다.
Why Promise?
What’s Promise?
Promise는 순차적인 비동기 코드를 깔끔하게 짤 수 있게 하는 문법이다. 문법에 포함된Promise 객체
로 처리한다. Promise로 거의 모든 비동기를 처리한다고 해도 과언이 아니다.Promise가 익숙하지 않다면 MDN을 참고:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise > https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises
비동기 작업 시 순차적인 흐름을 많이 구현해야 하는데, CPS 방식으론 간결하게 짤 수 없다. CPS 패턴 사용 시의 Tip | JSQnA 참고.
Promise의 장점: (콜백과 관련한 비교에 대한 내용은 CPS 패턴 참고.)
- 프로미스 체인을 사용하면 작업들을 순차 실행시키는 일은 그리 어렵지 않다.
throw
를 프로미스 체인에서 사용할 수 있다.- catch 될 때까지 전체 체인에 오류를 자동으로 전파할 수 있다. 비동기 오류가 누락될 확률이 줄어든다.
- 동기적으로 값을 반환해도 비동기적인 호출을 보장한다. 함수가 동기, 비동기 반환을 섞어서 하는 것은 나쁘다.
Promise.all
함수를 통해 비동기 작업을 병렬로 실행할 수 있다. (이건 CPS도 가능)Promise.race
함수를 통해 비동기 작업 중 가장 먼저 수행이 끝난 결과만 사용할 수 있다. (CPS에선 직접 구현해야 함.)
Promise로 함수 배열을 순차적으로 실행하는 패턴 (현재 이해 부족으로 인해 수정 필요함.):
책에 재밌는 코드가 있어 가져왔다. Promise로 함수의 배열을 순차적으로 실행하는 방법이 있을까?
1 | // sequential :: Array(() => Promise) => Promise |
reduce로도 가능하다:
1 | const tasks = [ |
제한된 개수로 병렬 실행하기: (현재 이해 부족으로 인해, 추후 삽입 예정)
ES8 비동기 함수
정의에 대한 자세한 내용은 MDN async function, MDN AsyncFunction 생성자를 참고하라.
ES7 비동기 함수는 비동기적으로 동작하는, async
, await
문법이 활용된 함수이다.
(설명 보충 예정.)
Why Generator?
What’s Generator?
Generator는 시작 지점이 여러 개이며 중간에 실행을 정지/재개할 수 있는 함수이다.
- 시작 지점이 여러 개: 다른 시작 지점에 대해 매번 새로운 arguments로 호출할 수 있다.
- 정지/재개할 수 있다: 제너레이터 함수는 실행 후 값을 반환할 때 정지한다. 이후 호출하면 다시 재개된다.
Generator가 익숙하지 않다면 MDN을 참고:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator
시작하기 전에 아래 두 코드의 결과를 모르겠다면 이후 내용을 이해하기 어려우므로, Generator에 대해 추가적으로 공부를 하기 바란다.
1 | // Generator Example 1 |
Generator with CPS into Async-Await:
놀랍게도 Generator에 약간의 양념을 치면 ES7 비동기 함수를 만들어낼 수 있다.
1 | const fs = require('fs'); |
try-catch
Async-Await과 유사하게, 제너레이터에는 throw
API가 있는데, 제너레이터 함수 내에서 try-catch
로 이를 처리할 수 있다:
1 | const twoWay = twoWayGenerator(); |
참고자료 전문: Async-Await ≈ Generators + Promises
참고 2: Difference between async/await and ES6 yield with generators | StackOverFlow
참고 3: ES2017 - Async vs. Yield | StackOverFlow
하나의 API로 CPS와 Promise 모두 지원하는 방법
mongoose와 같은 많은 라이브러리는 CPS와 Promise 방식을 모두 지원한다. 어떻게 한 함수로 동시에 지원할 수 있을까? 아래 코드와 같이 구현한다면 가능하다.
1 | // 마지막 인자로 callback 함수를 받는다. |
장점:
- Promise, CPS 패턴 사용자 모두에게 기능을 제공할 수 있다.
비동기와 함수형 자바스크립트
Javascript는 순수한 함수형 언어가 아니므로, 모든 코드를 함수형 패러다임을 적용해서 작성할 수 없다고 한다. 비동기를 다루는 코드에 있어서는, 특히 async-await 키워드를 사용하여 작성할 때는 명령형 코드가 되므로, 더 함수형과 멀어지게 되는데, 결론적으론 Javascript에서 함수형 패러다임을 실천할 때에는 함수형인 코드 베이스와 그렇지 않은 부분으로 나누는 게 좋다고 한다. 또한 Promise든 Async-Await이든 하나를 택해서 통일하는 게 좋다고 하니 참고 바란다.
전문: JS: Promises, async/await, and functional programming.
TODO:
- Generator는 아직도 공부 중이다. Iterable 프로토콜에 대한 얘기도 있고, 비동기 처리 외에 Generator의 쓰임새나 Generator 자체 개념에 대해 더 공부해야 한다.
- 코루틴에 대해서도 공부해봐야 할 것 같다. 공부 중 접하게 된 키워드이다.
- 제너레이터에 대한 설명을 보강해야겠다.
- 이해가 완료되면 자체 제작한 예제 코드로 교체한다.
JS Async Functionality 1 - Intro