Asynchronous Javascript

정마플로·2020년 12월 15일
0

why Async

서버와 클라이언트의 개념부터 짚고 넘어가자!

동기식 처리 모델(Synchronous processing mdoel)은 직렬적으로 task를 수행. 서버에 데이터를 요청하고 데이터가 응답할 때까지 이후 태스크들은블로킹 되는 경우, 비동기적 처리 방식!

반면 비동기식 처리 모델(Aynchronous processing mdoel) 병렬적으로 task를 수행. task가 종료되지 않은 상태여도 다음 task를 실행한다. 참고로, 자바스크립트 대부분의 DOM이벤트와 Timer 함수(setTimeout, setInterval), Ajax 요청은 비동기식 처리 모델로 동작한다.

만약 서버로부터 데이터를 받아와서 해당 데이터를 처리하는데, 이를 동기적으로 처리한다면?
서버로부터 데이터를 받아오는 코드의 실행이 완전히 끝난 뒤에 이후의 코드가 처리될 것이고, 유저들은 데이터 수신이 완료될 때가지 하염없이 기다려야할 것.

Callback

특정 함수에 매개변수로 전달된 함수를 의미하며, 콜백함수는 함수를 전달받은 함수 안에서 호출. 자바스크립트의 비동기성을 표현하는 가장 일반적인 기법!

위 두 가지 사례를 비교해보면, 콜백함수가 왜 필요한지 알 수 있다.
그렇지만 뭔가 한 눈에 잘 안들어온다. 해당 구조를 가장 단순화시킨 아래 두 코드를 한번 살펴보자.

function test(e) {
  e() 
}; 

// (2) 아래에서 전달된 함수가 test함수 매개변수 e에 저장되고, 
// (3) e() 호출. 그 결과로 console.log 안에 '콜벡'이 출력 됨!

test(function() {
  console.log('콜백')
}); 

// (1) test라는 함수는 인수로 함수로 받음.

잘 정리된 글을 다시 한번 읽어보며 복습하기

잘 정리된 글2 - 자바스크립트 비동기 처리와 콜백함수

Promise

프로미스는 JS 비동기 처리에 사용되는 객체. 주로 서버에서 받아온 데이터를 화면에 표시할 때 사용한다. 위 방식(콜백함수 사용)은 자칫 콜백지옥을 야기할 수 있는데, 이런 문제를 방지하기 위해 나온 것이 promise.
(잘 정리된 글2에 나와있는 것처럼) 중첩 선언했던 콜백 익명 함수를 각각의 함수로 구분하는 방식, 즉 코딩 패턴의 변화만으로도 이런 (콜백) 지옥에서 탈출할 수는 있지만 Promise를 이용하면 더 수월한 탈출(?)이 가능하다.

function getData(callbackFunc) {
  $.get('url 주소/products/1', function(response) {
    callbackFunc(response); // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨줌
  });
}

getData(function(tableData) {
  console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
});

위 코드는 제이쿼리의 ajax 통신 API를 이용해 지정된 URL에서 1번 사품 데이터를 받아오는 코드. 콜백 함수를 사용한 예다. 해당 코드에 프로미스를 적용하면 아래와 같은 코드가 된다.

`new Proimse()` `resolve()` `then()`과 같은 프로미스 API를 사용한 구조

function getData(callback) {
  // new Promise() 추가
  return new Promise(function(resolve, reject) {
    $.get('url 주소/products/1', function(response) {
      // 데이터를 받으면 resolve() 호출
      resolve(response);
    });
  });
}

// getData()의 실행이 끝나면 호출되는 then()
getData().then(function(tableData) {
  // resolve()의 결과 값이 여기로 전달됨
  console.log(tableData); // $.get()의 reponse 값이 tableData에 전달됨
});

프로미스의 3가지 상태(status)

  • Pending(대기): 비동기 처리 로직이 아직 완료되지 않은 상태
  • Fulfilled(이행): 비동기 처리가 완료되어 프로미스가 결과 값을 반화해준 상태
  • Rejected(실패): 비동기 처리가 실패하거나 오류가 발생한 상태

Pending

아래와 같이 new Promise() 메서드를 호출하면 Pending 상태가 된다.

new Promise();

new Promise() 메서드를 호출할 때 콜백 함수를 선언할 수 있고, 콜백 함수의 인자는 resolve, reject!

new Promise(function(resovle, reject) {
  // ...
});

Fulfilled

여기서 콜백 함수의 인자 resolve를 아래와 같이 실행하면 Fulfilled상태가 된다.

new Promise(function(resolve, reject) {
  resovle();
});

그리고 이행 상태가 되면 아래와 같이 then()을 이용하여 처리 결과 값을 받을 수 있다.

function getData() {
  return new Promise(function(resolve, reject) {
    var data = 100;
    resolve(data);
  });
}

// resolve()의 결과 값 data를 resolvedData로 받음
getData().then(function(resolvedData) {
  console.log(resolvedData); // 100
});

그리고 실패 상태가 되면 실패한 이유(실패 처리의 결과 값)을 catch()로 받을 수 있다.

Rejected

new Promise()로 프로미스 객체를 생성하면 콜백 함수 인자로 resolve, reject를 사용할 수 있고, 여기서 reject를 아래와 같이 호출하면 실패 상태(Rejected)가 된다.

new Promise(function(resolve, reject) {
  reject();
});

그리고 실패 상태가 되면 실패한 이유(실패 처리의 결과 값)를 catch()로 받을 수 있다.

function getData() {
  return new Promise(function(resolve, reject) {
    reject(new Error("Request is failed"));
  });
}

// reject()의 결과 값 Error를 err에 받음
getData().then().catch(function(err) {
  console.log(err); // Error: Request is failed
});

async await

여전히 콜백은 어렵다.
그래서 등장한 개념이 async await이 아닐까 생각해본다. (뇌피셜)
기본 공식은 아래와 같다

async function 함수명() {
  await 비동기_처리_메서드_명();
}

보다시피 함수의 앞에 async라는 예약어를 붙인다. 그러고 나서 함수의 내부 로직 중 HTTP 통신을 하는 비동기 처리 코드 앞에 await을 붙인다. 단, 여기서 비동기 처리 메서드가 꼭 Promise 객체를 반환해야 await이 의대한대로 동작한다.

자세한 예제 및 부연 설명은 아래 링크를 참고하자.

잘 정리된 글3

profile
스스로 브랜드가 되는 그 날까지

0개의 댓글