Modern JS Deep Dive 39 - END

MM·2022년 11월 10일

JSDeepDive

목록 보기
6/6
post-thumbnail

📃 39장. DOM

🔹 DOM이란

html문서의 계층적 구조와 정보를 표현하며,
이를 제어할 수 있는 프로퍼티와 메서드를 제공하는 트리형 자료구조!

🔹 노드

🔸 문서 노드

트리 루트노드 ( document )

html문서당 document 객체는 유일하다!

🔸 요소 노드

html요소를 가리키는 객체. 문서의 구조를 표현한다

🔸 어트리뷰트 노드

요소 노드의 자식 노드. 해당 노드를 수정하려면 반드시 해당 요소를 거쳐야 한다

🔸 텍스트 노드

요소 노드의 자식 노드.
요소 사이 공백이나 개행도 텍스트 노드가 된다!

😳 노드 객체는 표준 빌트인 객체가 아니다!

브라우저 환경에서 추가적으로 제공하는 호스트 객체.


🔹 XSS

사용자에게 입력받은 데이터를 innerHTML 프로퍼티에 할당하는 것은 크로스 사이트 스크립팅 공격에 취약하므로 위험하다!

🔸 HTML 새니티제이션

DOMPurify 라이브러리를 사용하여 잠재적 xss위험을 내포한 html마크업 텍스트를 없이 위험을 제거할 수 있다.


🔹 HTML 어트리뷰트

HTML요소의 초기 상태 프로퍼티를 지정하며, 변하지 않는다!
어트리뷰트 노드에서 관리된다.

🔸 DOM 어트리뷰트

즉, HTML에서 수정되는 요소는 모두 이 DOM 어트리뷰트에 반영되는 것!
언제나 최신 상태를 유지한다.
새로고침을 하면 다시 HTML 어트리뷰트의 값으로 되돌아간다.

😏 setAttribute는 초기상태 값을 변경한다

따라서 HTML어트리뷰트 값을 직접 변경한다!




📃 40장. 이벤트

🔹 이벤트 드리븐 프로그래밍

프로그램의 흐름을 이벤트 중심으로 제어하는 프로그래밍 방식

🔸 이벤트 핸들러

이벤트가 발생했을 때 호출될 함수.
이때 브라우저에게 이벤트 핸들러 호출을 위임하는 것을 이벤트 핸들러 등록이라고 한다!

🔸 이벤트 객체(e)

이벤트가 발생하면 이벤트에 관련된 정보를 담고 있는 이벤트 객체가 동적으로 생성된다!
브라우저는 이벤트 핸들러를 호출할 때 생성된 이벤트 객체를 첫번째 인수로 전달한다!

이벤트 객체 공통 프로퍼티 중 쓸만한 것만 모아 보았다!

프로퍼티설명
type이벤트 타입
target이벤트 발생 dom요소
currentTarget이벤트 핸들러가 바인딩된 dom요소
timeStamp이벤트 발생 시간

🔹 이벤트 전파

dom 트리의 dom 요소 노드에서 발생한 이벤트는 dom트리를 통해 전파된다!

🔸 이벤트 전파 단계

  1. 캡처링 단계
    이벤트가 상위(document)에서 하위로 전파
  2. 타깃 단계
    이벤트가 이벤트 타깃에 도달
  3. 버블링 단계
    이벤트가 하위(이벤트 타깃)에서 상위로 전파

👉 이벤트는 dom트리를 통해 전파되는 이벤트 패스에 위치한 모든 dom 요소에서 캐치가 가능하다!

	document.querySelector('p').addEventListener('click', ()=>{..}, true) //버블링 단계에서 캐치
	document.querySelector('p').addEventListener('click', ()=>{..}, true) //캡처링 단계에서 캐치

🔹 이벤트 위임

여러 하위 dom요소에 각각의 이벤트 핸들러를 등록하는 대신, 하나의 상위 dom요소에 이벤트 핸들러를 등록하는 방법!

