리액트 비동기

심채운·2022년 8월 5일
0

React

목록 보기
6/12

비동기 작업

웹 애플리케이션에서 서버 쪽 데이터가 필요할 때는 Ajax 기법을 사용하여 서버의 API를 호춤함으로써 데이터를 수신한다. 이렇게 서버의 API를 사용해야 할 때는 네트워크 송수신 과정에서 시간이 걸리기 때문에 작업이 즉시 처리되는 것이 아니라, 응답을 받을 때까지 기다렷다가 전달받은 응답 데이터를 처리해야한다. 이 과정에서 해당 작업을 비동기적으로 처리하게 된다.

동기 : 요청이 끝날 때까지 기다리는 동안 중지 상태가 되기 때문에 다른 작업을 할 수 없다. 요청이 끝나야 비로소 그다음 예정된 작업을 할 수 있다.
비동기 : 웹 애플리케이션이 멈추지 않기 때문에 동시에 여러가지 요청을 처리할 수 잇고, 기다리는 과정에서 다른 함수도 호출할 수 있다.
이렇게 서버 API를 호출할 때 외에도 작업을 비동기적으로 처리할 때가 있는데, 바로 setTimeout함수를 사용하여 특정 작업을 예약할 때이다.
자바스크립트에서 비동기 작업을 할 때 가장 흔히 사용하는 방법은 콜백 함수를 사용하는 것이다.

콜백 함수

function increase(number, callback) {
  setTimeout(() => {
    const result = number + 10;
    if (callback) {
      callback(result);
    }
  }, 1000);
}

increase(0, (result) => {
   console.log(result);
});

콜백함수를 중첩으로 구현할 수도 있다. ( 1초에 걸쳐 10씩 증가되는 값을 반환하려면)

function increase(number, callback) {
  setTimeout(() => {
    const result = number + 10;
    if (callback) {
      callback(result);
    }
  }, 1000);
}
console.log("작업시작");
increase(0, (result) => {
  console.log(result);
  increase(result, (result) => {
    console.log(result);
    increase(result, (result) => {
      console.log(result);
      increase(result, (result) => {
        console.log(result);
        console.log("작업 완료");
      });
    });
  });
});

이렇게 콜백안에 또 콜백을 넣어서 구현할 수 있지만, 여러번 중첩이 되면 코드의 가독성이 나빠진다. 이러한 형태의 코드를 '콜백 지옥'이라 부르고 이러한 코드는 지양해야 할 형태이다.

Promise

promise는 콜백 지옥같은 코드가 형성되지 않게 하는 방법으로 ES6에 도입된 기능이다.
.then을 사용하여 다음 작업을 설정한다. .catch로 에러를 잡아낸다.

function increase(number) {
  const promise = new Promise((resolve, reject) => {
    //resolve는 성공, reject는 실패
    setTimeout(() => {
      const result = number + 20;
      if (result > 50) {
        //50보다 높으면 에러 발생시키기
        const e = new Error("NumberTooBig");
        return reject(e);
      }
      resolve(result); // number 값에 +10 후 성공 처리
    }, 1000);
  });
  return promise;
}

increase(0)
  .then((number) => {
    //Promise에서 resolve된 값은 .then을 통해 받아 올 수 있음.
    console.log("number1 :", number);
    return increase(number); //Promise를 리턴하면
  })
  .then((number) => {
    //또 .then으로 처리가능
    console.log("number2 :", number);
    return increase(number);
  })
  .then((number) => {
    console.log("number3 :", number);
    return increase(number);
  })
  .then((number) => {
    console.log("number4 :", number);
    return increase(number);
  })
  .catch((e) => {
    //도중에 에러가 발생한다면 .catch를 통해 알 수 있다.
    console.log(e);
  });

async/await

async/await는 promise를 더욱 쉽게 사용할 수 있도록 해주는 ES8(ES2017)문법이다. 이 문법을 사용하려면 function앞 부분에 async 키워드를 추가하고, 해당 함수 내부에서 promise의 앞부분에 await 키워드를 사용한다. 이렇게 하면 promise가 끝날 때까지 기다리고, 그 결과 값을 특정 변수에 담을 수 있다.

function increase(number) {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      const result = number + 10;
      if (result > 50) {
        const e = new Error("NumberTooBig");
        return reject(e);
      }
      resolve(result);
    }, 1000);
  });
  return promise;
}

async function runTasks() {
  try {
    //try / catch 구문을 사용하여 에러를 처리한다.
    let result = await increase(0);
    console.log("result1:", result);
    result = await increase(result);
    console.log("result2:", result);
    result = await increase(result);
    console.log("result3:", result);
    result = await increase(result);
    console.log("result4:", result);
    result = await increase(result);
    console.log("result5:", result);
    result = await increase(result);
    console.log("result6:", result);
  } catch (e) {
    console.log(e);
  }
}

runTasks();

axios

axios는 현재 가장 많이 사용되고 있는 자바스크립트 HTTP클라이언트이다. 이 라이브러리의 특징은 HTTP 요청을 Promise 기반으로 처리한다는 점이다.
onClink 함수에서는 axios.get함수를 사용했다. 이 함수는 파라미터로 전달된 주소에 GET요청을 해주고 이에 대한 결과는 .then을 통해 비동기적으로 확인 할 수 있다.

// import logo from './logo.svg';
// import './App.css';
import { useState } from 'react';
import axios from 'axios';

function App() {
  const [data, setDate] = useState(null);

  const onClick = () => {
    axios
      .get('https://jsonplaceholder.typicode.com/todos/1')
      .then((response) => {
        console.log(response);
        setDate(response.data);
      });
  };
  return (
    <div className="App">
      <div>
        <button onClick={onClick}>불러오기</button>
      </div>
      {data && (
        <textarea
          rows={7}
          value={JSON.stringify(data, null, 2)}
          readOnly={true}
        />
      )}
    </div>
  );
}

export default App;
profile
불가능, 그것은 사실이 아니라 하나의 의견일 뿐이다. - 무하마드 알리

0개의 댓글