티스토리 뷰

728x90
반응형

Promise(=프로미스)는 자바스크립트 언어에서 사용되는 비동기 처리 객체입니다. Promise는 then, catch, async, await, try-catch 구문과 조합하여 동기, 비동기, 동기 처리 로직을 구성합니다. 앞에 언급한 키워드 사용법이 잘 기억나지 않으시면, 아래 포스팅 링크 참조 바랍니다. Promise.all 함수는 인자로 주어진 모든 프로미스를 실행하는 구문입니다. 이번 포스팅에서는 프로미스 여러 개를 동시에 실행할 수 있는 Promise.all을 사용하는 방법에 대해 알아보겠습니다.

 

[Node.js] Promise, Await, Async로 동기, 비동기 작성하기

비동기 처리는 함수를 호출하고 실행결과가 반환이 될 때까지 다른 작업을 진행하다가, 처리가 완료되었다는 이벤트를 수신하였을 때 작업을 마저 처리하는 방식입니다. Promise, Async를 이용하면

it-techtree.tistory.com

Promise.all 동작 이해하기

Promise.all은 인자로 넘겨진 모든 프로미스를 실행합니다. 간단한 예시를 작성하여 Promise.all의 실행 순서를 확인해보겠습니다. 코드 작성 및 실습 환경은 Node.js를 사용하였습니다. 

const testPromiseAll = async function() {
    let promise1 = new Promise((resolve, reject) => { resolve(1) })
    let promise2 = new Promise((resolve, reject) => { resolve(2) })
    let result = await Promise.all([promise1, promise2])
    console.log(result)
}
testPromiseAll()

// 실행결과
[ 1, 2 ]

프로미스의 실행 결과가 반환된 후 프로그램의 실행 흐름이 진행되도록 async와 await를 사용하였습니다. Promise.all를 사용할 때 Argument는 순회 가능한 object타입을 전달해야 합니다. 프로미스 객체를 2개를 생성 후 배열 타입으로 전달하여 프로미스 전체를 실행하였습니다. 반복문처럼 Promise.all 인자로 주어진 배열 항목에 저장된 프로미스를 순회하며 모두 실행하였다는 것을 이해할 수 있습니다. 개별적으로 프로미스를 정의하지 않고, 아래 코드와 같이 배열 형태로 프로미스 배열을 사용할 수 있습니다.  아래 코드는 위의 코드와 실행결과가 동일합니다.

let arr = [1,2]
let result = await Promise.all(arr.map(el => { return el }))

동기, 비동기 처리 방식을 조합하여 사용하는 방법

비동기 처리는 Non-blocking이므로, 작업의 효율이 좋습니다. 비즈니스 로직을 구현할 때, 모두 비동기 처리 방식으로 구현하면 좋을까요? 처리 순서가 중요할 때는 동기식으로 작업이 처리되도록 실행 흐름을 구성해야 합니다. 하지만, 일부 작업을 독립적으로 실행해도 무방하여 비동기 처리 방식으로 작업 처리 시간을 단축하고 싶은 경우도 있습니다. 이런 경우엔 동기-비동기 처리방식을 조합하여 작성해야 합니다.

반복문과 await으로 동기 처리하고, promise.all로 비동기 처리 로직 구현

promise, async, await, promise.all의 동작을 이해하였다면 손쉽게 동기, 비동기 처리 로직을 작성하실 수 있습니다. 반복문은 순서대로 실행되는 동기식 처리에 사용되는 문법입니다. Promise.all함수는 비동기 처리 로직을 다룰 때 사용하는 함수입니다. 반복문과 promise.all을 조합하여 사용하면, 기능 특징에 따라 순서 제어가 필요한 경우는 for문으로 처리하고, 독립적으로 작업 처리가 가능한 영역은 프로미스로 비동기 처리하여 작업의 효율을 높일 수 있습니다. 아래 코드는 비동기, 동기 처리 로직을 조합하여 작성한 코드 예시입니다.

let arr = [1, 2, 3]

const callPromise = async function(el) {
    console.log(time() + ' **  ' + el + 'callPromise start')
    await Promise.all(arr.map((data) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log(time() + ' *   printFunc' + data)
                resolve()
            }, 1000)
        })
    }))
    console.log(time() + ' **  ' + el + 'callPromise end')
}

const testPromise = async function() {
    for (const el of arr) {
        console.log(time() + ' *** ' + el + 'start')
        await callPromise(el)
        console.log(time() + ' *** ' + el + 'end')        
    }
}

function time() {
    var time = new Date()
    return time
}

testPromise()

소스코드에 대한 설명은 아래와 같습니다.

  • time : 함수가 호출된 시점의 시간을 반환합니다
  • testPromise : arr배열의 원소를 순회하며 callPromise함수를 호출하고, 함수의 결과가 반환될 때까지 기다립니다.
  • callPromise : arr배열의 원소 개수만큼 프로미스를 생성하여 Promise.all함수로 비동기 처리합니다. 실행된 모든 프로미스가 완료될 때까지 대기합니다.

스크립트를 실행해보면, callPromise함수에서 호출하는 Promise는 비동기로 실행되고, testPromise는 동기식으로 처리되고 있습니다. 아래 실행결과를 보면, settimeout함수가 비동기로 처리되어 1초 뒤 3번의 printFunc가 출력됩니다. testPromise의 경우는 callPromise 함수의 결괏값이 반환될 때까지 기다리므로, 1초마다 한 번씩 callPromise를 호출합니다.

동기, 비동기 처리 로직을 조합하여 실행한 결과

이 예제를 통해 동기, 비동기 처리 로직을 조합하여 작성하는 방법에 대해 알아보았습니다. 다음으로, Promise.all을 중첩하여 비동기 처리 효율을 극대화하는 방법에 대해 알아보겠습니다.

Promise.all을 중첩하여 비동기 처리 로직 작성하기

promise.all을 중첩하여 사용하는 경우는, HTTP 요청을 독립적으로 진행하는 경우에 많이 사용하는 방법입니다. RESTful API인 경우, 모든 요청에 대해 독립적으로 처리 가능합니다. 작업을 독립적으로 처리할 수 있는 구조라면, 비동기 로직으로 작성하여 애플리케이션 실행시간을 단축할 수 있습니다. 비동기 처리는 프로미스 단위로 작성하고, 여러 개의 프로미스는  promise.all을 이용하여 비동기로 실행 가능합니다. 위에서 작성한 testPromise함수를 아래와 같이 변경하면 Promise.all를 중첩하여 코드를 작성한 예시가 됩니다.

const testPromise = async function() {
    await Promise.all(arr.map(async (el) => {
        console.log(time() + ' *** ' + el + 'start')
        await callPromise(el)
        console.log(time() + ' *** ' + el + 'end')        
    }))
}

위의 코드를 실행해보면, 모든 작업이 비동기로 진행되어 병렬 처리된 것으로 보입니다. 총 3번의 프로미스 실행을 1초 만에 처리 하였습니다. 동기식에 비해 처리 시간을 상당히 단축할 수 있다는 것을 알 수 있습니다.

promise.all 중첩을 통해 비동기식 처리 성능을 개선한 결과

Node.js로 백엔드 서버 로직을 작성하면, 다른 시스템의 서버와 API 연계 로직을 작성해야 할 일이 많습니다. promise, await, async를 이용하면, 비동기, 동기 로직을 적절히 구성하여 애플리케이션의 성능을 최적화할 수 있습니다.

728x90
반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함