본문 바로가기
Coding/JAVA_SCRIPT

[JS] 동기/비동기. async function ~ await 함수를 사용하는 이유에 대한 깊은 생각과 결론

by 우지uz 2023. 9. 20.

https://www.notion.so/d64a4eeb40b14ba69e8d12313ca2ffe5?pvs=4 

 

비동기 처리와 콜백 함수

위 joshua1988님이 작성하신 gitHub 블로그의 내용을 그대로 직접 따라치며, 필기한 내용입니다.

www.notion.so

https://www.notion.so/JS-Promise-abb52b3c0437467d99011bbcc7986649?pvs=4 

 

JS Promise 이해하기

위 joshua1988님이 작성하신 gitHub 블로그의 내용을 그대로 직접 따라치며, 필기한 내용입니다.

www.notion.so

https://www.notion.so/JS-async-await-1efb1935768145cd9bd5e546a08bebb7?pvs=4 

 

JS async 와 await 문법

위 joshua1988님이 작성하신 gitHub 블로그의 내용을 그대로 직접 따라치며, 필기한 내용입니다.

www.notion.so

 

1. 동기, 비동기에 대한 개념

2. 그리고 콜백 함수와 콜백 지옥

3. JS fetch 및 Promise 객체 

4. async function ~ await 함수

에 대해서 모두 배워봤는데

의문이 드는 점은,
fetch 를 이용해서 객체를 가져오고, 다음 함수를 Callback 하거나 Promise 를 이용해도 되는데 

왜 async function ~ await 를 쓰는 것이 왜 더 좋은가 ?? 였다. 

내가 볼땐 두 기능 모두 잘 작동하고, 크게 달라보이지 않아서 였다.

 

 

실제로 제가 사이드 프로젝트를 하면서 작성한
두 코드의 예시로 설명드리도록 하겠습니다.

첫번째
// index.js
console.log("index.js 가 잘 로딩 되었습니다.")


fetch("./navbar.html").then(response => {
    return response.text()
})
    .then(data => {
        document.querySelector("header").innerHTML = data;
		// 1. header 라는 속성에 innerHTML 에 먼저 navbar.html 코드(데이터)를 담아주고 
        buttonBlockAndHide();
		// 2. 아래의 buttonBlockAndHide 함수를 순차적으로 실행한다. 
    })


const buttonBlockAndHide = () => {
    // 페이로드를 로컬스토리지에 저장하고, 페이로드에 있는 사용자 정보를 가져옴

    const payload = localStorage.getItem("payload");
    const payload_parse = JSON.parse(payload);
    const intro = document.getElementById("intro")
    if (payload) {
        intro.innerText = `${payload_parse.username}님 안녕하세요!`
        // 1. 로그인 성공 시, 로그인 버튼을 숨기고
        // 2. 로그아웃 버튼을 생성한다.
        // 3.

        console.log("로그인 버튼 Hide")
        let loginButton = document.getElementById("login-button")
        loginButton.style.display = "none";
        // 로그아웃 버튼을 ul 안에 li 로 생성
        let navberULRight = document.getElementById("navbar-right")
        let newLi = document.createElement("li")
        newLi.setAttribute("class", 'nav-item')
        let logOutBtn = document.createElement("button")
        logOutBtn.setAttribute("class", 'navbar-link btn')
        logOutBtn.setAttribute("id", "logout-button")
        logOutBtn.innerText = "로그아웃"
        logOutBtn.setAttribute("onclick", "handleLogout()")

        newLi.appendChild(logOutBtn)
        navberULRight.appendChild(newLi)

        // let logoutButton = document.getElementById("")
    } else {
        console.log("로그인 버튼 Block")

    }
}

fetch 로 navbar.html 을 넣어주는 것과 로그인 버튼을 숨기는 함수를 
굳이 따로따로 작성해서 콜백함수로 들고온 것을 볼 수 있다. 

 

