[React] 비동기 작업

🌊·2021년 12월 21일
0

React

목록 보기
14/20

비동기 작업 이해

기본적으로 웹 애플리케이션에서 서버 쪽 데이터가 필요할 때는 Ajax 기법을 사용하여 서버의 API를 호출함으로써 데이터를 수신한다.
서버의 API를 이용할 때는 네트워크 응답 시간이 필요하다. 이 과정에서 비동기적으로 처리하게 된다.

비동기

만약 작업을 동기적으로 처리한다면 해당 요청이 끝날 때까지 다른 요청을 수행할 수 없다.
비동기적으로 진행한다면 동시에 여러 요청을 수행할 수 있고, 기다리는 과정에서 다른 함수를 호출할수도 있다.
일반적으로 자바스크립트의 비동기 처리 코드는 콜백을 사용해야 코드의 실행순서를 보장받을 수 있다.

setTimeout 함수의 경우에는 특정 작업을 예약할 수 있다.
setTimeout 함수가 호출되면 코드가 멈추는 것이 아니라 그 다음 코드가 호출되고 지정한 시간이 지난 후에 setTimeout에 작성된 함수가 실행된다.
이렇게 지정한 시간 뒤에 실행될 (작성된) 함수가 콜백함수이다.

Promise

비동기 처리에 사용되는 객체
비동기 처리: 특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 특성
주로 서버에서 받아온 데이터를 화면에 표시할 때 사용한다. (일반적으로 웹 애플리케이션을 구현할 때 서버에서 데이터를 요청하고 받아오기 위해 API를 사용한다.)
요청에 대한 응답(데이터)이 오기도 전에 데이터를 화면에 표시하려고 하면 오류가 발생하거나 빈 화면이 나오는데 이와 같은 문제점을 해결하기 위한 방법으로 promise를 사용한다.

콜백함수 안에 콜백을 넣어서 구현할 수 있다. 하지만 계속 중첩되면 코드의 가독성이 나빠진다.
이러한 형태를 '콜백 지옥'이라고 한다. '콜백 지옥' 같은 코드가 형성되지 않게 하기 위해서 ES6에서 도입된 기능이다.

function increase(number) {
  const promise = new Promise((resolve, reject) => {
    // resolve: 성공, reject: 실패
    setTimeout(() => {
      const result = number + 10;
      if (result > 50) {
        const e = new Error('NumberTooBig');
        return reject(e);
      }
      resolve(result);
    }, 1000);
  });
  return promise;
}

increase(0)
  .then((number) => {
    return increase(number);
  })
  .then((number) => {
    return increase(number);
  })
  .catch((e) => {
    console.log(e);
  });

여러 작업을 연달아 처리하지만 함수를 여러번 감싸는 것이 아니라 그 다음 작업으로 설정하기 때문에 콜백 지옥이 형성되지 않는다.

Promise의 3가지 상태(states)

Pending(대기): 비동기 처리 로직이 완료되지 않은 상태

new Promise((resolve, reject) => {});

Fulfilled(이행): 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태

new Promise((resolve, reject) => {
  resolve();
});

이행 상태가 되면 then()을 사용해서 처리 결과 값을 받을 수 있다.

Rejected(실패): 비동기 처리가 실패하거나 오류가 발생한 상태

new Promise((resolve, reject) => {
  reject();
});

실패 상태가 되면 실패한 이유를 catch()로 받을 수 있다.

async/await

Promise를 더욱 쉽게 사용할 수 있도록 해주는 ES2017(ES8) 문법이다.
이 문법을 사용하려면 함수의 앞부분에 async 키워드를 추가하고 함수 내부에 Promise 앞 부분에 await 키워드를 사용한다.

기본적으로 비동기 코드를 쓰고 Promise를 더 읽기 쉽도록 만들어준다.

async 키워드를 붙여주면 Promise를 반환한다.

let hello = async () => { return "Hello" };

hello().then((value) => console.log(value))

결과를 직접반환하는게 아니라 Promise를 반환하게 된다.

async function hello() {
  return greeting = await Promise.resolve("Hello");
};

hello().then(alert);

axios로 API 호출해서 데이터 받아 오기

axios는 가장 많이 사용되고 있는 자바스크립트 HTTP 클라이언트이다.
이 라이브러리의 특징은 HTTP 요청을 Promise 기반으로 처리한다.

$yarn add axios

App.js

import React, { useState } from 'react';
import axios from 'axios';

const App = () => {
  const [data, setData] = useState(null);
  const onClick = () => {
    axios
      .get('https://jsonplaceholder.typicode.com/todos/1')
      .then((response) => {
        setData(response.data);
      });
  };

  return (
    <div>
      <div>
        <button onClick={onClick}>불러오기</button>
      </div>
      {data && (
        <textarea
          rows={7}
          value={JSON.stringify(data, null, 2)}
          readOnly={true}
        />
      )}
    </div>
  );
};

export default App;

async/await 적용했을 때

const onClick = async () => {
  try {
    const response = await axios.get(
      'https://jsonplaceholder.typicode.com/todos/1',
    );
    setData(response.data);
  } catch (e) {
    console.log(e);
  }
};

함수 앞에 async를 작성하고 Promise 객체가 반환되는 곳(대부분 API) 앞에 await를 작성한다. then()을 사용하지 않아도 되는 이유는 async/await가 없으면 then을 통해서 Promise객체가 반환됐을 때를 알고 setData를 해줄 수 있다.
await를 통해서 setData 함수의 실행을 지연시킬 수 있다.

0개의 댓글