공공데이터 이용하기 18 ( Heroku 사용하여 관리자 모드 권한 부여하기 )

KHW·2021년 5월 30일
0

http-server

목록 보기
2/3

목적

데이터가 추가될 때 웹에 관리자 모드 부분을 만들어 관리자가 데이터가 추가됨에 따라 기존 코드를 고치지 않게 하기


Heroku 사용

날짜 적용하기 로 기존에 했던 것을 적용해보기로 했다.


코드 수정하기

기존에 연관된 Set_data.js , Daily_Increase_Day.js, Daily_Total,Increase_Modify2.js, Pi_Chart_Bar_Chart.js 코드를 수정해야했다.


비동기 처리

  • Set_data.js
let start = '2020-03-03'
let end = '2020-12-31'
function requestApiAndGetData() {
  return fetch('https://coronaproject.herokuapp.com/api/covidDate').then(res => res.json()).then(obj => {
    return obj.data
  })
}
function calculateDateArray(end){
  let sdt = new Date(start); // 2020년 03월 04일 부터 시작
  let edt = new Date(end);
  let dateDiff = Math.ceil((edt.getTime()-sdt.getTime())/(1000*3600*24));

  let Year,Month,Day;                 // 각 날짜별 날짜 생성
  const date_array = [];              // 해당 필요부분 넣을 배열 생성
  for(let i=0;i<dateDiff;i++)              // 2020년 3월 4일부터 마지막 데이터 csv까지의 날짜의 차이에서 +1 한 값이 150 (ex 현재는 7월 31일까지)
  {
    sdt.setDate(sdt.getDate()+1)        // 3월 4일 계산 후 하루씩 증가
    Year = sdt.getFullYear().toString().slice(2,4);       // 2020년이 아닌 뒤의 두자리 수만 필요하므로 slice 사용
    Month = (sdt.getMonth()+1).toString().length==1 ? '0'+ (sdt.getMonth()+1).toString() :(sdt.getMonth()+1).toString() ; // 한자리 수 인경우 앞에 0을 붙인다.
    Day = sdt.getDate().toString().length==1? '0'+sdt.getDate().toString() : sdt.getDate().toString();
    date_array.push(Year+Month+Day);    //합친 내용을 배열로 만들어 준다.
  }
  return date_array;     //해당 배열을 반환한다.
}

async function Set_Date(){
  let data = await requestApiAndGetData();
  let date_array = await calculateDateArray(data);
  return date_array;
}

export {Set_Date}

주요 부분은 2개의 함수를 async await을 통해 비동기에 순차성을 부여하였다. 해당 함수만 작동시키면
먼저 requestApiAndGetData를 수행하고 return한 data 변수를 가지고 다시 calculateDateArray에 매개변수로 넣어 수행하고 date_array를 반환한다.

  • 주의할점 : async await 사용법 , fetch 사용시에도 해당 return 부분을 다시 return 해야한다. return fetch(~).then().then({return ~})

Daily_Increase_Day.js 코드 수정하기

  • 기존코드
import {url} from './utils/Data.js'
import {Set_Date} from "./utils/Set_Date.js";

const numberInput = document.getElementById('numberInput');

numberInput.addEventListener('keyup',(e)=>checkClick(e))
const checkClick = function(e){
  if(e.key === 'Enter' && Number.isInteger(Number(numberInput.value)))
  {
    load(numberInput.value);
  }
}

async function load (value) {
  const get_date = [];
  const get_sum = [];
  try {
    const datas = await Promise.all(Set_Date().map(date =>
      dfd.read_csv(`${url}${date}.csv`)
    ));
    datas.forEach(data => {
      get_sum.push(data.body__items__item__incDec.data[data.body__items__item__incDec.data.length - 1]);
      get_date.push(data.body__items__item__createDt.data[0].slice(2, 10));
    })
    let newSum = [];
    let newDate = [];
    get_sum.forEach((sum, index) => {
      if (sum > value) {
        newSum.push(sum);
        newDate.push(get_date[index]);
      }
    })
    const dataFrame = {'sum': newSum, 'data': newDate};
    const df = new dfd.DataFrame(dataFrame);
    df.plot('table').table();
  }
  catch(err){
    alert(err);
  }
}

async await에서 Promise.all을 이용하였다.

  • 수정한 코드
import {url} from './utils/Data.js'
import {Set_Date} from "./utils/Set_Date.js";

const numberInput = document.getElementById('numberInput');

numberInput.addEventListener('keyup',(e)=>checkClick(e))
const checkClick = function(e){
  if(e.key === 'Enter' && Number.isInteger(Number(numberInput.value)))
  {
    load(numberInput.value);
  }
}

async function load (value) {
  const get_date = [];
  const get_sum = [];
  try {
    const datas = await Set_Date()
      .then(values=>values.map(date => dfd.read_csv(`${url}${date}.csv`)))
      .then(data=>Promise.all(data));

    datas.forEach(data => {
      get_sum.push(data.body__items__item__incDec.data[data.body__items__item__incDec.data.length - 1]);
      get_date.push(data.body__items__item__createDt.data[0].slice(2, 10));
    })
    let newSum = [];
    let newDate = [];
    get_sum.forEach((sum, index) => {
      if (sum > value) {
        newSum.push(sum);
        newDate.push(get_date[index]);
      }
    })
    const dataFrame = {'sum': newSum, 'data': newDate};
    const df = new dfd.DataFrame(dataFrame);
    df.plot('table').table();
  }
  catch(err){
    alert(err);
  }
}