두번째
async function injectNavbar() {
    let navbarHtml = await fetch("./navbar.html")
    let data = await navbarHtml.text()
    document.querySelector("header").innerHTML = data

    const payload = localStorage.getItem("payload");
    if (payload) {
        const payload_parse = JSON.parse(payload);
        const intro = document.getElementById("intro")
        intro.innerText = `${payload_parse.username}님 안녕하세요!`
        // 1. 로그인 성공 시, 로그인 버튼을 숨기고 로그아웃 버튼을 생성한다.
        // 2. 로그인 X, 로그인 버튼을 유지하고 굳이 로그아웃 버튼이 생성되지 않는다

        console.log("로그인 버튼 Hide")
        let loginButton = document.getElementById("login-button")
        loginButton.style.display = "none";
        // 로그아웃 버튼을 ul 안에 li 로 생성
        let navberULRight = document.getElementById("navbar-right")
        let newLi = document.createElement("li")
        newLi.setAttribute("class", 'nav-item')
        let logOutBtn = document.createElement("button")
        logOutBtn.setAttribute("class", 'navbar-link btn')
        logOutBtn.setAttribute("id", "logout-button")
        logOutBtn.innerText = "로그아웃"
        logOutBtn.setAttribute("onclick", "handleLogout()")

        newLi.appendChild(logOutBtn)
        navberULRight.appendChild(newLi)

        // let logoutButton = document.getElementById("")
    } else {
        console.log("로그인 버튼 Block")

    }
}

injectNavbar();

fetch 로 navbar 를 가져오는 등의 코드가 3줄로 요약되었고

async function ~ await 함수로 인해, injectNavbar 라는 이름을 가진 함수명은

한눈에 알아보기 쉬운 함수명을 가졌으며

1. 함수명을 가졌다는 것 자체
에 대한 의미가 있다고 생각을 했다. 

변수명, 함수명, 클래스명 -- 정의를 하는 것 자체가 주는 "의미"가 있는 것이다.

관리하는 측면에서 (유지보수)

코드를 읽어내야하는 피로도면에서

2. 동기적이냐 비동기적이냐에 대한 고민을 줄여준다. 

콜백함수를 쓴다는 것 자체가, 지금 

동기적이지 않아서 생기는 "문제"가 발생했다는 것이다.. (필자도 에러가 발생..)

내가 겪은 문제는, navbar.html 이 순서대로 읽혀지지 않고 비동기적으로 불러와져서

id 값이 null 로 불러와졌다.

3. api.js 및 index.js  loader.js 등등 동시에 많은 JS 함수들이 
하나의 html 에 불러와지기 때문에 

1번 코드와 같이, 굉장히 많은 함수들에 대해서 

콜백함수로 한땀 한땀 순서를 정하는 것은 

굉장히 피곤한 일이 된다. 

 

4. Error 처리 및 로직 구현의 용이성

async function logTodoTitle() {
  try {
    var user = await fetchUser();
    if (user.id === 1) {
      var todo = await fetchTodo();
      console.log(todo.title);// delectus aut autem}
  } catch (error) {
    console.log(error);
  }
}

다음과 같이 try catch 문법으로 예외 처리가 가능하다. 

const condition = true;
const promise = new Promise((resolve, reject) => {
  if (condition) {
    resolve('resolved');
  } else {
    reject('rejected');
  }
});

promise
  .then((res) => {
    console.log(res);
  })
  .catch((error) => {
    console.error(error);
  });

callback 이나 Promise 를 이용하면 then catch 문법으로 체이닝 및 로직 구현이 가능하지만

동기 / 비동기 로직에 대한 순서에 대한 고민도 많이 해야하고

유지 보수가 어려울 수도 있다는 생각을 했다. 

 

promise 는 에러 핸들링이 다소 편해보이지만, 
async await 도 try catch 를 통해 에러처리가 가능해서 
크게 차이점이라곤 생각이 들지 않았다. 

 

 " 도대체 왜일까 ???  "

async function ~ await 를 쓰는 이유가 무엇인지 
편의성을 위해 Callback, Promise 이후에 생겨난 이유가 무엇인지

배운지 약 1주일이 지나고난 후에 내린 결론은 이거지만

추후에 동기/비동기에 대한 깨달음이 주어진다면, |
블로그에 더 기록하겠읍니다....!
감사합니다