본문 바로가기
국비학원/수업기록

국비 지원 개발자 과정_Day53

by 루팽 2023. 2. 13.

"type": "module",

packge.json에 등록한다

생략하면 CommonJS이므로 반드시 module 등록한 후 사용 가능(주의할 것!)

 

<step 1>

export default 10; // 1개밖에 사용 못함, default사용하면 {} 사용불가!

export const insa = "hello";
export const names = ["apple", "kiwi", "tomato"];
export const hap = (i, j) => {
  return i + j;
};

export class Sonata {
  constructor() {
    this.wheelNum = 4;
    this.speed = 10;
  }

  speedUp = () => {
    this.speed = this.speed + 1;
  };
}

/* 
  호이스팅 이슈
  1) var i
  2) head태그 안에 선언한 함수
  3) import문 - 모듈사용(ES6, 브라우저지원)

  함수선언
  1) 선언형 함수
  2) 익명함수 - 콜백함수(나중에 실행) -> JS는 동기적
  전제조건: JS에서는 함수도 객체다
  3) 대입함수 - 일급함수 -> 고차함수[리덕스(리액트 상태관리 구현한것) 만드는데 결정적 역할] -> 리액트
  const func = () => {}
  4) 즉시실행함수 (){} - ES6 이전에는 호이스팅 이슈를 해결하는 방법으로 사용됨
*/

 

import number from "./module1.js";
import { insa, names, hap, Sonata } from "./module1.js";

console.log(number); // 10
console.log(insa); // hello
console.log(names); // [ 'apple', 'kiwi', 'tomato' ]
console.log(hap); // [Function: hap]

const myCar = new Sonata();
console.log(`내 자동차의 바퀴수는 ${myCar.wheelNum}`); // 내 자동차의 바퀴수는 4
myCar.speedUp();
console.log(`현재 소나타의 속도는 ${myCar.speed}`); // 현재 소나타의 속도는 11

 

import * as all from "./module1.js";

console.log(all);
/* [Module: null prototype] {
  Sonata: [class Sonata],
  default: 10,
  hap: [Function: hap],
  insa: 'hello',
  names: [ 'apple', 'kiwi', 'tomato' ]
} */
console.log(all.insa); // hello
console.log(all.names); // [ 'apple', 'kiwi', 'tomato' ]
console.log(all.hap); // [Function: hap]

/* 
  매개변수로 함수를 받을 수 있다는 것은 함수가 객체라는 의미
  리턴타입을 함수로 사용 가능한 것은 고차함수
  변수가 함수를 참조할 수 있는 것은 일급함수
  이런 것들이 가능한 객체를 일급 객체라고함
*/

const myCar = new all.Sonata();
console.log(`내 자동차의 바퀴수는 ${myCar.wheelNum}`); // 내 자동차의 바퀴수는 4
myCar.speedUp();
console.log(`현재 소나타의 속도는 ${myCar.speed}`); // 현재 소나타의 속도는 11

 

console.log(1);
setTimeout(() => {
  console.log(2);
}, 2000); // mili sec 1000이 1초임
console.log(hap(1, 3)); /// import문이 뒤에 있음에도 4가 출력됨 -> 호이스팅 발생
/* import문도 호이스팅이 일어남 */
import { hap } from "./module1.js";
console.log(3);

/*
1
4
3
2
*/

 

<step 2>

export const one = () => {
  return 1;
};

 

export const two = () => {
  return 2;
};

 

export { one } from "./one.js";
export { two } from "./two.js";

// 모듈을 가져오자마자 내보내기도 가능

 

import { one, two } from "./common.js";

console.log(one()); // 1
console.log(two()); // 2

 

kakaomap api

1. npm init -y

    package.json 생성됨

2. index.js 파일 추가한 뒤 console.log('123')

3. package.json에 아래 내용 수정함

    "scripts": {

    "dev": "parcel ./index.html",

    "build": "parcel build ./index.html" },

4. 실행 시에는 npm run dev

