[ 07.05 ] 비동기 리뷰

💣 리뷰하는 이유

이번주는 기존에 알고있던 React, styled-component 에 대해 배운다.
모르는 내용이 있다면 TIL 작성 하겠지만 이번주는 그동안 부족했던 비동기, 상태관리 등 스프린트에서 다룬 내용 위주로 복습겸, 블로깅해야할것 같다.

💣 비동기 리뷰

비동기 처리방식 세가지인 callback, Promise, async/await 세가지를 이용하여 나타내보기.

1. fs 모듈 이용하여 비동기처리 - callback 방식

fs.readFile(path,[,option],callback함수)
const fs = require("fs");

const getDataFromFile = function (filePath, callback) {
  // TODO: fs.readFile을 이용해 작성합니다
   fs.readFile(filePath,(err,data)=>{
    if(err){
      return callback(err,null);
    }
    else{
      return callback(null,data.toString());
    }
  })
};

module.exports = {
  getDataFromFile
};

🧨 풀이

fs.readFile 로 콜백함수를 부를때 err 가 날 경우와 data 가 제대로 처리될 경우 두가지의 인자를 작성해 주어야 한다.

인자가 2개이므로 callback을 리턴할땐 당연히 인자가 두개 와주어야 하는데, 해당되지 않는부분에는 반드시 null 을 넣어준다.
❗️ undefined 나 false 는 엄연히 "있는 값" 처리가 되기 때문에 사용할 수 없다.

2. fs 모듈과 promise 로 비동기 처리하기.

const fs = require("fs");

const getDataFromFilePromise = filePath => {
  // TODO: Promise 및 fs.readFile을 이용해 작성합니다
   return new Promise((resolve,reject)=>{
    fs.readFile(filePath,'utf8',(err,data)=>{
      if(err){
        return reject(err);
      }else{
        return resolve(data);
      }
    })
  })
}

module.exports = {
  getDataFromFilePromise
};

🧨 풀이

1번에서 작성한 콜백함수 자리에 err,data 를 인자에 작성해주었다면
프로미스의 resolve(성공), reject(실패) 를 작성하여 비동기처리 하였다.
부끄럽지만 이번에 다시 풀면서 새로 발견한건데 ,,
프로미스로 resolve, reject 인자를 지정할때 순서도 지켜줘야 한다.
그것도 모르고 reject, resolve 순으로 작성했더니 계속 오류가나서 혹시나,, 하고 써본게 역시나였다. ㅎㅎㅎ
new Promise 에 마우스를 갖다대면 해당 함수의 정보를 볼 수 있는데 너무도 명확하게 resolve,reject 순으로 나왔다.
밑의 조건문 주는 부분은 크게 상관없는것 같다.

3. promise chaning

const path = require('path');
const { getDataFromFilePromise } = require('./02_promiseConstructor');

const user1Path = path.join(__dirname, 'files/user1.json');
const user2Path = path.join(__dirname, 'files/user2.json');

/* user1.json,user2.json 파일의 내용
{
  "name": "김코딩",
  "age": 26,
  "sex": "Male",
  "company": {
    "name": "코드스테이츠"
  }
}
{
  "name": "박해커",
  "age": 40,
  "sex": "Female",
  "company": {
    "name": "Anomymous"
  }
}
*/

const readAllUsersChaining = () => {
  // TODO: 여러개의 Promise를 then으로 연결하여 작성합니다
  const promise1 = getDataFromFilePromise(user1Path);
  const promise2 = getDataFromFilePromise(user2Path);
  let result = '';
  
  return promise1
  .then((data1)=>{
    return promise2
    .then((data2)=>{
      result = `[${data1},${data2}]`
    })
  })
  .then(()=>{
    return JSON.parse(result);
  })
}

🧨 풀이

앞서 fs 모듈로 작성한 파일을 가져와서 promise 식을 작성했다.
이 문제의 목적은 객체형태로 되어있는 각각의 파일들을 하나의 배열에 합친 후 다시 JSON 형태로 리턴하는 것이다.
요로케 👉🏻 [ {user1.json} , {user2.json } ]
배열로 합치는거라 당연히 push 를 생각하고 풀었는데 나중에 JSON 형태로 다시 변환하는게 귀찮아져서 템플릿문자열로 바꿨다.
문자열이 된 상태를 다시 json 객체형태로 바꾸기 위해서 JSON.parse() 메소드를 사용했다.

