티스토리 뷰

[JS 기본 지식]

자바스크립트는 함수를 변수처럼 이용할 수 있다. 함수 선언문에도 해당함 

b는 a의 콜백함수가 되겠네요. 

콜백함수(callback)를 대충 지금 당장에 호출되는 것이 아니라 나중에 호출될 인자로 전달된 함수..정도로 이해하면 될 거 같습니다.

 

function b() {

console.log("b called");

}

function a(another){

console.log("a started");

another(); // "b called"

console.log("a ended");

}

 

자바스크립트에서 비동기 처리를 다룰 수 있는 방법은 여러가지가 있습니다.

주로 callback, Promise, async/await 를 활용합니다. 

 

👾 Promise 

Promise는 비동기 작업을 처리하는 함수(or 비동기 작업의 최종 완료 또는 실패를 나타내는 객체)입니다. 내용은 실행 되었지만 결과를 아직 반환하지 않은 객체라고 이해하면 좋습니다. 

Promise에는 

  • Pending (대기)
  • Fulfilled (이행)
  • Rejected (실패) 

의 3가지 상태가 있습니다. 

비동기 처리가 완료되지 않았다면 Pending, 완료되었다면 Fulfilled, 실패하거나 오류가 발생했다면 Rejected 의 상태를 갖습니다. 

 

 

Promise는 executor라는 callback함수를 인자로 받게 되는데 이 함수는 비동기 작업이 성공했을 때 resolve함수를 호출하고 실패했을 때는 reject 함수를 호출합니다 만일 호출 작업을 처리해주지 않는다면 pending 상태가 유지됩니다. Promise가 끝나고 난 다음의 동작을 우리가 설정해줄 수 있는데 여기서 then 메소드와 catch메소드를 사용합니다. 

resolve한 반환 값에 대해서는 then() 을 통해 결과 값을 반환받을 수 있고 reject 의 반환 값에 대해서는 catch()를 통해 반환 받습니다. (then과 catch는 인자로 함수를 받습니다.)
then() 과 catch() 문의 체이닝을 통해 비동기 로직의 성공 여부에 따른 분기 처리가 가능합니다. 

e.g.) promise1.then(()=> {console.log("then resolved");}).catch(()=>{ throw new Error("rejecteed error");});

Promise의 장점 

Chaining

보통 두 개 이상의 비동기 작업을 순차적으로 실행해야 하는 상황을 흔히 보게 됩니다. 순차적으로 각각의 작업이 이전 단계 비동기 작업이 성공하고 나서 그 결과값을 이용하여 다음 비동기 작업을 실행해야 하는 경우를 의미합니다. 우리는 이런 상황에서 promise chain을 이용하여 해결하기도 합니다.

then()함수는 새로운 promise를 반환합니다. 처음에 만들었던 promise와는 다른 새로운 promise입니다.

Promise 사용 예시

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);
  });

condition의 값에 따라 promise의 반환 값이 결정되고 있다. 

값이 참이면 resolve 를 호출하고, 아닐 시에는 reject를 호출합니다. 

 

👾 async / await 

가장 최근에 나온 비동기 처리 문법으로 기존의 callback이나 Promise의 단점을 해소하고자 만들어졌습니다. 

callback 이나 Promise의 경우에 단점은 꼬리에 꼬리를 무는 코드가 나올 수 있다는 점입니다(a.k.a콜백지옥, then() 지옥 ). 

 

 

await 를 통해 Promise 반환 값을 받아올 수 있습니다. (async 함수의 리턴 값은 무조건 Promise 이다.)

const variable =  await promise;
// promise의 반환 값을 받아 variable 에 할당

하지만 async / await 를 사용하기 위해서는 선행되어야 하는 조건이 있는데, 바로 await 은 async 함수 안에서만 동작한다는 것입니다. 

 

async / await 사용 예시

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

  try {
    const result = await promise;
    console.log(result);
  } catch (err) {
    console.error(err);
  }
})();

위 예시는 Promise 예시를 async / await 를 사용하여 변경한 코드입니다. 

익명 함수 패턴을 활용하여 async 함수 내의 await를 통해 Promise의 반환 값을 result 변수에 담아 콘솔에 출력합니다. 

 