5. 콘솔창에 http://localhost:1234 ctrl+클릭

6. 해당 파일이 열림

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Kakao 지도 시작하기</title>
  </head>
  <body>
    <div id="map" style="width: 700px; height: 500px"></div>
    <script
      type="text/javascript"
      src="//dapi.kakao.com/v2/maps/sdk.js?appkey="
    ></script>
    <script>
      const container = document.getElementById("map");
      const options = {
        center: new kakao.maps.LatLng(37.4989931, 127.0329085),
        level: 2,
      };

      const map = new kakao.maps.Map(container, options);

      const marker = new kakao.maps.Marker({
        position: new kakao.maps.LatLng(37.4989931, 127.0329085),
      });
      marker.setMap(map);
    </script>
  </body>
</html>

 

동기(synchronous)

코드를 순차적으로 실행

 

비동기(asynchronous)

코드를 비순차적으로 실행

 

<동기와 비동기 step 1>

setTimeout(() => {
  console.log("상품조회");
}, 3000);
console.log("장바구니담기");
console.log("결제");
console.log("배송준비");

/* 
비동기, 순서x
장바구니담기
결제
배송준비
상품조회
*/

 

<동기와 비동기 step 2>

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button id="btnCart">장바구니담기</button>
    <script src="./main2.js"></script>
  </body>
</html>

 

const btnCart = document.querySelector("#btnCart");
// 자바스크립트는 기본적으로 동적 처리이다
// 그러나 실생활에서는 비동기적 상황들이 훨씬 많이 일어난다
btnCart.addEventListener("click", () => {
  console.log("카트담기");
});
console.log("여기");

 

<callback패턴 1>

// 콜백(callbak) 패턴

const goodSearch = () => console.log("상품조회");
const cart = () => console.log("카트담기");

goodSearch();
cart();

/*
상품조회
카트담기
*/

 

<callback패턴 2 - 지연발생>

// 콜백(callbak) 패턴

const goodSearch = () => {
  setTimeout(() => {
    console.log("상품조회");
  }, 2000);
};
const cart = () => console.log("카트담기");

goodSearch();
cart();

/*
카트담기
상품조회
*/

 

<callback패턴 3 - 콜백함수>

// 콜백(callbak) 패턴

const goodSearch = (callback) => {
  setTimeout(() => {
    console.log("상품조회");
    callback();
  }, 2000);
};
const cart = () => console.log("카트담기");

// 함수도 객체 -> 파라미터(일급함수), 리턴타입(고차함수)으로 넘길 수 있다
goodSearch(() => {
  cart();
});

/* 
상품조회
카트담기
*/

 

<callback패턴 4 - 결제하기 추가>

// 콜백(callbak) 패턴

const goodSearch = (callback) => {
  setTimeout(() => {
    console.log("상품조회");
    callback();
  }, 3000);
};

const cart = (callback) => {
  setTimeout(() => {
    console.log("카트담기");
    callback();
  }, 2000);
};

const account = () => console.log("결제하기");

goodSearch(() => {
  cart(() => {
    account();
  });
});

/* 
상품조회
카트담기
결제하기
*/

 

<callback패턴 5 - 배송하기 추가>

// 콜백(callbak) 패턴

const goodSearch = (callback) => {
  setTimeout(() => {
    console.log("상품조회");
    callback();
  }, 3000);
};

const cart = (callback) => {
  setTimeout(() => {
    console.log("카트담기");
    callback();
  }, 2000);
};

const account = (callback) => {
  setTimeout(() => {
    console.log("결제하기");
    callback();
  }, 4000);
};

const delivery = () => console.log("배송하기");

goodSearch(() => {
  cart(() => {
    account(() => {
      delivery();
    });
  });
});

/* 
상품조회
카트담기
결제하기
배송하기
*/

