본문 바로가기
JavaScript&Typescript

비동기 처리-3

by 스르나 2021. 1. 30.
  1. Promise.all
  2. Promise.race
  3. 병렬처리의 에러상황

 

1. 비동기 처리를 병렬로 처리하기 - Promise.all

 

비동기 처리를 처리하기위해 Promise, async,await의 사용방법을 알아 봤다

 

그런데 비동기처리에서 중요하게 생각해야 할것이 있다. 비동기 처리를 병렬로 처리하는 것이다.

 

const work=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log('작업 1')
            resolve()
        },2000)
    });    
}

const work2=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log('작업 2')
            resolve()
        },2000)
    })
}

const work3=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log('작업 3')
            resolve()
        },2000)
    })
}

const foo=async ()=>{
    const data1=await work();
    const data2=await work2();
    const data3=await work3();
}

foo();

 

위의 코드를 보자 work함수들을 await를 통해 비동기 처리지만 순차적으로 처리하고 있다.

 

그런데 위와같이 비동기 처리들이 서로 영향이없을때 (각각의 함수들이 공통된 변수를 다루지 않을때) 이렇게 순차적으로 처리된다면 그건 매우 비효율적이다. 위의 코드는 처음부처 차례로 2초씩 총 6초가 소요된다.

 

이런 문제를 해결하는 방법이 Promise.all이다 Promise.all은 인자로 넘겨준 iterable한 Promise들을  병렬로 처리한다.

 

const work=(name)=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log('작업 1')
            resolve(name)
        },200*Math.random())
    });    
}

const work2=(name)=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log('작업 2')
            resolve(name)
        },200*Math.random())
    })
}

const work3=(name)=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log('작업 3')
            resolve(name)
        },200*Math.random())
    })
}

Promise.all([work('hello'),work2('nice'),work3('good')]).then(value=>{console.log(value)})

이번에는 Promise.all을 통해 병렬로 처리한 코드이다. 우선 먼저본 코드와의 차이를 보자

setTimeout의 시간을 랜덤하게 줬다. 이유는 동일하게 주면 서로 블록킹을 하기때문이다. 그렇게 되면 병렬로 처리하는 의미가 없이 직렬로 처리가된다.

 

다음 차이점은 각 work함수에 인자를 주었고 resolve로 인자를 다시 주었다. 인자를 준이유는 Promise.all의 then에 어떤 결과가 들어가는지 보기 위해서이다.

 

그럼 실행 결과를 보자

 

결과를 보면 1,2.3순서대로가 아닌 2,3,1순서로 진행이 되었다.

 

그렇지만 then에는 1,2.3순서대로의 값이 들어간다.

 

즉, 실행완료시점은 다르지만 결과값을 받는것은 순서가 동일하다.

 

Promise.all의 주의점은 병렬로 진행이 되기때문에 동일한 변수를 사용하면 예상하지 못한 결과값을 얻을 수 있다는 것이다. 이점을 꼭 염두해두고 사용하자.

 

그 예시를 바로한번 보고 마치자

 

let num=10
const foo1=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            num+=1
            console.log('one')
            resolve(`one ${num}`)
        },200*Math.random())//200*Math.random()         
    })
}

const foo2=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            num+=2
            console.log('two')
            resolve(`two ${num}`)
        },200*Math.random())    
    })
}

const foo3=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            num*=3
            console.log('three')
            resolve(`three ${num}`)
        },200*Math.random())      
    })
}

Promise.all([foo1(),foo2(),foo3()]).then(value=>{console.log(value)})

결과는 아래와 같다.

 

결과가 실행할 때마다 다른것을 볼 수 있다.

 

 

2. Promise.race

다음으로 볼것은 Promise.race인데 Promise.race는 Promise.all과 비슷하지만 가장 먼저 실행이 완료된것의 결과만 받아오는 것이다. 실행이 느린것도 마지막까지 실행이 완료가 되지만 결과값을 받는 then에는 가장 먼저 완료된것의 결과만 받는다.

 

아래 코드와 결과를 보면 쉽게 이해가 갈것이다.

 

let num=10
const foo1=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            num+=1
            console.log('one')
            resolve(`one ${num}`)
        },200*Math.random())//200*Math.random()         
    })
}

const foo2=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            num+=2
            console.log('two')
            resolve(`two ${num}`)
        },200*Math.random())    
    })
}

const foo3=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            num*=3
            console.log('three')
            resolve(`three ${num}`)
        },200*Math.random())      
    })
}

Promise.race([foo1(),foo2(),foo3()]).then(value=>{console.log(value)})

빨간색 밑줄친것이 결과인데 결과가 한개인것을 볼 수 있고 다른 Promise들도 실행이 완료된것을 볼 수 있다.

 

 

3. 병렬처리의 에러상황

 

병렬처리의 마지막으로 처리도중 에러가 났을때의 결과인데 병려로 처리하던 중 에러가 발생하면 에러가 가장 먼저 발생한것을 바로 리턴하고 종료한다.

 

let num=10
const foo1=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            num+=1
            throw 'error!!!'
            console.log('one')
            resolve(`one ${num}`)
        },200*Math.random())//200*Math.random()         
    })
}

const foo2=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            throw 'error!'
            num+=2
            console.log('two')
            resolve(`two ${num}`)
        },200*Math.random())    
    })
}

const foo3=()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            num*=3
            console.log('three')
            throw 'error!!!!!!'
            resolve(`three ${num}`)
        },200*Math.random())      
    })
}

Promise.all([foo1(),foo2(),foo3()]).then(value=>{console.log(value)}).catch(error=>{console.log(error)})


 

'JavaScript&Typescript' 카테고리의 다른 글

비동기 처리 -2  (0) 2021.01.28
비동기 처리-1  (0) 2020.12.18