이터러블을 다루는 많은 함수들은 map, filter, reduce를 뼈대로 응용해서 함수합성등을 통해 (ex: L.map + takeAll, flatMap...) 응용 함수들을 만들었습니다.
L.map, map, take는 기본적으로 동기적으로 돌아가는 상황에서만 정상적인 동작을 보장했습니다. reduce, pipe등 비동기상황에서도 동작하는 이런 함수들처럼 L.map, map, take함수들도 비동기적 상황에서도 정상동작하도록 코드를 리팩토링 해보겠습니다.
go([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)],
L.map(a=>a+10),
take(2),
log
);//"[object Promise]10", "[object Promise]10"]
const go1 = (a, f) => a instanceof Promise ? a.then(f) : f(a);
L.map = curry(function* (f, iter) {
for (const a of iter) {
yield go1(a,f);
}
});
...
go([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)],
L.map(a=>a+10),
take(2),
log
);
//실행결과
//0: Promise {<fulfilled>: 11}
//1: Promise {<fulfilled>: 12}
이제 프로미스에 map의 인자값으로 받은 함수는 적용되어 11,12과 되었습니다. 이제 Promise안에 들어있는 값을 꺼내보도록 합니다.
const take = curry((l, iter) => {
let res = [];
iter = iter[Symbol.iterator]();
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())
res.push(a);
if (res.length === l) return res;
}
return res;
}();
});
go([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)],
L.map(a=>a+10),
take(2),
log
);//[11,12]
기존 take 함수에서 currentValue(cur.value)이 Promise일 경우 내부의 값을 then을 통해 res Array에 넣어준 뒤 재귀적으로 다시 유명함수 recur()를 호출해 문제를 해결하고 있습니다.
go(
[Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)],
map(a => Promise.resolve(a+10)),
take(2),
log
)//[11,12]
go(
[2,3,4],
map(a => Promise.resolve(a+10)),
take(2),
log
)//[11,12