/* 
  이처럼 순서대로 일처리를 위해 콜백을 계속 반복해서 작성해야하고
  바깥쪽에서 안쪽으로 계속적인 들여쓰기가 되면서 해석하기도 불편하고
  유지보수도 어려워진다.
  이것을 콜백지옥이라고함
*/

 

<Promise prototype 활용 1>

// Promise prototype 활용

const goodSearch = () => {
  // 고차함수(함수 반환함)
  // 설공시 resolve 콜백, 실패시 reject 콜백
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("상품조회");
      resolve();
    }, 2000);
  });
};
const cart = () => console.log("카트담기");

// goodSearch함수가 호출될 때 콜백에서 cart함수를 호출하면
// 순서가 보장된다
goodSearch().then(() => {
  cart();
});

/* 
상품조회
카트담기 
*/

 

<Promise prototype 활용 2 - 결제하기 추가>

// Promise prototype 활용

const goodSearch = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("상품조회");
      resolve();
    }, 3000);
  });
};

const cart = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("카트담기");
      resolve();
    }, 2000);
  });
};

const account = () => console.log("결제하기");

goodSearch()
  .then(() => {
    return cart();
  })
  .then(() => {
    return account();
  });

/* 
상품조회
카트담기
결제하기
*/

 

<Promise prototype 활용 3 - 배송하기 추가>

// Promise prototype 활용

const goodSearch = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("상품조회");
      resolve();
    }, 3000);
  });
};

const cart = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("카트담기");
      resolve();
    }, 2000);
  });
};

const account = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("결제하기");
      resolve();
    }, 2000);
  });
};

const delivery = () => console.log("배송하기");

goodSearch()
  .then(() => {
    return cart();
  })
  .then(() => {
    return account();
  })
  .then(() => {
    return delivery();
  });

/* 
상품조회
카트담기
결제하기
배송하기
*/

 

<Promise prototype 활용 4 - fetch형식으로 바꾸기 1>

// Promise prototype 활용

const goodSearch = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("상품조회");
      resolve();
    }, 3000);
  });
};

const cart = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("카트담기");
      resolve();
    }, 2000);
  });
};

const account = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("결제하기");
      resolve();
    }, 2000);
  });
};

const delivery = () => console.log("배송하기");

// Fetch형식으로 바꾸기
goodSearch()
  .then(() => cart())
  .then(() => account())
  .then(() => delivery());

/* 
상품조회
카트담기
결제하기
배송하기
*/

 

<Promise prototype 활용 4 - fetch형식으로 바꾸기 2>

// Promise prototype 활용

const goodSearch = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("상품조회");
      resolve();
    }, 3000);
  });
};

const cart = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("카트담기");
      resolve();
    }, 2000);
  });
};

const account = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("결제하기");
      resolve();
    }, 2000);
  });
};

const delivery = () => console.log("배송하기");

// Fetch형식으로 바꾸기
goodSearch()
  .then(cart) // 파라미터로 cart를 넘기면 resolve가 cart함수 전체를 받아서 처리해줌
  .then(account) // account를 넘기면 resolve가 account함수 전체를 받아서 처리해줌
  .then(delivery) // delivery를 넘기면 resolve가 delivery함수 전체를 받아서 처리해줌
  .then(() => console.log("배송완료"));

/* 
상품조회
카트담기
결제하기
배송하기
배송완료
*/

 

<기존의 authLogic>

import {
  getAuth,
  signInWithPopup,
  GithubAuthProvider,
  GoogleAuthProvider,
} from "https://www.gstatic.com/firebasejs/9.17.1/firebase-auth.js";

// 객체선언 - 자바스크립트에는 중복선언이 불가하다
class AuthLogic {
  // 익명 생성자
  constructor() {
    this.firebaseAuth = getAuth(); // 구글에서 객체 주입해줌
    this.googleProvider = new GoogleAuthProvider(); // 구글 지원 객체
    this.githubProvider = new GithubAuthProvider(); // 구글 github 지원 객체
  }