🔸 dom 요소 기본동작 중단

e.preventDefault();

🔸 이벤트 전파 방지

e.stopPropagation();


🔹 이벤트 핸들러 내부의 this

🔸 이벤트 핸들러 호출시의 인수 this

<button onclick="handleClick(this)">Click me</button>
<script>
  function handleClick(button){
  	console.log(button);//이벤트를 바인딩한 butto
  	console.log(this);	//window
  }
</script>

🔸 이벤트 핸들러 프로퍼티와 addEventListenr 시의 this

<button class="btn" onclick="handleClick(this)">Click me</button>
<script>
  const $button = document.querySelector(".btn");

  $button.onclick = function (e){
    console.log(e.currentTarget); // $button
  	console.log(this);			 // $button
  }

  //단. 이렇게 화살표 함수로 정의된 경우 화살표함수가 자신의 this를 가지지 않으므로
  //상위 스코프의 this를 가져온다.

  $button.onclick=(e)=>{
  	console.log(e.currentTarget); // $button
  	console.log(this);			 // window
  }

  $button.addEventListener("click", functino(e){
	console.log(e.currentTarget); // $button
  	console.log(this);			 // $button              
                           });

</script>

🔸 화살표 함수

👉 단, 화살표 함수의 this는 상위 스코프의 this.




📃 41장. 타이머

🔹 타이머 함수

js엔진은 싱글 스레드이므로, 타이머 함수들은 비동기 처리 방식으로 동작한다!

🔸 디바운스

짧은 시간 간격으로 이벤트가 연속해서 발생할 때..
👉 이벤트 핸들러를 호출하지 않다가, 일정 시간동안 이벤트가 더 이상 발생하지 않으면 그때 한 번만 이벤트 핸들러를 호출!

const debounce = (callback, delay) =>{
  let timeId;
  return event => {
    if(timeId) clearTimeout(timerId)
    timerId = setTimeout(callback, delay, event);
    //새 이벤트가 발생하면, 다시 처음부터 초를 센다..
  };
};

🔸 스로틀

짧은 시간 간격으로 연속해서 이벤트가 발생할 때..
👉 이벤트를 그룹화하여 일정 시간 단위로 이벤트 핸들러가 호출되도록 호출 주기를 만든다!
👉 따라서 delay 시간 간격으로 콜백 함수가 호출된다!

const throttle = (callback, delay) =>{
  let timeId;
  return event => {
    if(timeId) return;
    timerId = setTimeout(()=>{
      callback(event);
      timeId = null;
    }, delay, event);
  };
};



📃 42장. 비동기 프로그래밍

🔹 동기처리와 비동기 처리

js엔진은 단 하나의 실행 컨텍스트 스택을 갖는다.

🔸 블로킹

js엔진은 한번에 하나의 태스크만 실행하는 싱글스레드 방식이므로, 처리에 시간이 걸리는 태스크를 실행하는 경우 다른 한 작업이 중단된다.

👉 이렇게 한 번에 하나씩만 수행할 수 있는 것을 비동기라고 한다!

😌 js의 내장 비동기 함수들

타이머 함수, http 요청, 이벤트 핸들러


🔹 이벤트 루프와 태스크 큐

🔸 이벤트 루프

js의 동시성을 지원하는 브라우저 기능!

콜스택

js의 실행 컨텍스트 스택

객체가 저장되는 메모리 공간.
객체 크기에 따라 메모리 크기를 런타임에 동적할당하므로 구조화되어있지 않다!

태스크 큐

비동기 함수의 콜백함수나 이벤트 핸들러가 일시적으로 보관되는 영역

이벤트 루프

콜 스택에 실행 중인 컨텍스트가 있는가?
태스크 큐에 대기중인 함수가 있는가?
를 확인하여 태스크 큐에서 콜 스택으로 함수를 옮겨 실행하는 루프!

👉 비동기 함수의 콜백 함수는 태스크 큐에 푸시되어 대기하다가, 다른 함수가 모두 종료되면 비로소 콜 스택에 푸시되어 실행된다!




📃 43장. Ajax

AJAX 내 반쪽 아니 완 전 카피~

🔹 Ajax란?

브라우저가 서버에게 비동기 방식으로 데이터를 요청하고,
서버가 데이터를 수신하여 웹페이지를 동적 갱신하는 프로그래밍 방식

🔸 XMLHttpRequest

브라우저 제공하는 web api.
http 비동기 통신을 제공한다.

🔸 전통적인 웹페이지 생명주기

  • 이전 웹페이지와 차이가 없는 부분도 전부 다시 전송받아 불필요한 데이터 통신이 발생한다.
  • 모든 페이지가 변경되어 순간 깜빡 현상이 일어난다
  • 동기 방식이기 때문에 서버 응답이 있을 때까지 다음 처리는 블로킹된다.

👉 ajax는 이러한 전통적인 패러다임에서 벗어나, 변하지 않은 부분은 다시 렌더링하지 않는다!





📃 44장. REST API

🔹 REST란

http를 기반으로 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍처

🔹 REST API의 구성

🔸 자원(URI)

특정 리소스를 식별하는 데 사용되는 고유한 문자열 시퀀스를 말한다!

😆 URI 구조

scheme://user:password@host:port/path?query#fragment

scheme : 사용할 프로토콜을 뜻하며 웹에서는 http 또는 https를 사용
host와 port : 서버 호스트명과 포트번호
path : 서버 경로에 대한 상세 정보
query : 접근할 대상에 전달하는 파라미터
fragment : 서브 리소스 식별 정보

🔸 행위(HTTP 요청 메서드)

클라이언트가 웹 서버에게 사용자 요청의 목적과 종류를 알려줄 때 사용한다.

GET, POST, DELETE...

🔸 표현(페이로드)

전송되는 데이터!

🔹 REST API 설계 원칙

🔸 URI는 리소스를 표현하는 데 집중하라

동사보다는 명사를 사용하여 리소스를 표현한다!

# bad
GET /getTodos/1

# good
GET /todos/1

🔸 행위에 대한 정의는 HTTP 요청 메서드를 통해 진행하라

HTTP 요청 메서드종류목적페이로드
GETindex/retrieve모든/특정 리소스 취득X
POSTcreate리소스 생성O
PUTreplace소스 교체O
PATCHmodify리소스 일부 수정O
DELETEdelete리로스 삭제X



📃 45장.프로미스

🔹 비동기 처리를 위한 콜백 패턴의 단점

🔸 콜백 헬

비동기 함수는 비동기 처리 결과를 외부에 반환할 수도, 상위스코프 변수에 할당할 수도 없다!
👉 따라서 비동기 함수의 처리 결과와 후속 처리는 비동기 함수 내에세서 수행해야 한다.
👉 이것이 반복되면, 비동기 내 비동기 내 비동기 내 비동기함수 사용이 되는데..
👉 이것을 콜백 헬이라고 한다.

🔸 에러 전파

에러가 호출자 방향으로 전파된다!
이렇게 전파된 에러는 catch에서 캐치되지 않는다!


🔹 프로미스

프로미스란, 비동기 처리 상태와 처리 결과를 관리하는 객체를 말한다!

🔸 프로미스 상태

  • pending: 아직 처리x
  • fulfilled: 처리 성공 👉 resolve 함수 호출
  • rejected: 처리 실패 👉 refect 함수 호출

😏 settled 상태란?

fulfilled, rejected 상태와 상관 없이 비동기 처리가 수행된 상태를 말한다!
한번 settled ㄷ상태가 되면 다른 상태로 변화할 수 없다!

🔸 프로미스 후속 처리

//성공
new Provise(resolve=>resolve("fulfilled"))
	.then(v=>conosle.log(v), e=>console.error(e));

//실패
new Provise((_,resolve)=>resolve("fulfilled"))
	.then(v=>conosle.log(v), e=>console.error(e));

👉 then 메서드는 언제나 프로미스를 반환한다!
👉 프로미스가 아닌 값을 반환하면 그 값을 암묵적으로 resolve, reject하여 프로미스를 생성해 반환한다!

🤭 프로미스 후속 처리 메서드

프로미스의 비동기 처리 상태가 변화하면, 후속 처리 메서드에 인수로 전달한 콜백 함수가 호출된다!

then, catch(에러), finally(에러, 성공 상관없이 공통 처리)..


🔹 프로미스 체이닝

프로미스 후속 처리 메서드는 언제나 프로미스를 반환하므로, 연속적으로 사용할 수 있다.

promiseGet(`url`).then(({userId})=> promiseGet(`url/${userId}`)))
				 .then(...)
                 .catch(...)

🔹 프로미스 정적 메서드

🔸 Promise.rolve & Promise.reject

전달받은 값을 resolve or reject하는 프로미스를 생성한다.

const resolvePromise = Promise.resolve([1,2,3]);
resolvePromise.then(console.log); //[1,2,3]

const rejectPromise = Promise.reject(new Error('error'));
rejectPromise.catch(console.log); //error

🔸 Promise.all

여러 개의 비동기처리를 병렬 처리할 때 사용한다.
처리 순서를 보장하며, 하나라도 reject되면 즉시 종료한다.

const promise1=new Promise(resolve=>setTimeout(()=>resolve(1),3000));
const promise2=new Promise(resolve=>setTimeout(()=>resolve(2),2000));
const promise3=new Promise(resolve=>setTimeout(()=>resolve(3),1000));


//Promise.all을 쓰지 않으면 6초 소요
const res=[];
promise1().then(data=>{res.push(data); return promise2();})
          .then(data=>{res.push(data); return promise3();})
		  .then(data=>{res.push(data); console.log(res);})
		  .catch(console.log(error));

//Promise.all을 쓰면 3초 소요
Promise.all([promise1(), promise2(), promise3()])
	   .then(console.log) //1,2,3
	   .catch(console.log(error));

🔸 Promise.race

가장 먼저 fulfilled된 상태의 프로미스 처리결과를 resolve하는 프로미스를 반환한다.

Promise.race([promise1(), promise2(), promise3()]).
	   .then(console.log) //3
	   .catch(console.log);

🔸 Promise.allSettled

프로미스가 모두 settled상태가 되면 처리 결과를 배열로 반환한다.
즉, reject도 반환하는 Promise.all이라고 생각하면 될 듯!


🔹 마이크로태스크 큐

setTimeout(()=>console.log(1),0);

Promise.resolve().then(()=>console.log(2)).then(()=>console.log(3));
//우리의 예상: 1, 2, 3
//실제로는..: 2, 3, 1

🔸 프로미스 후속 처리 메서드 콜백 함수는 마이크로 태스크 큐에 저장된다

태스크 큐의 우선순위 < 마이크로 태스크 큐

마이크로 태스크 큐의 모든 프로미스 후속처리메서드 콜백 함수를 실행하고 나서야
이벤트 루프에서 태스크 큐의 함수가 실행된다!


🔹 fetch

http 요청 전송 기능을 제공하는 클라이언트 사이드 web api

🔸 fetch 함수

[ [ http응답을 나타내는 Response 객체 ] 를 래핑한 Promise 객체 ]를 반환한다!
단, http 에러(404, 500..)는 reject하지 않는다!
👉 대신 Response객체의 ok속성 상태를 false로 해서 return한다!
👉 네트워크 장애, CORS 에러에 의한 경우만 프로미스를 rejec한다!

😏 그런 면에서 axios는...

모든 http 에러를 reject해준다!!

🔸 HTTP 요청 예제

