비동기 함수를 go와 pipe 안에서 쓸 때 async/await를 자연스럽게 섞을 수 있다.
const delayIdentity = a => new Promise(res => setTimeout(() => res(a), 500));
const f1 = pipe(
L.range,
L.map(delayIdentity),
L.filter(a => a % 2),
take(3),
reduce(add)
);
go(f1(5), log); // 1+3 = 4
async/await로 작성해도 결과는 같다.
(async () => {
const result = await f1(5);
log(result);
})();
go에 넘긴 f1(5)가 Promise를 반환하고, await로 기다리면 된다. 함수형 파이프라인과 async/await는 충돌하지 않는다.
Array.prototype.map에 async 함수를 넘기면 Promise 배열이 반환된다.
const result = [1, 2, 3].map(async a => await delayIdentity(a + 10));
log(result); // [Promise, Promise, Promise]
각 값을 꺼내려면 Promise.all이 필요하다.
log(await Promise.all(result)); // [11, 12, 13]
FxJS의 map은 다르다.
go(
[1, 2, 3],
map(async a => await delayIdentity(a + 10)),
log
); // [11, 12, 13]
FxJS map은 내부에서 reduce를 쓰고, reduce는 중간에 Promise가 나오면 .then으로 이어간다. go도 마찬가지로 Promise를 .then으로 처리하기 때문에 log가 받는 값은 이미 해소된 [11, 12, 13]이다. Promise.all을 따로 써야 하는 번거로움이 없다.
동시성 제어가 필요할 때도 차이가 난다.
go(
[1, 2, 3],
L.map(async a => await delayIdentity(a + 10)),
take(2),
log
);
L.map이면 take(2)가 2개만 요청하고 나머지는 실행하지 않는다. Array.prototype.map은 모든 Promise를 즉시 만들기 때문에 3번 모두 실행된다. 지연 평가와 비동기를 함께 활용할 때는 FxJS 방식이 유리하다.