  // 로그인 함수
  login(providerName) {
    const authProvider = this.getProvider(providerName); // 구글인지 깃헙인지 문자열 정보 가져옴
    return signInWithPopup(this.firebaseAuth, authProvider);
  }

  // 로그아웃 버튼이 눌리면 호출
  // 굳이 export로 선언하는 이유
  // -> 리액트에서는 한 페이지를 모듈화시켜서 재사용성을 높이는 방식이므로
  //  어떤 컴포넌트에서든지 호출이 가능하도록 (함수를) 설계하는것이 좋다
  logout() {
    this.firebaseAuth.signOut();
  }

  // 호출되면 파라미터값에 따라서 변경사항이 있을때마다 자동 호출됨
  onAuthChange(onUserChanged) {
    // 구글에서 제공되는 함수 - onAuthStateChanged
    this.firebaseAuth.onAuthStateChanged((user) => {
      onUserChanged(user);
    });
  }

  // 파라미터에 Google 혹은 Github(소문자로쓰면 값이달라 에러!)
  getProvider(providerName) {
    switch (providerName) {
      case "Google":
        return this.googleProvider;
      case "Github":
        return this.githubProvider;
      default:
        throw new Error(`not supported provider: ${providerName}`);
    }
  }
}

export default AuthLogic; // 이렇게해야 외부에서 사용가능함, 객체가 하나니까 default붙임

/* 
  package.json에는 의존관계 라이브러리 등록
    개발자 의존 -D(실제 운영서버에는 미배포)
    배포용


    외부 스크립트 사용 방법
  1. commonjs - 디폴트(생략되어있음 - package.json -> npm init -y해야 생성됨)
    const http = requires('http')

  2. module
    import { ... } from './XXX.js'

    리액트 수업 공통 사항
    authLogic.js - 리액트 수업 활용


    export - 여러개 가능 {}
    export default - 하나만 가능


    호이스팅 대상(가장 먼저 실행된다, 전역변수화된다)
    1. var i
    2. 함수 선언
    3. import문
    

    이걸 미루는 예약어 defer -> 다운로드가 끝나고, 브라우저(인터프리터)가 DOM Tree를 그린다 이때까지 기다릴것
    -> DOM Tree가 완성되면 DOM API 사용가능 -> document.querySelector() document.querySelectorAll() => 반환타입 배열[]
    -> 브라우저는 같은 이름이 두 개 이상이면 자동으로 배열 전환이 된다.
      checkbox neme = hobby
      배열 - 데이터셋과 직결 - json
      const temp = JSON.stringify(response.json()) -> 객체를 문자열로 바꿔줌
      const jsonDoc = JSON.parse(temp) -> 문자열을 배열로 바꿔줌
      jsonDoc[].XXX

      이런 json 누가 제공하나? -> 서버가 제공한다
      유투브 API, OpenWeather, HackerNews 등등
      내려받으려면 시간이 걸림 - 비동기처리 발생 - 지연발생
      따로따로 처리하다가 먼저 처리가 되면 -> then(()=>{})

      fetch("https://api.openweathermap.org/data/2.5/weather?appid=&q=seoul&units=metric", requestOptions)
      .then(response => response.text())
      .then(result => console.log(result))
      .catch(error => console.log('error', error));


      mime type
      text/javascript -> import, require쓰면 error!
      text/module -> import기억하기
      text/common -> require기억하기
      위의 것들은 서로 호환되지 않는다
    */

 

<Promise 활용한 authLogic>

import {
  getAuth,
  signInWithPopup,
  GithubAuthProvider,
  GoogleAuthProvider,
} from "https://www.gstatic.com/firebasejs/9.17.1/firebase-auth.js";
class AuthLogic {
  constructor() {
    this.auth = getAuth();
    this.googleProvider = new GoogleAuthProvider();
  }

  getUserAuth = () => {
    return this.auth;
  };

  getGoogleAuthProvider = () => {
    return this.googleProvider;
  };
} // end of AuthLogic

export default AuthLogic;

