avatar
Published on

map과 reduce에서 async await 사용하기

Author
  • avatar
    Name
    yceffort
function sayHello(name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(`Hello, ${name}`), 2000)
  })
}

const message1 = await sayHello('yceffort')
console.log(message1)

요런 비동기 함수가 있고, 이를 map으로 처리한다고 가정해보자.

const names = [
  'yceffort1',
  'yceffort2',
  'yceffort3',
  'yceffort4',
  'yceffort5',
  'yceffort6',
]

const messages = names.map(async (name) => await sayHello(name))
console.table(messages)

이렇게 하면 될 것 같지만?

(6) [Promise, Promise, Promise, Promise, Promise, Promise]
0: Promise {<pending>}
1: Promise {<pending>}
2: Promise {<pending>}
3: Promise {<pending>}
4: Promise {<pending>}
5: Promise {<pending>}

아쉽게도 모든 결과가 pending으로 뜬다. awaitPromise 객체만 기다려 주기 때문에 그런 것으로 보인다. 반변에 우리가 넘긴 것은 list다.

따라서 이를 정상적으로 실행하기 위해서는 Promise.all을 사용해야 한다.

const promiseMessages = await Promise.all(
  names.map(async (name) => await sayHello(name)),
)
console.log(promiseMessages)
;[
  'Hello, yceffort1',
  'Hello, yceffort2',
  'Hello, yceffort3',
  'Hello, yceffort4',
  'Hello, yceffort5',
  'Hello, yceffort6',
]

그렇다면 reduce의 경우에는 어떻게 처리하면 좋을까?

const oddMessages = names.reduce(async (prev, current, index) => {
  if (index % 2 > 0) {
    return [...prev, await sayHello(current)]
  } else {
    return prev
  }
}, [])

이렇게 하면 당연히 안될 것이다. 여기에서 prev는 기존의 값이 아닌 Promise일 것이다.

const oddMessages = await names.reduce(async (prev, current, index) => {
  const prevResult = await prev.then()
  if (index % 2 === 0) {
    const result = await sayHello(current)
    return Promise.resolve([...prevResult, result])
  } else {
    return Promise.resolve(prevResult)
  }
}, Promise.resolve([]))

기존에 있던 모든 return을 Promise.resolve로 감싸고, 이전에 넘어온 prevthen처리를 했다.

;['Hello, yceffort1', 'Hello, yceffort3', 'Hello, yceffort5']