❗️ then 이 받는 파라미터는 실행을 적용할 파라미터로,
사용법도 모르고 인자를 텅텅 비워둔 과거의 나자신 ,, 그래 발전했다 발전했어ㅠ 흡

4. Promise.all()

const path = require('path');
const { getDataFromFilePromise } = require('./02_promiseConstructor');

const user1Path = path.join(__dirname, 'files/user1.json');
const user2Path = path.join(__dirname, 'files/user2.json');

const readAllUsers = () => {
  // TODO: Promise.all을 이용해 작성합니다
  const prom1 = getDataFromFilePromise(user1Path);
  const prom2 = getDataFromFilePromise(user2Path);
  let result = '';

  return Promise.all([prom1,prom2])
  .then(([a,b])=>{
    result = `[${a},${b}]`
  })
  .then(()=>{
    console.log(result);
    return JSON.parse(result)
  })
}

🧨 풀이

3번과 같은 결과지만 이번에는 Promise.all() 을 사용했다.
여러개의 비동기 처리식이 있을때 여러번 써줄 필요없이 Promise.all 의 인자안에 넣어 처리할 수 있다.
Promise.all의 인자는 반드시 배열형태가 와야하며 .then 의 인자도 자연스럽게 Promise.all 의 인자의 갯수와 동일하다.

Promise.all 배열인자 안에서 then 처리하는 경우도 봤는데 그렇게 하면 더 헷갈렸다. 굳이 그렇게 쓰지 않겠다. ㅎ

5. async, await

const path = require('path');
const { getDataFromFilePromise } = require('./02_promiseConstructor');

const user1Path = path.join(__dirname, 'files/user1.json');
const user2Path = path.join(__dirname, 'files/user2.json');

const readAllUsersAsyncAwait = async () => {
  // TODO: async/await 키워드를 이용해 작성합니다
  const prom1 = await getDataFromFilePromise(user1Path)
  const prom2 = await getDataFromFilePromise(user2Path)
  let result = '';
  result = `[${prom1},${prom2}]`
  return JSON.parse(result);
}

🧨 풀이

마찬가지로 결과는 동일하지만 이번에는 async, await 을 이용하여
비동기처리를 해보았다.
가장 최근에 나오고, 딱봐도 제일 간편해보이는 이 두 쌍은 항상 같이 다닌다고 보면 된다.

❗️ 제일 간편하고 제일 쉽다고는 하지만 사실 await 를 어디에 써야할지 헷갈렸었다. 그냥 맘편하게 비동기처리할 함수에 붙여줘야 하는것 같다.
처음에 const prom1 = getDataFromFilePromise(user1Path) 한 후 뒤에서 await prom1 처리를 했더니 result 에서 작성한 prom1 에 전혀 반영이 되지 않았었다.


💣 응용

각각의 json 객체 형태의 url 이 있다.

let newsURL = 'http://localhost:5000/data/latestNews';
let weatherURL = 'http://localhost:5000/data/weather';

위의 url 에 담긴 객체를 다음과 같이 변경하고 두 url 내용을 합치는것이 목적이다.
👉🏻 변경된 사항 파악하기
newsURL의 key 인 data 가 news로 바뀌었고, weatherURL 은 weather 이라는 key 가 추가되어 obj 라는 하나의 객체에 담겼다.

Promise, PromiseAll, async/await 총 세가지 방법으로 바꿔보겠다.

const obj = {
      news: [
              {
                row_id: 2,
                title: '2021년 경제 성장률 전망 밝아',
                source: 'A신문',
                timestamp: '2020/12/30',
              },
              {
                row_id: 3,
                title: '코로나19 증가추세 대폭 하락해',
                source: 'BBC',
                timestamp: '2020/12/29',
              },
              {
                row_id: 4,
                title: '코드스테이츠 취업연계 파트너사 xxx건 돌파',
                source: '스타트업 뉴스',
                timestamp: '2020/12/31',
            },
         ],
    weather: { status: 'sunny', tempature: '28', finedust: 'good' },
          };

* fetch

