[javascript] 비동기(async)

jinwonShen·2025년 1월 25일

javascript

목록 보기
46/52
post-thumbnail

비동기(async)

자바스크립트는 Non-blocking + Async 방식을 사용한다.

동기(sync)와 비동기(async)

sync

  • 어떤 식이든 B함수 작업이 끝난 것을 확인 후, 작업 마무리를 A함수에서 하는 것
  • B함수 쪽의 처리결과를 A쪽에서 계속 신경쓰는 형태\

async

  • A는 B함수 호출 까지만을 담당했을 뿐 처리 + 마무리는 B함수에서 하는 것
  • B함수 쪽으로 아예 작업을 위임 해버리는 것.

sync/async : 특정 작업을 위한 제어흐름의 최종 마무리를 어디서 하는지에 대한 속성


블로킹(blocking)과 논-블로킹(Non-blocking)

A 함수에서 어떤 작업 처리를 위해 B 함수를 호출했다고 가정한다.

Blocking : B함수에서 할 일을 다 마칠때까지 A함수 제어흐름은 대기

Non-Blocking : B함수에서 할일의 완료 여부와 상관없이 곧바로 A함수쪽의 제어흐름은 이어짐

blocking/non-blocking : 제어권이 넘어갔을 때 곧바로 반환 여부에 대한 속성


콜백함수(callback function)

  • 어떤 함수를 호출할때, 인자값으로 넘기는 나중에 실행될 함수
  • 콜백함수가 실행되는 시점은 콜백함수를 인자값으로 넘겨받은 함수 구현에 따라 결정된다.

콜백함수의 용도

  • javascript의 비동기 작업을 처리하기 위한 방법
  • 주로 어떤 작업이 끝난 이후, 그 결과 값을 가지고 뒤에 이어서 처리되어야하는 로직을 담는다. (ex)성공 또는 실패 핸들러

콜백 지옥

  • 콜백함수를 겹겹이 연달아서 구현하는 형태
  • 코드 가독성이 떨어지고 이해하기도 어려워짐

Ajax

  • Asynchronous Javascript And XML (비동기 자바스크립트와 XML)을 줄임말
  • Web API의 XML HttpRequest(=XHR)라는 Object를 이용하여, 비동기적으로 서버에 요청을 날려 응답을 받아와서, 그 응답정보를 HTML DOM에 표현하는 프로그래밍 기법
  • Client 입장에서 화면 전체를 reload할 필요가 없어져 매끄러운 서비스 이용이 가능해짐
  • 페이지 내 필요한 만큼만 데이터를 가져와 동적으로 보여주면 되기때문에 훨씬 경제적이다.

XML(=Extensible Markup Language)

  • html과 비슷한 형식으로 정보를 표현하기 위해 태그를 사용하는 마크업 언어
  • 과거에 한창 데이터 송수신 포맷으로 활발하게 사용되던 시기가 있었으나, 이제는 JSON이 대체함

XMLHttpRequest

  • 페이지 전체 refresh없이 비동기적으로 http요청을 날릴 수 있는 브라우저 제공 기능.

코드예제

callback 코드예제

// 합이 10 미만 여부에 따라 성공/실패 응답을 하는 콜백함수를 입력받는 함수
function myFunc(p1, p2, successCallback, failCallback) {
  try {
    console.log("p1 + p2:", p1, p2);
    result = p1 + p2;

    if (result < 10) {
      successCallback(result);
    } else {
      noWhereFunc(); // 에러 테스트
    }
  } catch (error) {
    failCallback(error);
  }
}

// 함수사용
const successFunc = function (result) {
  console.log("The result is " + result);
};

const failCallback = function (error) {
  console.log("Failed reason: " + error);
};

// success
myFunc(3, 4, successFunc, failCallback);

// failed
myFunc(9, 10, successFunc, failCallback);

ajax 코드예제


콜백지옥 코드예제

// 선언--
function loginUser(id, pw, onSuccess, onError) {
  console.log("Match ID & PWD...");
  if (pw === "correct") {
    onSuccess(id);
  } else {
    onError("Authentication Failed...");
  }
}

function getPermissions(userID, onSuccess, onError) {
  console.log("Access DB and load user permissions...");
  if (userID < 1000) {
    let permissions = ["perm1", "perm2", "perm3"];
    onSuccess(permissions);
  } else {
    onError("Load Permission Failed...");
  }
}

// 활용 --
loginUser(
  123,
  "sdad123",
  (userID) => {
    getPermissions(
      userID,
      (permissions) => {
        console.log("User permissions are :" + permissions);

        // ... 대각선으로 계속 깊어져 가독성이 떨어짐
      },
      (errMsg) => {
        console.log("Get user permissions failed :" + errMsg);
      }
    );
  },
  (errMsg) => {
    console.log("Login user failed: " + errMsg);
  }
);

