바쁘신 분을 위한 짧은 요약
promise.all 을 활용하여 그룹화 된 promise 수행을 통해 async 함수를 효과적으로 빠르게 수행합니다.
출처 : https://medium.freecodecamp.org/avoiding-the-async-await-hell-c77a0fb71c4c
비동기(async)는 콜백지옥(callback hell)에서 우리를 자유롭게했습니다. 하지만 이는 잘못된 사용으로 인해 비동기 지옥(async hell)의 탄생으로 이어졌습니다.
이 글에서는 async / await 이 무엇인지 설명하며, 비동기 지옥 탈출을위한 몇 가지 팁을 공유합니다.
async / await 지옥이란 무엇입니까?
async 자바스크립트로 작업하는 동안 사람들은 여러 문장을 차례로 작성하고 함수 호출 전에 기다리고 있습니다. 이로 인해 하나의 명령문이 이전 명령문에 의존하지 않아도, 이전 명령문이 완료 될 때까지 기다려야합니다.
async / await hell의 예
피자와 술 주문을 위한 코딩을 생각해보십시오.
(async () => {
const pizzaData = await getPizzaData() // async call
const drinkData = await getDrinkData() // async call
const chosenPizza = choosePizza() // sync call
const chosenDrink = chooseDrink() // sync call
await addPizzaToCart(chosenPizza) // async call
await addDrinkToCart(chosenDrink) // async call
orderItems() // async call
})()
겉으로 보기에는 정확하고 잘 동작합니다. 하지만 실제론 좋은 구현은 아닙니다. 이제 문제를 인식하고 해결해 보도록 합시다.
설명
비동기 함수를 즉시 실행함수로 래핑했습니다. 이는 아래 순서로 발생합니다.
1 피자 목록 획득.
2 음료 목록을 획득.
3 목록에서 피자 선택.
4 목록에서 음료 선택.
5 선택한 피자를 장바구니 담기.
6 선택한 음료를 장바구니 담기.
7 장바구니 항목 주문.
뭐가 잘못됬나 ?
앞서 강조했듯이, 이 모든 구문은 하나씩 실행되며 여기에는 동시성이 없습니다.
잘 생각해 보세요 : 왜 우리는 음료 목록을 가져오기 전에 피자 목록을 가져오려 기다리는 중입니까? 단, 피자를 선택할 때 피자 목록을 미리 준비해야합니다. 음료수도 마찬가지입니다.
따라서 피자와 관련된 작업이 동시에 진행될 수 있으나, 피자 관련 개별 단계는 순차적으로 (하나씩) 수행되어야합니다.
나쁜 구현의 또 다른 예
아래 코드는 장바구니에있는 항목을 가져 와서 주문을 수행하는 것입니다.
async function orderItems() {
const items = await getCartItems() // async call
const noOfItems = items.length
for(var i = 0; i < noOfItems; i++) {
await sendRequest(items[i]) // async call
}
}
이 경우 for 루프는 다음 반복을 계속하기 전에 sendRequest() 함수가 완료 될 때까지 대기해야합니다. 그러나 실제로 기다릴 필요는 없습니다. 모든 요청을 가능한 한 빨리 보내고 모든 요청이 완료 될 때까지 기다릴 수 있습니다.
async / await 지옥이 무엇인지 이제 감이 오시나요 ?
await 키워드가 사라진다면 ?
비동기(async) 함수를 호출하는 동안 기다리는 것(await)을 빼면 함수가 바로 실행되기 시작합니다. 즉, 함수를 실행하는 데 대기 시간이 필요하지 않습니다. 비동기(async) 함수는 나중에 사용할 수있는 약속(Promise)을 반환합니다.
또 다른 결과는 컴파일러가 함수가 완전히 실행될 때까지 기다리고 싶다는 것을 알지 못한다는 것입니다. 따라서 컴파일러는 비동기 작업을 끝내지 않고 프로그램을 종료합니다. 그래서 우리는 await 키워드가 필요합니다.
약속(Promise)의 한 가지 재미있는 속성은 한 줄에 약속(Promise)을하고 다른 약속(Promise)을 해결할 때까지 기다릴 수 있다는 것입니다. 이것은 async / await hell을 피하는 열쇠입니다.
(async () => {
const promise = doSomeAsyncTask()
const value = await promise
console.log(value) // the actual value
})()
보시다시피 doSomeAsyncTask()가 약속(Promise)을 반환합니다. 이 시점에서 doSomeAsyncTask()가 실행을 시작했습니다. 약속의 해결 된 값을 얻기위해 await 키워드를 사용하면 JavaScript가 다음 줄을 즉시 실행하지 않고 결과를 확인한 후 실행하라는 약속(Promise)을 기다립니다.
async/await 지옥에서 빠쪄나오는 방법
async/await 을 피하기 위해 다음 단계를 따라야합니다.
첫 번째 예에서는 피자와 음료를 선택했습니다. 우리는 피자를 선택하기 전에 피자 목록을 가지고 있어야한다고 결론을 내렸고 피자를 장바구니에 넣기 전에 피자를 선택해야합니다. 그래서 우리는이 세 단계가 서로 의존한다고 말할 수 있습니다. 우리는 이전 일을 마칠 때까지 한 가지를 할 수 없습니다.
그러나 좀 더 광범위하게 살펴보면 피자 선택은 음료 선택에 달려 있지 않기 때문에 병행으로 선택할 수 있음을 알게됩니다.
따라서 우리는 다른 명령문의 실행에 의존하는 명령문과 그렇지 않은 명령문을 알아야 됩니다.
비동기 함수의 그룹 종속 문
위에서와 같이 피자를 선택하는 것은 피자 목록을 얻고 그중 하나를 선택하고 난 이후 피자를 장바구니에 추가하는 것과 같은 종속적 문장을 포함합니다. 우리는 이러한 명령문을 비동기 함수로 그룹화해야합니다. 이렇게하면 두 개의 비동기 함수 인 selectPizza () 및 selectDrink ()가 발생합니다.
이러한 비동기 함수를 동시에 실행하세요
이후 비동기(비차단)함수를 동시에 실행하기 위해 이벤트 루프를 이용합니다.이는 Promise.all 함수를 통해 처리할 수 있습니다.
예제 수정하기
위 단계를 거쳐 예제에 적용 해 보겠습니다.
async function selectPizza() {
const pizzaData = await getPizzaData() // async call
const chosenPizza = choosePizza() // sync call
await addPizzaToCart(chosenPizza) // async call
}
async function selectDrink() {
const drinkData = await getDrinkData() // async call
const chosenDrink = chooseDrink() // sync call
await addDrinkToCart(chosenDrink) // async call
}
(async () => {
const pizzaPromise = selectPizza()
const drinkPromise = selectDrink()
await pizzaPromise
await drinkPromise
orderItems() // async call
})()
// Although I prefer it this way
(async () => {
Promise.all([selectPizza(), selectDrink()].then(orderItems) // async call
})()
이제 우리는 두 문장을 두 가지 기능으로 그룹화했습니다.
함수 내에서 각 구문은 이전 구문의 실행에 의존합니다. 그런 다음 selectPizza() 및 selectDrink() 함수를 동시에 실행합니다.
두 번째 예에서는 알 수없는 약속을 처리해야합니다.
이 상황을 다루는 것은 매우 쉽습니다. 배열을 만들고 약속을 푸시합니다. 그런 다음 Promise.all()을 사용하여 우리는 모든 약속이 동시에 해결 될 때까지 기다립니다.
async function orderItems() {
const items = await getCartItems() // async call
const noOfItems = items.length
const promises = []
for(var i = 0; i < noOfItems; i++) {
const orderPromise = sendRequest(items[i]) // async call
promises.push(orderPromise) // sync call
}
await Promise.all(promises) // async call
}
이 글을 통해 async / await의 기본을 이해하고, 이후 응용 프로그램의 성능을 향상시키는 데 도움이되기를 바랍니다.
좀 더 알기 쉽게 예를 들면...
1 피자 목록 획득.
2 음료 목록을 획득.
3 목록에서 피자 선택.
4 목록에서 음료 선택.
5 선택한 피자를 장바구니 담기.
6 선택한 음료를 장바구니 담기.
7 장바구니 항목 주문.
각 항목당 수행 시간이 1초식 걸린다면 ...
기존 비동기에서는 7초가 걸리지만...
그룹화된 비동기를 활용하면 (3,3,1) => 4초면 해결됨 !
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit