Til Home

2020-09-21-TIL

Fact

  • 오늘은 학습 정리를 했다.

Feelings

  • 고오오오옹부 빨리하자

Findings

  1. 빌드 하는 이유
  2. transpiling 표준 되어 있지 않은 기능들을 현제 설정 사항에 맞게 알아 들을 수 있게 변환 작업
  3. 오류점검
  4. 성능
  5. 테스팅

js 최적화 (min & uglify)

js 코드 품질 검증 (js lint, flow)

js 테스트 수행

css 최적화(min)

css image sprite 자동화 (이미지 하나로 만들어서 좌표값으로 불러오기)

frontend

frontend에서 브라우저 하위 호환성을 보장하는게 힘들다.

js에서 최신 기능을 사용하고 싶지만 브라우저가 호환을 안하면 못쓴다.

https://caniuse.com/?search=array

https://kangax.github.io/compat-table/es6/

transpiler

transpiling 을 통해서

  • 하위브라우저에서도 동작하게 문법을 바꾼다.

    • 최신기능의 문법도 사용가능하다.
    • 제안된 기능(언어에 표준 기능? 으로 등록 되어 있지 않은것들) TC39 Process(https://tc39.es/process-document/) 에 들어가면 1~3단계가 제안된 기능이라고 보면 된다. 이러한 기능들을 쓰다가 그 기능들이 없어질 수도 있다.

polyfill을 통해서 지원하지 않는 native API를 다른 코드로 동작하게 한다.

  • feature detection를 기반으로 동작
  • 걷어내기 쉽다. (브라우저 100% 달성 했을시에 빼고 싶을때 그냥 지우면 코드에 영향 없이 바로 지울 수 있다.)

webpack

  • bundler 이라고 생각하면 편하다.

    • js, css, html 등 종류별 다수 파일들을 종류별 하나의 파일로 묶어 준다.
    • 묶어주는 행동을 bundling이라고 한다. bundling을 할때 babel로 transpiling 과정을 거칠 수 있고 또한 polyfill을 쓴다 하면 설정 되로 지원하지 않는 native API를 지원 할 수 있게 된다.
    • 웹팩 설정에서 Tree Shaking 이라는 옵션을 줄 수 있다.
    • 이것은 안쓰는 모듈들을 지운다.(build 에서 제외)

      • import export로 통해서 감지
      • webpack 4 부턴 compiler 한태 package.json속성을 통하여 파일들이 “pure” 한것들을 전달해서 안전하게 제거가 가능한지 알려준다.
    • 웹팩 설정에서 sourcemap 이라는 옵션을 줄 수 있다
    • 소스맵은 generated/transpiled/minified JavaScript 파일과 하나 이상의 원본 파일 간의 매핑이다. 소스맵의 주요 목적은 디버깅을 지원하는 것이다. 기본적으로 생성된 코드 파일에 오류가 있을 경우 맵에서 원본 파일 위치를 알려줄 수 있다.
    • 사용방법

    • 웹팩 설정에서 SplitChunksPlugin 을 줄 수 있다.
    • 이것은 보통 코드 스플리팅 을 해야 할때 쓰는 것이다.

      • 코드 스플리팅은 간단하게 말해서 많은 코드들을 분리 하는것이다. 예를들어서 한 페이지에 수많은 코드가 있어서 로딩 속도가 느려지면 그때 그때 필요한것을 로딩 할 수 있게 끔 나눠서(빨리 렌더링 될수 있게끔) 만드는게 코드 스플리팅이다.
    • https://www.zerocho.com/category/Webpack/post/58ad4c9d1136440018ba44e7

ES Module

  • 모듈라 프로그래밍은 복잡한 애플리케이션을 모듈단위로 만들어 관계를 짓는 (의존성을 관리하는) 프로그래밍 방법이며,

웹프론트엔드에서도 SPA(single page application)의 등장으로 더욱 필요성이 커졌다.

</div>
<script type="text/javascript" src="//c.011st.com/js/lib/handlebars/handlebars-v4.0.5.min.js"></script>
<script type="text/javascript" src="//c.011st.com/html/inc_header_data.js"></script>
<script type="text/javascript" src="//c.011st.com/js/common/headerCommonJs.js"></script>
<script type="text/javascript" src="//c.011st.com/html/browsing/main/mainAdDsData.js"> </script>
...

이러한 파일들을

</div>

    <script type="module" src="./app.js"></script>
    ...
//handlebars-v4.0.5.min.js

const handlebars = {
  code ...
}

export default handlebars


//inc_header_data.js

const incHeaderData = {
  code ...
}

export default incHeaderData

//app.js


import incHeaderData from '..../inc_header_data.js'
import handlebars from '..../handlebars-v4.0.5.min.js'

  code ...

하나의 루트 파일에서 export import를 하면서 tree 구조로 관리를 할 수 있게 된다.

중요 한 점은

<script type="module" src="./app.js"></script>

에서 type=“module” 로 해줘야한다. 그리고 이 app.js 가 entry point 이다.

이벤트 위임

이벤트 효율적으로 등록 하여 브라우저가 너무 많은 이벤트핸들러를 기억하지 않게 하고, 또한 DOM이 추가/삭제 될때 Event등록을 매번 해줘야 하는 수고를 없앨 수 있다.

예제

<ul>
  <li>
    <img src="https://images-na.,,,,,/513hgbYgL._AC_SY400_.jpg" class="product-image" >	</li>
  <li>
    <img src="https://images-n,,,,,/41HoczB2L._AC_SY400_.jpg" class="product-image" >	</li>
  <li>
    <img src="https://images-na.,,,,51AEisFiL._AC_SY400_.jpg" class="product-image" >  </li>
 <li>
    <img src="https://images-na,,,,/51JVpV3ZL._AC_SY400_.jpg" class="product-image" >
 </li>
</ul>

사진이 있다고 치자. 각 사진에 이벤트를 달기 위해서 보통

const logNode = document.querySelector(".log");
const lists = document.querySelectorAll("ul > li");

for(let i=0,len=lists.length; i < len; i++) {
  lists[i].addEventListener("click", function(evt) {
     logNode.innerHTML = "clicked" + evt.currentTarget.firstElementChild.src;
  });
}

로 4개의 이벤트를 달 수 있다.

그러나 4개 단다는게 너무 비효율 적이다. 그래서 하는게 event bubbling이다.

const ul = document.querySelector("ul");
ul.addEventListener("click",function(evt) {
    if(evt.target.tagName === "IMG") {
      log.innerHTML = "clicked" + evt.target.src;
    } else if (evt.target.tagName === "LI") {
      log.innerHTML = "clicked" + evt.target.firstElementChild.src;
    }
});

target = 현제 누르는것
currentTarget = 이벤트단 최상단 element

이벤트 버블링이란 중첩된 노드에서 아래에 걸 클릭 할때 그것을 감싸고 있는 엘레먼트 중 이벤트 가 등록되어 있다면 실행 시켜주는 과정이다

event delegation 이벤트 위임 => img tag의 이벤트를 위쪽 ul인 부모에게 위임한다 해서 나온 말이다.

불가피 하게 다수 이벤트를 등록 해야 하지만 부모의 이벤트를 실행 시키지 않고 싶다면 stopPropagation을 쓰면 된다.

  <div> 
    <p> hello
      <span>
        hi
      </span>
    </p>
  </div>
document.querySelector("div").click(function(){
  alert("The div element was clicked.");
});

document.querySelector("span").click(function(event){
  event.stopPropagation();
  alert("The span element was clicked.");
});

document.querySelector("p").click(function(){
  alert("The p element was clicked.");
});

hello를 누르면 alert 가 두번 나온다. 처음 “The p element was clicked.” 와 그다음 “The div element was clicked.” 이 나온다.
hi 를 누르게 되면 stopPropagation을 event bubbling을 방지하게 됨으로써 “The span element was clicked.” 만 출력이 된다.

FE-Promise패턴과 fetch API활용

예전엔 page.html을 요청만 가능했었는데, 비동기적으로 데이터를 받아 올 수 있게 됨으로써 json형태의 데이터를 받아올 수 있게 되었다. spa에선 이러한 형식이 중요하다.
데이터통신을 위해서는 XML이나 JSON같은 포맷을 통해서 클라이언트와 서버가 맞춰야 한다.

XML보단 JSON을 표준처럼 쓴다. 클라이언트에서 데이터를 보낼때나 받을때 모두 JSON형태를 사용할 수 있다. https://json.org/example.html

fetch api

비동기 데이터 통신은 XMLHTTPRequest 객체를 사용했다. 그러나 이러한 통신을 사용할때 코드가 길어지면 형태가 콜백헬처럼 된다. 이 이유 뿐만은 아니지만 전체적으로 조금 더 원활하게 사용하기 위해서 나온게 fetchAPI이다.

xhr 코드

let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain/service');

// request state change event
xhr.onreadystatechange = function() {

  // request completed?
  if (xhr.readyState !== 4) return;

  if (xhr.status === 200) {
    // request successful - show response
    console.log(xhr.responseText);
  }
  else {
    // request error
    console.log('HTTP error', xhr.status, xhr.statusText);
  }
};

// start request
xhr.send();

fetchapi 코드

fetch(
    'http://domain/service',
    { method: 'GET' }
  )
  .then( response => response.json() )
  .then( json => console.log(json) )
  .catch( error => console.error('error:', error) );

promise 패턴

비동기처리를 동기적인것처럼 보여주는 패턴이다.

콜백함수(비동기 수행이 끝난 다음에 실행되는)을 비동기 로직에서 분리 되었다. 콜백함수는 then 의 인자로 등록되었다.

let myFirstPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Success!");
  }, 1000);
});

myFirstPromise.then((successMessage) => {
  console.log("Yay! " + successMessage);
});

실행순서 promsie 실행 -> then 실행(콜백함수 promise에 등록) -> 비동기완료시 resolve메서드실행 -> 콜백함수 실행

특징

  • Promise는 비동기로직에서 콜백함수를 분리 할수 있다.
  • thenable syntax 코드 구조를 사용하여 synchronous한것 처럼 보이는 코드를 만들 수 있다.
  • then메서드에 의해 실행되는 콜백함수는 resolve 혹은 reject메서드가 실행된 후에 실행 된다.
  • 위의 기능들로 가독성이 높아진다

활용 방법

  • 병렬 처리

    • const promise1 = Promise.resolve(3);
      const promise2 = 42;
      const promise3 = new Promise((resolve, reject) => {
      setTimeout( () => resolve("foo"), 1000);
      });
      
      Promise.all([promise1, promise2, promise3]).then(function(values) {
      console.log(values);
      });

      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

    • fetchAPI promise all 예제

      function getDatas() {
      const todos = fetch('https://jsonplaceholder.typicode.com/todos')
      .then(response => response.json());
      
      const comments   = fetch('https://jsonplaceholder.typicode.com/comments')
      .then(response => response.json());
      
      Promise.all([todos, comments])
      .then( values =>  {
        const [todoList, commentList]  = values;
        fn(todoList, commentList);
      })
      }

Future Action

  • 막 하는것 보다 효율적인것을 생각하면서 하자 뭐든.