fetch 는 url 의 비동기처리를 위해 사용되는 메소드이다.
fetch 의 형태는 아래와 같다.

fetch(url주소 또는 변수명)
.then((response)=>{return response.json()})
.then((data)=>{return data})
.catch((err)=>{return err})

fetch 와 같이쓰이는 것으로 매개변수가 따로 없는, json() 이 있다.
그냥 외워두는게 정신건강에 좋아서 외워버렸다.

1. Promise

function getNewsAndWeather() {
  let obj = {};
  
  return fetch(newsURL)
  .then((res)=>{return res.json()})
  .then((newsData)=>{
    obj.news = newsData.data;
    return fetch(weatherURL)
    .then((res)=>{return res.json()})
    .then((weatherData)=>{
      obj.weather = weatherData;
      return obj;
    })
  })
}

🧨 풀이

연속해서 처리해줄 newsURL 과 weatherURL 을 fetch 에 담아주었다.
앞서 말했다시피 fetch 는 json 처리를 해주는 .then 식과 실행할 .then 식을 작성해주고 그다음 처리해줄 비동기처리할 함수를 계속해서 이어나가는 식이다.

obj 라는 빈객체에 key 가 news인 값을 newsURL에서 받은 인자 newsData의 키인 data의 값을 대체해주었고
weatherURL 에서 받은 인자 weatherData에 obj객체의 key가 weather 인 값을 넣어주어 최종적으로 obj 를 리턴했다.
이게 복잡해 보인다면 아래와 같은 방법도 있다.

 return fetch(newsURL)
  .then((res)=>{return res.json()})
  .then((newsData)=>{
    return fetch(weatherURL)
  .then((res)=>{return res.json()})
    .then((weatherData)=>{
      return {
        news : newsData.data,
        weather : weatherData
      }
    })
  })

2. Promise.all()

function getNewsAndWeatherAll() {

  const newsData = fetch(newsURL).then((res)=>{return res.json()});
  const weatherData = fetch(weatherURL).then((res)=>{return res.json()});
  let obj = {};

  return Promise.all([newsData,weatherData])
  .then(([a,b])=>{
    obj.news = a.data,
    obj.weather = b
  })
  .then(()=>{
    return obj;
  })
}

🧨 풀이

인자에 너무 복잡하게 들어가면 가독성이 떨어질것 같아 따로 변수를 지정했다.
newsData 에는 newsURL을 fetch, json 처리 한것
weatherData 에는 weahterURL 을 fetch,json 처리한것.
그 나머지는 promise.all 에서 처리하기로 한다.

const newsData = fetch(newsURL).then((res)=>{return res.json()});
const weatherData = fetch(weatherURL).then((res)=>{return res.json()});

return Promise.all([newsData,weatherData])
 .then(([a,b])=>{
   return {
   news : a.data,
   weather : b
   }
 })

obj 변수에 따로 담아주지 않고 이렇게 한큐에 작성하는 방법도 있다.

3. async,await

async function getNewsAndWeatherAsync() {
 const newsData = await fetch(newsURL).then((res)=>{return res.json()});
 const weatherData = await fetch(weatherURL).then((res)=>{return res.json()});

  let obj = {};

  obj.news = newsData.data;
  obj.weather = weatherData;
  return obj;
}

🧨 풀이

위에서의 교훈을 일삼아 ,, await 은 바로 비동기함수에 붙여주었다.
사실 위에서 계속 반복이라 해설이랄게 없다.

async function getNewsAndWeatherAsync() {
const newsData = await fetch(newsURL).then((res)=>{return res.json()});
const weatherData = await fetch(weatherURL).then((res)=>{return res.json()});
  return {
    news : newsData.data,
    weather : weatherData
  }
}

obj 변수를 뺀, 더 가독성이 좋은코드로 다듬어보았다.


💣 처음에는 내가 배운내용이 맞나.. 하고 어리버리떨었는데
그거째애끔 익숙해졌다고 풀려진다.. ㅎ ,, 하지만 아무리 비동기 개념이 잡혔다고 해서 진짜 실무에선 어떻게 쓰일지 솔직히 감이 안잡힌다. 역시 많이 데여봐야 하는것 같다.

좋은 웹페이지 즐겨찾기