const request = {
	get(url){ return fetch(url);},
  	post(url, payload){
      return fetch(url, {
   						method:"POST",
   						headers: {"content-Type":"application/json"},
        				body: JSON.stringify(payload)
    });},
    patch(url, payload){
      return fetch(url, {
        				method: "PATCH",
        				headers: {"content-Type":"application/json"},
        				body: JSON.stringify(payload)
    });},
    delete(url){ return fetch(url, {method: "DELETE"});
   }
}



📃 46장. 제너레이터와 async/await

🔹 제너레이터란?

코드 블록 실행을 일시중지했다가 필요시점에 다시 재개할 수 있는 특수한 함수!
이러한 제네레이터의 가독성을 좋게 한 것이 async/await이다!

🔸 일반 함수와의 차이점

  • 함수 호출자에게 함수 실행 제어권을 양도할 수 있다.
    👉 즉, 함수 호출자가 함수 실행을 제어할 수 있다!
  • 함수 호출자와 상태를 주고받을 수 있다.
  • 제네레이터 객체를 반환한다.
    👉 제네레이터 함수를 호출하면 함수 코드를 실행하는 것이 아니라 이터러블한 제네레이터 객체를 반환한다!

🔸 제너레이터 함수의 정의

화살표 함수나 생성자 함수로 호출할 수 없다!

function* getDecFunc(){ yield 1; }



📃 47장. 에러 처리

🔹 try, throw, catch, finally

에러가 발생해도 프로그램이 강제종료되지 않는다!

try{
  //실행 코드
  throw new Error("에러발생!"); //catch로 Error 객체 던짐
}.catch(err){
	//실행 코드에서 에러 발생시 catch로 Error객체 전달
}.finally{
  //에러 발생과 상관없이 반드시 한 번 실행
}

🔹 Error 객체

에러 메시지를 인수로 전달하는 것이 가능하다!

🔸 종류

  • Error
  • SyntaxError: 문법 오류
  • ReferenceError: 참조할 수 없는 식별자
  • TypeError: 데이터 타입 오류
  • RangeError: 숫자값 허용 범위 초과
  • URIError: URI가 필요한 곳에 부적절한 인수 전달
  • EvalError: eval함수에서 발생

🔹 에러의 전파

👉 throw된 에러를 캐치되지 않으면 호출자 방향으로 전파된다!
👉 error를 아무도 캐치하지 않으면 프로그램은 강제 종료된다!

🥺 비동기 함수 setTimeout나 프로미스 후속처리메서드는 호출자가 없어요

이러한 함수들의 실행 컨텍스트는 콜스택의 가장 하부에 존재하게 되기 떄문에, 에러를 전파할 호출자가 존재하지 않는다!




📃 48장. 모듈

🔹 모듈의 일반적 의미

애플리케이션을 구성하는 개별적 요소로써 재사용 가능한 코드 조각을 의미한다!

🔸 모듈의 조건

  • 모듈은 자신만의 파일(모듈) 스코프를 가져야 한다.
  • 모듈의 자산은 기본적으로 캡슐화되어야 한다.
  • 모듈은 개별적 존재로써 애플리케이션과 분리되어 존재해야 한다.
  • 모듈은 재사용되어야 의미가 있다.

🔸 export

모듈은 공개가 필요한 자산에 한정하여 명시적으로 선택적 공개가 가능하다. 이것이 export!

🔸 import

모듈 사용자는 모듈이 공개한 자산을 자신의 스코프로 가져와 사용할 수 있다. 이것이 import!

😧 초반에는 말입니다

js에는 모듈이 존재하지 않았다!
대신 script 태그로 모든 파일이 하나의 js에 있는 것처럼 동작시킬 수는 있었다.
이는 하나의 전역을 공유하여 변수 중복 등의 문제를 야기했다.


🔹 ES6모듈(ESM)

import * as lib from "./lib.js";

console.log(lib.pi);
profile
중요한 건 꺾여도 그냥 하는 마음

0개의 댓글