• 230216 TIL : 비동기 프로그래밍 (async & await)

    2023. 2. 16.

    by. 옛슬

    오늘은 Promise에 이어서 aync & await에 대해 학습해보려고 한다.


    Async Function

    - async function 선언은 AsyncFunction 객체를 반환하는 하나의 비동기 함수를 정의

    - 암시적으로 Promise를 사용하여 결과를 반환, 그러나 비동기 함수를 사용하는 코드의 구문, 구조는 표준 동기 함수와

      많이 비슷함.

     

    AsyncFunction

    - 자바스크립트에서 모든 비동기 함수는 사실상 AsyncFunction 객체이다.

    - AsynFunction 생성자는 새로운 async function 객체를 만든다.

     

    기본 문법

    // * getRandomFriendName 함수는 promise
    
    // 선언문
    async function getFriends () {
    	const name1 = await getRandomFriendName();
    	const name2 = await getRandomFriendName();
    	const name3 = await getRandomFriendName();
    	const name4 = await getRandomFriendName();
        
        return [name1, name2, name3, name4]
    }
    
    // 표현식
    const helloWorld = async function () {
    	// 상단과 동일함.
    }
    
    (async function() {
    	// IIFE(즉시실행함수)로도 실행할 수 있음.
    })

    - async 함수에는 await 식이 포함될 수 있으며, 이 식은 async 함수의 실행을 일시 중지하고 전달된 Promise의 해결을 기다린 다음 async 함수의 실행을 다시 시작하고 완료후 값을 반환.

    - async 함수는 항상 promise를 리턴한다. 만약에 함수의 반환값이 명시적으로 promise가 아니라면 암묵적으로 promise로 감싸진다.

    function getMyFriendName () {
    	return '영희'; 
        // 이 부분이 암묵적으로 return Promise.resolve('영희')로 변환됨
    }

    - async 함수의 본문은 0개 이상의 await문으로 분할됨.

    - 첫번째 await문을 포함하는 최상위 코드는 동기적으로 실행되고, await문이 없는 async함수는 동기적으로 실행됨.

    - 단, await문이 있다면 async함수는 항상 비동기적으로 완료됨.

     

    MDN 예시 뜯어보기

        // ⏹ Promise 함수 소개
        // slowPromise() : 2초 후 실행
        // fastPromise() : 1초후 실행
        
        // 1️⃣ 잇달아 일어남
        // 결과 값 : 2초 후 slowPromise → 1초 후 fastPromise
        var sequentialStart = async function () {
          console.log('==SEQUENTIAL START==');
          const slow = await slowPromise();
          const fast = await fastPromise();
        }
    
        // 2️⃣ 동시에 일어남
        // 결과 값 : 2초 후 slowPromise, 그 뒤에 이어서 fastPromise가 바로 리턴됨.
        var concurrentStart = async function () {
          console.log('==CONCURRENT START with await==');
          const slow = slowPromise(); // 처음에 await을 안붙여주기 때문에 바로 시작됨.
          const fast = fastPromise();
    
          console.log(await slow);
          console.log(await fast); // 먼저 결과 값을 받았지만, await문 때문에 기다린 후 slow가 반환되면 바로 리턴.
        }
    
        var stillConcurrent = function () {
          console.log('==CONCURRENT START with Promise.all==');
          Promise.all([slowPromise(), fastPromise()]).then((messages) => {
            console.log(messages[0]); // slow
            console.log(messages[1]); // fast
          });
        }
    
        // 3️⃣ 병렬적으로 진행됨.
        // 결과 값 : 1초 후 fast 리턴, 2초 후 slow 리턴
        var parallel = function () {
          console.log('==PARALLEL with Promise.then==');
          slowPromise().then((message) => console.log(message));
          fastPromise().then((message) => console.log(message));
        }

     

    await

    - Promise를 기다리기 위해 사용

    - async function 내부에서만 사용

     

    - 결론 : 그래서 await이 필요하다.

    - await은 위 MDN 예시 뜯어보기를 보면 알겠지만 정말 다양한 방식으로 비동기 코드를 처리할 수 있고,  then()으로 계속 체이닝을 하는 것이 아닌 마치 일반 함수를 호출하는 듯한 작성 방식으로 훨씬 가독성이 높아졌다.

     

        
        function getRandomNumber(time) {
          return new Promise((resolve, reject) => {
            const randomNum = Math.floor(Math.random() * 100);
    
            setTimeout(function () {
              resolve(randomNum);
            }, time)
          })
        }
    
        // Async function
        async function getRandNumsWithAsync() {
          const num1 = await getRandomNumber(100);
          const num2 = await getRandomNumber(200);
          const num3 = await getRandomNumber(300);
          const num4 = await getRandomNumber(400);
          const num5 = await getRandomNumber(500);
    
          return `${num1}/${num2}/${num3}/${num4}/${num5}`
        }
    
        // promise
        function getRandNumWithPromiseTwo() {
          return getRandomNumber(100).then(num1 => {
              return getRandomNumber(200).then(num2 => {
                return getRandomNumber(300).then(num3 => {
                  return getRandomNumber(400).then(num4 => {
                    return getRandomNumber(500).then(num5 => {
                      return `${num1}/${num2}/${num3}/${num4}/${num5}`
                    })
                  })
                })
              })
            })
        }
    
    	// promise2
        function getRandNumWithPromiseTwo() {
          return getRandomNumber(100).then(num1 => 
          getRandomNumber(200).then(num2 => getRandomNumber(300).then(num3 => getRandomNumber(400).then(num4 => getRandomNumber(500).then(num5 => `${num1}/${num2}/${num3}/${num4}/${num5}`)))))
        }

    - 또 다른 콜백 지옥을 만날 수 있음. 혹시 몰라서 return문을 빼볼까싶어서 탄생한게 promise2 ㅎㅎ...

    - async는 진짜 함수에서 값을 받아온 다음에 그냥 쓰는 느낌이라 가독성이 확 높아졌다. 하지만 promise가 더 유용한 경우가 있다고 하는데 이에 대해서는 한번 검색이 필요할거 같다 


    😂 예-스 드디어 비동기 프로그래밍 기초에 대해서 공부하게 되었다.

    해당 개념이 어려울거 같다고 항상 미뤘는데 리덕스 thunk 공부하면서 공부를 안할 수가 없었던 부분 !

    생각보다 개념이 난해하지는 않았던거 같다. 다만 어떻게 써야 더 효율적인지 그런 실무적인 부분은 다른 사람의 코드를 좀 봐봐야할듯?

    아마 각각의 데이터의 관계에 따라 어떤게 더 효율적인지 확인 후 사용하는 거 같다, 왜냐면 Promise에도 다양한 메서드 (all, race, any 등)이 있기 때문에 경우에 따라서는 이게 더 유용할 거 같기 때문이다.

     

    참고자료

    https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/async_function

    https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/await

    https://www.youtube.com/watch?v=aoQSOZfz3vQ 

     

    댓글