// 크롬에서 서비스 사용시 로그인 정보가 수정될 때 콜백되는 코드
// 상태가 바뀔때마다 자볻으로 호출됨
// 절대 개발자가 호출하는 함수가 아님
export const onAuthChange = (auth) => {
  return new Promise((resolve) => {
    auth.onAuthStateChanged((user) => {
      resolve(user);
    });
  });
};

export const loginGoogle = (auth, googleProvider) => {
  return new Promise((resolve, reject) => {
    //result에는 구글 서버에서 전달해준 사용자 이름이 들어있음
    signInWithPopup(auth.googleProvider)
      .then((result) => {
        const user = result.user;
        console.log(user); // json형식
        resolve(user);
      })
      .catch((e) => reject(e));
  });
}; // end of loginGoogle

export const logout = (auth) => {
  return new Promise((resolve, reject) => {
    auth.signOut().catch((e) => reject(alert(e + ": 로그아웃 에러입니다")));
    resolve();
  });
};

 

<OpenWeatherAPI 1 - 날씨조회>

import { weatherKey } from "../../apiKEY.js";

const getWeather = (local, callback) => {
  fetch(
    `https://api.openweathermap.org/data/2.5/weather?appid=${weatherKey}&q=${local}&units=metric`
  )
    .then((response) => response.json())
    .then((response) => {
      console.log(response);
      callback();
    });
};

// 함수호출, 비동기(순서x)
getWeather("seoul", () => {
  console.log("서울 날씨 가져오기");
});

getWeather("busan", () => {
  console.log("부산 날씨 가져오기");
});

getWeather("incheon", () => {
  console.log("인천 날씨 가져오기");
});

 

<OpenWeatherAPI 2 - callback활용>

import { weatherKey } from "../../apiKEY.js";

const getWeather = (local, callback) => {
  fetch(
    `https://api.openweathermap.org/data/2.5/weather?appid=${weatherKey}&q=${local}&units=metric`
  )
    .then((response) => response.json())
    .then((response) => {
      console.log(response);
      callback();
    });
};

// 함수호출, 비동기(순서x)
getWeather("seoul", () => {
  console.log("서울 날씨 가져오기");
  getWeather("busan", () => {
    console.log("부산 날씨 가져오기");
    getWeather("incheon", () => {
      console.log("인천 날씨 가져오기");
    });
  });
});

 

<OpenWeatherAPI 3 - promise 활용>

import { weatherKey } from "../../apiKEY.js";

const getWeather = (local) => {
  return new Promise((resolve, reject) => {
    fetch(
      `https://api.openweathermap.org/data/2.5/weather?appid=${weatherKey}&q=${local}&units=metric`
    )
      .then((response) => response.json())
      .then((response) => {
        console.log(response);
        resolve();
      });
  });
};

getWeather("seoul")
  .then(() => {
    console.log("서울 날씨 가져오기");
  })

  .then(() => {
    console.log("부산 날씨 가져오기");
    return getWeather("busan");
  })

  .then(() => {
    console.log("인천 날씨 가져오기");
    return getWeather("incheon");
  });

 