주의할 점은 async/ await은 Promise와는 다르게 에러 핸들링을 할 수 있는 기능이 없습니다. 따라서 try-catch()문을 활용하여 에러를 핸들링해주어야 합니다. 

 

 

👾 Promise 와 async/ await 차이점

에러 핸들링 

  • Promise 를 활용할 시에는 .catch() 문을 통해 에러 핸들링이 가능하지만, async/ await 은 에러 핸들링 할 수 있는 기능이 없어 try-catch() 문을 활용해야 합니다. 

코드 가독성

  • Promise의 .then() 지옥의 가능성 
  • 코드가 길어지면 길어질수록, async/await 를 활용한 코드가 가독성이 좋습니다. 
  • async / await은 비동기 코드가 동기 코드처럼 읽히게 해줍니다. 또한 코드 흐름을 이해하기 쉽습니다. 

Promise란 무엇인가요? 
프로미스는 비동기 작업을 처리하는 함수 혹은 비동기 작업의 상태를 나타내는 객체를 말합니다. 
프로미스에는 pending, fulfilled, rejected 의 3가지 상태가 있습니다. 여기서 상태란 비동기 처리 상태를 뜻합니다. 
상태값에 따라 후속 작업을 해줄 수 있는데 then과 catch 문의 프로미스 체이닝을 통해 비동기 로직의 성공 여부에 따른 처리가 가능합니다. 

 

async / await 이란 무엇인가요?
async / await 은 가장 최근에 나온 비동기 처리 문법으로 기존의 callback이나 promise의 단점인 꼬리를 무는 코드를 개선한 것입니다.  await은 async 함수 안에서만 동작하기 때문에 await을 쓰려면 async와 함께 써야합니다. 

Promise와 async / await의 차이점?


둘의 차이점은 에러핸들링 코드 가독성에 있습니다. 
promise는 catch문을 통해 에러 핸들링이 가능하지만 async / await은 에러 핸들링 기능이 없어 try- catch문을 사용해야 합니다. 
코드가 길어지면 promise가 then지옥의 가능성이 있어 코드 가독성이 떨어지는데 비해 async / await은 비동기 코드가 동기 코드처럼 읽히게 해주기 때문에 코드 가독성이 더 좋습니다. 

 

Q. 비동기 처리는 무조건 async/await 으로 처리해야 좋을까요? (async await 남발)

async/await은 기존 비동기처리가 주는 불편함을 해소하기 위해 등장한 만큼, 어디선가 최소 한 번은 async/await을 사용하는 것이 좋습니다. 하지만 중간 과정에있는 함수 전부에서 사용하는 것은 아닙니다. 

 

async await을 남발한다하여 성능상에 문제가 있는 것은 아니지만 코드 가독성이나 의미 판단에 있어서 오해를 불러일으킬 수 있기 때문에 남발하지 의미입니다.  -> async await으로 작성한 함수가 곧 다른 팀원이 보기에는 반드시 해당 코드가 동기적으로 동작을 마친 뒤에 다음 코드로 진행해야한다는 의미로 받아들여지기 때문입니다. 

함수를 async로 만든다는 것은 곧 원래의 함수를 Promise로 감싸는 것임을 염두해야 합니다.

 

async await이 필요 없는 함수를 중간함수라고 했습니다.

여기서 중간함수란 Promise를 그대로 리턴하는 함수를 말합니다. (이미 Promise를 리턴하는데 굳이 async를 붙여 또 Promise로 감쌀 필요가 없죠)

중간함수를 예시로 들면, 아래의 getProduct를 들 수 있습니다. 

const fetchJson = url => fetch(url).then(res => res.json());
const fetchProduct = id => fetchJson("url주소/${id}");

//여기서는 getProduct()가 중간함수입니다. 
function getProduct(id){
    const json = fetchProduct(id);
    return json;
}

async function handleChange(e){
    const id =e.target.value'
    const product = await getProduct(id);
    renderProduct(product);
}

참고 리소스: https://www.youtube.com/watch?app=desktop&v=Z1zHOh45NDU (FE재남님 유튜브)

 

 

댓글