[async/await]
- 내가 프로미스를 써서 평가 시점을 다룬다거나 하려면 asyn await말고 직접써야된다
- async/await는 그냥 Promise 쓴것을 사용하도록 도와줄 뿐이다
function delay(time) {
return new Promise(resolve => setTimeout(() => resolve(), time));
}
async function delayIdentity(a) {
await delay(500);
return a; // Promise 리턴
}
async function f1() {
const a = await delayIdentity(10);
const b = await delayIdentity(5);
return a + b; // Promise 리턴
}
f1(); // Promise
f1().then(log); // 15
go(f1(), log); // 15
const pa = Promise.resolve(10);
(async () => {
log(await pa); // 10 // 이렇게 꺼내볼수 있다
})();
[Q&A]
[Array.prototype.map이 있는데 왜 FxJS의 map 함수가 필요한지?]
function delayI(a) {
return new Promise(resolve => setTimeout(() => resolve(a), 100));
}
// Array.prototype.map 로 Promise 제어 해보기
async function f2() {
const list = [1, 2, 3, 4];
const temp = list.map(async a => await delayI(a * a));
log(temp);// Prmoise의 배열
// 아무리 async 함수를 쓴다고해도 map이 Promise를 제어해주지 않기 때문에
// 해당 문제가 해결이 되지 않는다
const res = await temp;
// temp는 그냥 배열이라서 이위에 await를 달아서 풀려고 해도 풀 수 없는것
log(res);
}
f2();
// FxJS map 로 Promise 제어 해보기
async function f3() {
const list = [1, 2, 3, 4];
const temp = map(a => delayI(a * a), list);
log(temp);// Promise pending // 미리 배열을 다만들어서 배열자체가 pending 되어 있게 되어있음
const res = await temp;
log(res); // [1 4 9 16]
}
f3();
function f4() {
return map(a => delayI(a * a), [1, 2, 3, 4]);
}
(async () => {
log(await f4()); // Promise를 전달받아서 async await를 품
})();
[이제 비동기는 async/await로 제어할 수 있는데 왜 파이프라인이 필요한지?]
둘은 전혀 다른 상황의 해결책, 그것을 해결하기 위한 기술 이다
- async/await 는 Promise then then으로 이어진 부분이 이질적이다 보니 이키워드를 통해서 특정 부분에서 함수 체인이 아닌 문장형으로 다루기 위한 것
- async await 는 합성이 아닌 풀어 놓기 위한것
- 파이프라인의 목적은 비동기 프로그래밍이 아닌 안정적으로 함수를 합성하기 위한게 목적!
- 로직을 테스트하기 쉽게 만들고
- 유지보수 좋게 만들고
- 둘이 비슷하다고 느끼게 되는것은 파이프라인으로 했을때도 비동기나 동기나 비슷하게 표현되기 때문에 혼돈이 되는것
function f5(list) {
return go(list,
L.map(a => delayI(a * a)),
L.filter(a => delayI(a % 2)),
L.map(a => delayI(a + 1)),
C.take(2),
reduce((a, b) => delayI(a + b)));
}
go(f5([1, 2, 3, 4, 5, 6, 7, 8]), a => log(a, 'f5'));
// f5의 파이프라인은 단순히 명령형적인 부분을 함수형을 고치는데 제일 큰 목적이 있다
// 테스트도 쉽고 유지보수도 쉽다
// take 대신 C.take를 써서 최대한 빠르게 실행도 가능하다
// f5를 async await로 명령형으로 풀어써 본 f6
async function f6(list) {
let temp = []
for (const a of list) {
const b = await delayI(a * a);
if (await delayI(b % 2)) {
const c = await delayI(b + 1);
temp.push(c);
if (temp.length == 2) break;
}
}
let res = temp[0], i = 0;
while (++i < temp.length) {
res = await delayI(res + temp[i]);
}
return res;
}
// 동기 비동기가 없는상황이 되면 엄청난 변화가 또 필요하다
// 재활용이 불가능한 코드
// 이 코드가 위 코드로 변하는것도 상당히 어렵다
// 아래 코드가 위 코드처럼 동시성 으로 최대한 빠르게 처리하려고하면 엄청난 변화가 또 필요하다
go(f6([1, 2, 3, 4, 5, 6, 7, 8]), log);
// async await와 파이프라인은 쓰는 목적이 다르다
[async/await와 파이프라인을 같이 사용하기도 하나요?]
async function f52(list) {
const r1 = await go(list,
L.map(a => delayI(a * a)),
L.filter(a => delayI(a % 2)),
L.map(a => delayI(a + 1)),
C.take(2),
reduce((a, b) => delayI(a + b)));
const r2 = await go(list,
L.map(a => delayI(a * a)),
L.filter(a => delayI(a % 2)),
reduce((a, b) => delayI(a + b)));
const r3 = await delayI(r1 + r2);
return r3 + 10;
}
go(f52([1, 2, 3, 4, 5, 6, 7, 8]), a => log(a, 'f52'));