promise를 통한 동기 호출을 공부하다가 array.reduce의 몰랐던 활용법을 알게 되어 정리해보았다.
일단 reduce의 기본 형태는 아래와 같다.
arr.reduce(callback[,initialValue])
- Callback
- acc : 콜백의 반환값을 누적할 공간
- val : 처리할 현재 값
- index : 현재의 인덱스 (선택)
- array : reduce()를 호출할 배열(선택)
- InitiailValue (선택)
- callback의 최초 호출에서 첫 번째 인수에 제공하는 값.
- 지정하지 않는다면 배열의 첫 번째 요소가 저장됨
설명만 봤을때는 처음 떠오르는 생각은 누적합이었고, 실제로 reduce예제를 찾아보면 누적합이 가장 많이 보인다. 나 역시 reduce를 배울 때 누적합 할 때 가장 많이 사용하겠구나 생각하고 그 이후로, reduce를 사용하지 않았었는데 이번에 공부하다가 나름 충격적인 예제를 보았다.
이 예제는 값들을 Promise와 reduce를 이용하여 동기적으로 호출하는 예제이다.
function delay_word(word, delay) {
return new Promise(resolve => {
setTimeout(function (){
resolve(word)
}, delay)
})
}
const array = [{word:'Hi', delay:500}, {word:'My', delay:490}, {word:'Friend', delay:480}
, {word:'Good', delay:470}, {word:'Day', delay:460}]
array.reduce((prev, item) => {
return prev.then(() =>
delay_word(item.word, item.delay).then((promise) => {console.log(promise)}))
}, Promise.resolve())
이 예제를 보고 reduce가 어떻게 작동하는 것인지 이해가 안되어 나름대로 정리해보았다.
첫 번째로 reduce의 핵심은 `InitialValue'이다. InitalValue에 따라서 reduce가 하는 역할이 단순 누적합뿐만 아니라 다양해질 수 있는 것이다. 즉 초기값의 타입에 따라 다양한 연산이 가능해지는 것이다.
두 번째로 Promise.resolve()이다. 이 예제에서 초기값으로 주어지는 객체인데 이 객체는 이행된 Promise를 반환한다.
위 두가지를 활용하여 이해한 바로는 prev는 초기값인 Promise.resolve()이고 then을 가질 수 있는 값이기 때문에 바로 동기 호출이 가능해졌다. 이런 이유로 모든 배열을 순회하는 reduce함수가 호출된 콜백 함수를 기다리면서 진행할 수 있고 동기적으로 값을 처리하게 된다.
어차피 return값이 중요한 게 아닌 것처럼 보이는데 forEach구문을 써도 되지 않을까라는 생각에 forEach문과 차이점을 고민해 보았고 확실히 차이점을 확인할 수 있었다.
const array = [{word:'Hi', delay:500}, {word:'My', delay:490}, {word:'Friend', delay:480}
, {word:'Good', delay:470}, {word:'Day', delay:460}]
array.forEach((item) => {
delay_word(item.word, item.delay).then((resolve) => {console.log(resolve)})
})
일단 결과는 forEach는 동기적으로 호출하지 못한다.
그 이유는 forEach가 배열을 돌면서 함수를 실행할 때 그 함수가 WEB API를 호출해야 하는 함수라면 Web API에게 맡기고 결과를 기다리지 않고 다음 배열로 넘어가기 때문이다.
하지만 위의 예제인 reduce는 그렇지 않다. 그 이유는 초기값이 Promise.resolve()이기 때문에 바로 reduce가 순회하지 않고 대기할 수 있게 만들 수 있기 때문이다.
만약 forEach를 활용하여 동기적으로 호출하기 위해서는 프로미스 객체들을 하나의 배열에 넣어서 프로미스객체들을 순회하며 동기적으로 호출해야 한다.
코드로 나타낸다면 아래와 같다.
const promise_list = []
array.forEach((item) => {
const promise = delay_word(item.word, item.delay)
promise_list.push(promise)
})
Promise.all(promise_list).then((values) => {
values.forEach((resolve) => {console.log(resolve)})
})
위 코드처럼 forEach구문으로 promise 객체까지만 만들어놓고 Promise.all함수를 통해서 모든 값들을 동기적으로 수행한 후 반환한다.
동기 / 비동기 예제를 공부하다가 생각지도 못한 reduce에 막혀서 나름대로 정리해보았지만, 아직 이해가 완벽히 되지 않아 조금 더 공부해봐야 할 것 같다..
'CS' 카테고리의 다른 글
[JS] this (feat : 코어 자바스크립트) (0) | 2022.12.15 |
---|---|
[JS] 실행컨텍스트 (feat : 코어 자바스크립트) (0) | 2022.12.14 |
[JS] undefined와 null (feat : 코어자바스크립트) (0) | 2022.12.13 |
[JS] 기본형데이터와 참조형데이터 (feat : 코어자바스크립트) (0) | 2022.12.12 |
[JS, React] ref, useRef (0) | 2022.08.25 |