async await은 같지만 해당 Set_Date함수를 이용해

values부분은 ["200304", "200305", "200306", "200307", "200308", "200309", "200310", "200311", "200312", "200313", "200314", "200315", "200316", "200317", "200318", "200319", "200320", "200321", "200322", "200323", "200324", "200325", "200326", "200327", "200328", "200329", "200330", "200331", "200401", "200402", "200403", "200404", "200405", "200406", "200407", "200408", "200409", "200410", "200411", "200412", "200413", "200414", "200415", "200416", "200417", "200418", "200419", "200420", "200421", "200422", "200423", "200424", "200425", "200426", "200427", "200428", "200429", "200430", "200501", "200502", "200503", "200504", "200505", "200506", "200507", "200508", "200509", "200510", "200511", "200512", "200513", "200514", "200515", "200516", "200517", "200518", "200519", "200520", "200521", "200522", "200523", "200524", "200525", "200526", "200527", "200528", "200529", "200530", "200531", "200601", "200602", "200603", "200604", "200605", "200606", "200607", "200608", "200609", "200610", "200611", …] 이러한 배열부분이고

해당 내용을 map함수를 이용해 각각 분리한 것이 date이다.

data 부분은 Promise형태로 반환되어 이를 처리하기 위해 Promise.all을 사용하여 return 하였다.

Danfo 사이트에서도 해당 dfd.read_csv부분을 Promise형태로 반환되어 처리하기 때문에 그에대해 처리를 위해서는 Promise.all을 이용하여 반환시켜야 원하는 값을 얻을 수 있다.


Daily_Total_Increase_Modify2.js 코드수정

  • 기존코드
  const datas = await Promise.all(Set_Date().map(date =>
    dfd.read_csv(`${url}${date}.csv`)
  ));
  • 수정코드
  const datas = await Set_Date()
    .then(values=>values.map(date =>dfd.read_csv(`${url}${date}.csv`)))
    .then(data=>Promise.all(data));

마찬가지로 유사하게 진행한다. 결국 다른점은 Promise를 처리하기 위해 진행된다.


Pi_Chart_Bar_Chart.js

  • 수정코드
const datas = await Set_Date()
  .then(values=>values.map(date =>dfd.read_csv(`${url}${date}.csv`)))
  .then(data=>Promise.all(data));

기존코드에서 end변수만을 이용한 것을 바꾸었다.


코드 고민 더 해보기

  • 기존코드
  const datas = await Promise.all(Set_Date().map(date =>
    dfd.read_csv(`${url}${date}.csv`)
  ));
  • 수정코드
  const datas = await Set_Date()
    .then(values=>values.map(date =>dfd.read_csv(`${url}${date}.csv`)))
    .then(data=>Promise.all(data));

이렇게 바꿨었는데

  • 고민한 코드
  const datas = await Promise.all(Set_Date()
    .then(values=>values.map(date =>dfd.read_csv(`${url}${date}.csv`))))

이렇게 코드는 안되는 것인가 고민해보니 오류가 떴다.

TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))


Set_date 함수가 async 함수일때와 아닐때의 차이점

console.log(Set_Date()) 결과


async가 아닐때

    const datas = await Promise.all(Set_Date().map(date =>
      dfd.read_csv(`${url}${date}.csv`)
    ));

배열형태로 리턴된다.
Set_Date().map(date => dfd.read_csv(${url}${date}.csv))
해당부분이 Promise로 반환하므로 이를 처리하려면 Promise.all(Promise형태)로 진행되어야한다.


async일때

    const datas = await Set_Date()
      .then(values=>values.map(date => dfd.read_csv(`${url}${date}.csv`)))
      .then(data=>Promise.all(data));

Promise 형태로 리턴한다.
Promise이므로 then형태로 만들어 처리하되 Promise를 then으로 순차적으로 처리하기때문에 첫번째 then을 통해 처리된 data 부분이 Promise형태이기 때문에 이를 다시 then형태로 Promise.all을 이용한다.


정리

  • async await을 통해서 비동기의 순차적 처리가 가능하고
    async 함수는 일반 함수와 다르게 return 값이 같은 Object에 같은 배열 형태로 나타나더라도 실체는Promise형태이다.
    일반함수는 그냥 Object에 같은 배열 형태이다.
  • 즉, 리턴한 값을 처리할 때
    일반함수는 map함수를 쓰면서 이를 전체를 묶어 처리하는 Promise.all(Promise 배열형태)이고
    async 함수는 then으로 연결처리를 해야하므로 Promise형태.then(~).then(promise형태=>Promise.all(promise 배열형태))로 처리한다.
profile
나의 하루를 가능한 기억하고 즐기고 후회하지말자

0개의 댓글