파트10. 비동기 동시성 프로그래밍(2) - ChoDragon9/posts GitHub Wiki
지연 평가 + Promise - L.map, map, take
take, L.map 함수에서 Promise 일 때 동작하도록 수정하면 비동기 데이터와 동기 데이터를 같이 사용할 수 있다.
const take = curry((l, iter) => {
if (l === 0) return [];
let res = [];
iter = L.values(iter);
return function recur() {
let cur;
while (!(cur = iter.next()).done) {
const a = cur.value;
if (a instanceof Promise) {
return a
.then(a => (res.push(a), res).length == l ? res : recur())
.catch(e => e == nop ? recur() : Promise.reject(e));
}
res.push(a);
if (res.length == l) return res;
}
return res;
} ();
});
L.map = curry(function *(f, coll) {
for (const a of L.values(coll)) yield go1(a, f);
});
Kleisli Composition - L.filter, filter, nop, take
filter에 비동기도 전달되는 값의 평가가 거짓일 경우 Promise.reject를 사용합니다. Promise.reject에 인자는 Symbol('nop')이라는 값을 전달합니다. 해당 값을 take에서 처리하게 되면 filter 이후 함수들을 평가가 되지 않습니다.
go([1, 2, 3],
L.map(v => Promise.resolve(v * v)),
L.filter(v => v % 2),
take(2),
console.log);
L.filter = curry(function *(f, coll) {
for (const a of L.values(coll)) {
const b = go1(a, f);
if (b instanceof Promise) yield b.then(b => b ? a : Promise.reject(nop));
else if (b) yield a;
}
});
지연된 함수를 병렬적으로 평가하기 - C.reduce, C.take
지연평가되는 함수들은 평가가 되지 않은 상황에 reduce로 들어오게 됩니다. 그리고 reduce를 평가할 때 수직방향으로 실행하게 됩니다.
go(
[1, 2],
L.map(a => delay1000(a * a)),
L.filter(a => delay1000(a % 2)),
reduce(add),
console.log
)
전달되는 이터러블값을 실행하게 되면 모든 값을 병렬적으로 처리할 수 있습니다.
C.reduce = curry((f, acc, iter) => iter ?
reduce(f, acc, [...iter]) :
reduce(f, [...acc]);