<jquery이용해 브라우저에 출력>

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>날씨조회</title>
  </head>
  <body>
    <h3 id="cTime">현재시간→</h3>
    <h3 id="cTemp">현재온도→</h3>
    <h3 id="maxTemp">최고온도→</h3>
    <h3 id="minTemp">최저온도→</h3>
    <h2 class="icon"></h2>
    <script
      src="https://code.jquery.com/jquery-3.6.3.js"
      integrity="sha256-nQLuAZGRRcILA+6dMBOvcRh5Pe310sBpanc6+QBmyVM="
      crossorigin="anonymous"
    ></script>
    <script>
      $.getJSON(
        `https://api.openweathermap.org/data/2.5/weather?appid=&q=seoul&units=metric`,
        (result) => {
          console.log(result);
          console.log(result.dt);
          console.log(result.main);
          console.log(result.weather);
          console.log(result.weather[0].icon);

          // 현재 시간 출력하기
          // 시간(밀리세크) 단위 변환
          const timeFormat = (t) => {
            const cdate = new Date(t * 1000);
            const hour = cdate.getHours();
            const min = cdate.getMinutes();
            const sec = cdate.getSeconds();
            return `${hour}:${min}:${sec}`;
          };

          const dt = result.dt; // 현재시간(밀리세크단위)
          const test = timeFormat(dt);
          $("#cTime").append(test);

          // 현재 온도 출력하기
          $("#cTemp").append(result.main.temp);

          // 최고온도 출력하기
          $("#maxTemp").append(result.main.temp_max);

          // 최저온도 출력하기
          $("#minTemp").append(result.main.temp_min);

          // 날씨 아이콘 출력하기
          const iconURL = `<img src="http://openweathermap.org/img/wn/${result.weather[0].icon}.png" alt="${result.weather[0].description}" />`;
          $(".icon").html(iconURL);
        }
      );
    </script>
  </body>
</html>

 

<async와 await 1>

// async와 await

const goodSearch = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("상품조회");
      resolve();
    }, 2000);
  });
};

const cart = () => console.log("카트담기");

// async와 await 사용
const runTest = async () => {
  await goodSearch();
  cart();
};

runTest();

/* 
상품조회
카트담기
*/

 

<async와 await 2 - 날씨 가져오기>

import { weatherKey } from "../../apiKEY.js";

const getWeather = (local) => {
  return new Promise((resolve, reject) => {
    fetch(
      `https://api.openweathermap.org/data/2.5/weather?appid=${weatherKey}&q=${local}&units=metric`
    )
      .then((response) => response.json())
      .then((response) => {
        console.log(response);
        resolve();
      });
  });
};

// promise가 반환하는 함수에서만 await를 붙여야한다
// console.log에는 await를 붙이지 않는다
// async와 await는 함께 사용한다
const runTest = async () => {
  await getWeather("seoul");
  console.log("서울 날씨 가져오기");
  await getWeather("busan");
  console.log("부산 날씨 가져오기");
  await getWeather("incheon");
  console.log("인천 날씨 가져오기");
};

runTest();

/* 
  날씨를 제공하는 서버에 다녀오는(request와 response) 시간이 걸리므로 
  어느 지역이 먼저 처리될지 알 수 없다
  실행할때마다 순서가 다를 수 있다
  호출하는 순서가 처리 순서를 의미하지 않는다

  만약 순서를 보장하고 싶다면?
  
  콜백메소드 반복 작성
  들여쓰기와 arrow function이 반복해서 나옴
  이러면 depth가 깊어짐 -> 소스분석이 어렵다
  
  자바스크립트는 기본적으로 순서대로 처리된다, 동기(서로 맞춘다) <=> 비동기(순서가 맞지 않는것)  
*/

 

<동기 비동기코드 1>

const double = (x) => {
  return x * 2;
};

// 6번 x가 확정되어야 9번 y가 실행될 수 있다(종속적) -> 동기코드(순차적 실행됨)
const x = double(100);
console.log("x: " + x); // x: 200

const y = x;
console.log("y: " + y); // y: 200

 

<동기 비동기코드 2>

const hap = (x, y) => {
  setTimeout(() => {
    return x + y;
  }, 2000);
};

const x = hap(2, 3);
console.log("x: " + x); // x: undefined
const y = x;
console.log("y: " + y); // y: undefined

/* 
2초 대기 후 리턴하기에 undefined, 2초 후에는 리턴 값을 받을 곳이 없음
*/

 

<동기 비동기코드 3>

const hap = (x, y, callback) => {
  setTimeout(() => {
    callback(x + y);
  }, 2000);
};

const x = hap(2, 3, (result) => {
  console.log("result: " + result);
});

const y = x;
console.log("y: " + y);

/* 
y는 undefined이지만, x는 콜백을 썼기에 5

y: undefined
result: 5
*/

댓글