작성 날짜 | 수정 날짜 |
---|---|
2021-01-07 | 2021-01-08 |
이번에 예전에 공부하면서 작성한 코드를 리팩토링할 일이 생겼다.
리팩토링 중 for문으로 범벅되어 있는 것을 이번에 forEach로 바꿔보려고 시도를 했다.
수정 전
const files = [
{ id: 1, name: 'first.txt' },
{ id: 2, name: 'second.txt' },
{ id: 3, name: 'third.txt' },
]
let fileName, file
let fileList = []
for (let i = 0; i < files.length; i++) {
file = await File.create({ files[i].name })
fileList.push(file.dataValues)
}
console.log(fileList)
실제 코드에서 로직 부분만 간추렸다.
수정 후
const files = [
{ id: 1, name: 'first.txt' },
{ id: 2, name: 'second.txt' },
{ id: 3, name: 'third.txt' },
]
let fileName, file
let fileList = []
files.forEach(async element => {
file = await File.create({ element.name })
fileList.push(file.dataValues)
})
console.log(fileList)
나는 forEach
를 활용해 위와 같이 코드를 작성했다.
기대 결과
[
{ id: 1, fileName: 'first.txt' },
{ id: 2, fileName: 'second.txt' },
{ id: 3, fileName: 'third.txt' }
]
나는 이전 코드에서 위와 같은 결과를 원했다.
현실
[]
하지만 실제 결과는 위와 같다.
왜 for문에서는 제대로 돌아가던 코드가 forEach로 전환했을 때 돌아가지 않는 것일까?
왜냐하면 forEach는 반복문의 종료를 기다리지 않기 때문이다. 반복문이 끝나지 않아도 다음 구문을 실행시킨다.
fileList 배열에 push하기 전에 fileList를 console.log로 출력하기 때문에, 빈 배열로 나오는 것이다.
이것을 해결하기 위한 방법은 크게 2가지가 있다. 그것은 순차 처리와 병렬 처리이다.
순차 처리
순차처리는 배열 요소마다 차례대로 비동기 작업을 수행하는 것이다.
로직의 실행 순서가 보장되어야할 때 사용한다.
병렬 처리
배열 요소에 대해서 한꺼번에 비동기 작업을 수행한다.
로직의 실행 순서가 중요하지 않을 때 사용한다.
실행 순서가 상관 없는 경우에 병렬 처리를 하는 것이 유리하다. 왜냐하면 병렬 처리가 속도가 더 빠르기 때문이다.
순차 처리에는 방법이 여러 가지가 있다.
- for (기존 방식)
- for...of
for...of
const files = [
{ id: 1, name: 'first.txt' },
{ id: 2, name: 'second.txt' },
{ id: 3, name: 'third.txt' },
]
let fileName, file
let fileList = []
for (let element of files) {
file = await File.create({ element.name })
fileList.push(file.dataValues)
}
console.log(fileList)
위와 같이 작성하면 제대로 작동하지만, 순차적으로 비동기 작업을 수행하기에 시간이 오래 걸린다.
Promise.all
과 map
을 활용해서 병렬 처리를 구현하면, 성능 면에서 매우 유리하다.
Promise.all + map
const files = [
{ id: 1, name: 'first.txt' },
{ id: 2, name: 'second.txt' },
{ id: 3, name: 'third.txt' },
]
let fileName, file
let fileList = []
const pushFile = async (file) => {
file = await File.create({ element.name })
fileList.push(file.dataValues)
}
const promises = files.map(file => pushFile(file))
await Promise.all(promises)
console.log(fileList)
코드 설명을 좀 해보겠다.
일단 기존 반복문에 들어가는 로직으로 이루어진 비동기 함수(pushFile)를 하나 만든다.
그리고 map을 이용해서 해당 promise 함수들을 엮어준다.
그리고 Promise.all을 사용해서 한꺼번에 병렬 처리한다.
for문에서 forEach문으로 바꿨을 때 작동하지 않는다고 당황하지 말고, Promise.all과 map을 사용하자.
'개발 공부 > Web (웹)' 카테고리의 다른 글
Docker [3/3] - NodeJS + PostgreSQL 연결 (0) | 2021.01.22 |
---|---|
Docker [2/3] - NodeJS 환경 구축 (0) | 2021.01.22 |
Docker [1/3] - 기초부터 이미지 생성까지 (0) | 2021.01.20 |
nodeJS는 JS 기반인데 어떻게 웹 서버로 사용할 수 있을까? (0) | 2020.09.28 |
livereload 사용법 (0) | 2019.01.25 |