Promise

  • js비동기 작업의 최종적인 성공이나 실패의 제어흐름을 알아보기 쉽게 표현해주는 객체
  • 비동기 로직 구현 시, 콜백함수를 활용하는 방식보다 더 편리해짐
  • ECMA Script 2015(=ES6)에 도입
  • 3가지 상태가 있음 : pending = 대기, fulfill = 완료-성공, reject = 완료-실패

간단한 예시

promise 기본예제

let myPromise = new Promise(function (resolve, reject) {
  // 성공 시 resolve()를 호출해 결과값 전달
  // 실패 시 reject()를 호출해 에러를 전달
});

myPromise
  .then(function (result) {
    // 결과값 활용해 성공처리
  })
  .catch(function (err) {
    // 에러객체 활용해 실패처리
  })
  .finally(function () {
    // 공통 마무리 작업
  });

resolve test

let p3 = new Promise(function (resolve, reject) {
  resolve("resolve called");
});

p3.then((data) => {
  console.log("p3 - then:", data);
})
  .catch((error) => {
    console.log("p3 - catch: ", error);
  })
  .finally(() => {
    console.log("p3 - finally");
  });

// p3 - then: resolve called
// p3 - finally

reject test

let p3 = new Promise(function (resolve, reject) {
  reject("rejected called");
});

p3.then((data) => {
  console.log("p3 - then:", data);
})
  .catch((error) => {
    console.log("p3 - catch: ", error);
  })
  .finally(() => {
    console.log("p3 - finally");
  });

// p3 - catch: rejected called
// p3 - finally

Promise 코드예제

function asyncFunc(isSuccess) {
  setTimeout(() => {
    if (isSuccess) {
      return { id: 13, name: "Silva" };
    } else {
      throw new Error("Failed !!");
    }
  }, 3000);
}

let result = asyncFunc(true);
console.log(result); // undefined

// 셋타임아웃의 맵 api에 3초뒤 실행되도록 스케쥴링 되었고,
// 논블로킹인 자바스크립트에서는 바로 코드가 실행되기 때문에
// result 안에 값이 할당되기 전에 실행되어 undefined를 반환하게 된다?

// Promise 사용해 개선
function asyncFuncProm(isSuccess) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (isSuccess) {
        resolve({ id: 13, name: "silva" });
      } else {
        reject(new Error("Failed!!"));
      }
    }, 3000);
  });
}

asyncFuncProm(true)
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.error(error);
  });

promise chaining

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1);
  }, 1000);
}).then((result) => {
  console.log("#1 resolve:", result);

  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(result * 10);
    }, 1000);
  }).then((result) => {
    console.log("#2 resolve:", result);

    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(result * 10);
      }, 1000);
    }).then((result) => {
      console.log("#3 resolve:", result);
    });
  });
});
// 1초 후
// #1 resolve: 1
// 1초 후
// #2 resolve: 10
// 1초 후
// #3 resolve: 100

Async & Await

  • js의 비동기 로직 처리 패턴 중 가장 인간이 알아보기 쉬운 형태
  • 일반적으로 코드를 위에서 아래로 읽으며 실행 순서를 파악하는 점을 감안하여 만든 기능
  • ECMA Script 2017에 도입

Callback -> Promise -> async / await 로 발전


async

  • 비동기 로직을 포함하는 함수앞에 붙인다.
  • 함수가 Promise 객체를 리턴하게 만든다.
  • 함수 내부에서 await 키워드 사용이 가능하게 된다.

await

  • async 키워드를 붙인 함수에서만 사용가능
  • Promise 객체를 리턴하는 함수 호출 코드 앞쪽에만 붙일 수 있다.
  • Promise의 then() 부분에서 전달받던 성공 시 결과값을 곧바로 얻을 수 있다.

간단한 예시

async / await 사용예제

function resolveAfter2Seconds(x) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function f1() {
  var x = await resolveAfter2Seconds(10);
  console.log(x); // 2초 뒤 10
}

f1();

async / await 간단한 용법

function fetchUser(isSuccess) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (isSuccess) {
        resolve({
          id: 1,
          name: "홍길동",
          gender: "male",
          email: "bosv031999@gmail.com",
        });
      } else {
        reject(new Error("유저정보 불러오기 싫패"));
      }
    }, 1000);
  });
}

function fetchTodo(isSuccess) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (isSuccess) {
        resolve({
          userId: 1,
          id: 1,
          title: "우유 2개 사기",
          completed: false,
        });
      } else {
        reject(new Error("Todo정보 불러오기 실패"));
      }
    }, 1000);
  });
}

async function getUserTodoData() {
  try {
    let user = await fetchUser(true);
    // let user = await fetchUser(false);
    console.log("유저정보: ", user);
    let todo;
    if (user.id === 1) {
      // todo = await fetchTodo(true);
      todo = await fetchTodo(false);
      console.log("Todo 정보: ", todo); // 에러 반환
    }

    return {
      userInfo: user,
      todoInfo: todo,
    };
  } catch (error) {
    console.log("에러가 발생했습니다.", error);
  }
}

getUserTodoData().then((logData) => {
  console.log(logData);
});
profile
하면 된다. | 좋은 FE 개발자 되기

0개의 댓글