Search

JavaScript4

38. 브라우저 렌더링 과정

쭉 읽다가 script 태그를 만나면 DOM 생성을 일시 중단함.
script 태그의 위치에 따라 HTML 파싱이 블로킹 되어 DOM 생성이 지연될 수 있다.
즉 DOM 생성 이전의 스크립트 태그에서 DOM을 변경하는 경우 이미 DOM이 생성되어있어야한다.
→ body 요소의 가장 아래에 자바스크립트를 위치시키는 것이 좋다.
자바스크립트 파일 로드와 HTML 파싱은 동기적으로 실행되는데, 비동기적으로 실행하고 싶다면
async 어트리뷰트 및 defer 어트리뷰트가 있어야한다.

async 어트리뷰트

→ HTML파싱과 자바스크립트 파일의 로드가 비동기적으로 동시에 진행
→ 자바스크립트 실행은, 자바스크립트 파싱 직후에 진행
→ 자바스크립트 실행 때는 HTML 파싱이 중단됨

defer 어트리뷰트

→ HTML 파싱과 자바스크립트 파일의 로드가 비동기적으로 진행
→ 자바스크립트의 파싱과 실행은 HTML 파싱이 완료된 직후.

39.DOM

트리 구조, 상속 구조, 각 트리의 노드
상위 노드 → 문서 노드, 요소 노드, 어트리뷰트 노드, 텍스트 노드
document.getElementById
document.getElementsByTagName → DOM 컬렉션 객체인 HTMLCollection 객체를 반환
getElementsByClassName → 컬렉션 반환
querySelector → Css 선택자를 만족시키는 하나의 요소 노드를 반환(첫번째)
querySelectorAll → 만족시키는 모든 요소 노드를 탐새갛여 반환

HTMLCollection 과 NodeList

HtmlCollectIon → 살아 있는 객체
→ HTMLCollection을 이용해서 함수를 실행하는 도중에 HTMLCollection이 실시간으로 변경된다.
NodeList → 정적 객체다
→ childNodes 프로퍼티가 반환하는 NodeList는 live 객체이다.
가장 좋은 방법은 그냥 배열로 변환하여 사용하는 것

공백 텍스트 노드

→ 행바꿈 등이 다 텍스트 노드를 생성한다.

자식 노드 탐색

childNodes : NodeList를 담아 반환. 자식 노드를 모두 담아 반환. 텍스트 노드도 포함되어있을 수도
children : 자식 노드 중 요소 노드만 모두 탐색해서 HTMLCollection에 담아 반환. 텍스트 노드 포함 X
firstChild: 첫번째 자식노드. 텍스트 노드이거나 요소 노드
lastChild: 마지막 자식 노드. 텍스트 노드이거나 요소 노드
firstElementChild: 첫번째 자식 요소 노드
lastElementChild: 마지막 자식 요소 노드

요소 노드의 텍스트 조작

nodeValue

실제로 노드의 값을 바꾸는 것

textContent

노드의 컨텐츠 영역 내의 텍스트를 모두 반환
이 때 HTML 마크업은 무시된다.

DOM 조작

innerHTML

요소 노드의 콘텐츠 영역 내에 포함된 모든 HTML 마크업을 문자열로 반환

40. 이벤트

이벤트 핸들러 등록

이벤트 핸들러 어트리뷰트 방식

함수 호출문으로 할당한다.
<body> <button onclick = "sayHi('Lee')"> Click me!</button> <script> function sayHi(name){ console.log(`Hi! ${name}.`); } </script> </body>
JavaScript
복사
이렇게 하면 사실 암묵적으로 함수를 생성하고, 이벤트 핸들러 어트리뷰트 이름과 동일한 onclick이벤트 핸들러 프로퍼티에 할당한다.
function onclick(event){ sayHi('Lee'); }
JavaScript
복사

이벤트 핸들러 프로퍼티 방식

const button = document.querySelector('button'); button.onclick = function(){ console.log('button click'); };
JavaScript
복사
event target → button
event type → onclick
event handler → function
⇒ 이벤트 핸들러 프로퍼티에 하나의 이벤트 핸들러만 바인딩할 수 있다.

addEventlistener

이벤트 핸들러 프로퍼티 방식은 이벤트 핸들러 프로퍼티에 이벤트 핸들러를 바인딩하지만, addEventListener는 이벤트 핸들러를 인수로 전달한다.
여러개의 이벤트 핸들러를 전달가능하다.

이벤트 핸들러 제거

→ 등록할 때와 똑같은 형식의 인수를 전달해야함
→ 무명 함수를 이벤트 핸들러로 등록한 경우, 참조를 못찾기 때문에 제거 못함
이벤트 핸들러 프로퍼티 방식으로 등록한 거는 이런식으로 제거 못한다. 그냥 null할당해야함.

이벤트

target → 이벤트를 발생시킨 DOM 요소
currentTarget → 이벤트 핸들러가 바인딩된 DOM 요소
이벤트 핸들러 어트리뷰트 방식 → 함수 내부의 this는 전역 객체를 가리킨다.
이벤트 핸들러 프로퍼티 및 addEvnetListener 방식 → 이벤트를 바인딩한 DOM 요소

이벤트 핸들러에 인수 전달

1.
이벤트 핸들러 내부에서 함수를 호출하면서 인수를 전달할 수 있다.
const checkUserNameLength = min =>{ $msg.textcontext = $input.value.length < min ? `이름은 ${min}자 이상 입력해주세요` : ''; }; $input.onblur = () => { checkUserNameLength(MIN_USER_NAME_LENGTH); }
JavaScript
복사
2.
이벤트 핸들러를 반환하는 함수를 호출하면서 인수를 전달할 수도 있다.
const checkUserNameLength = min => e => { $msg.textContent = $input.value.length < min ? `이름은 ${min}자 이상 입력해주세요`:''; }; input.onblur = checkUserNameLength(MIN_USER_NAME_LENGTH);
JavaScript
복사

42.비동기 프로그래밍

그냥 비동기로 한다.
비동기로 진행되는 것들은 브라우저가
동기로 진행되는 것들은 자바스크립트 엔진이 실행됨.

43. Ajax

직렬화: 클라이언트가 서버로 객체를 전송하려면, 객체를 문자열화 하는데, 이 작업을 직렬화라고 함.
역직렬화: Json.parse는 문자열을 배열 객체로 변환한다.

45. 프로미스

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

동기 함수를 호출하면 함수 내부의 비동기로 동작하는 코드가 완료되지 않았다해도 기다리지 않고, 즉시 종료된다.
비동기 함수 내부의 비동기로 동작하는 코드는 비동기 함수가 종료된 이후에 완료된다. 따라서 비동기 함수 내부의 비동기로 동작하는 코드에서 처리 결과를 외부로 반환하거나 상위 스코프의 변수에 할당하면 기대한 대로 동작하지 않는다.
const get = url => { const xhr = new XMLHttpRequest(); xhr.open('GET',url); xhr.send(); xhr.onload = () => { if(xhr.status == 200){ return JSON.parse(xhr.response); } console.error(`${xhr.status} ${xhr.statusText}`); }; }; const response = get('https:/jsonplaceholder.typicode.com/posts/1'); console.log(response); // undefined
JavaScript
복사
get함수에 명시적인 반환문이 없으므로 get함수는 undefined를 반환한다.
이벤트 핸들러 프로퍼티에 바인딩한 반환문은 get함수의 반환문이 아니다.
unload 이벤트 핸들러는 get함수가 호출하지 않기 때문에, 반환값을 캐치할 수가 없다.
let todos; const get = url => { const xhr = new XMLHttpRequest(); xhr.open('GET',url); xhr.send(); xhr.onload = () => { if(xhr.status == 200){ todos = JSON.parse(xhr.response); } console.error(`${xhr.status} ${xhr.statusText}`); }; }; get('https:/jsonplaceholder.typicode.com/posts/1'); console.log(todos); // undefined
JavaScript
복사
get함수가 종료하면 실행 컨텍스트가 팝되고, 곧바로 console.log가 호출됨.
서버로부터 응답이 도착하면 xhr객체에서 load 이벤트가 발생하는데, 이 때 이벤트 핸들러가 즉시 실행되는 것이 아니라. 일단 테스트 큐에 저장되어 대기하다가, 콜 스택이 비면 이벤트 루프에 의해 콜 스택으로 푸시되어 실행된다.
→ 처리 결과에 대한 후속 처리는 비동기 함수 내부에서 수행해야한다.
→ 비동기 함수에 비동기 처리 결과에 대한 후속 처리를 수행하는 콜백함수를 전달하는 것이 일반적이다.
const get = (url, successCallback, failureCallback) => { const xhr = new XMLHttpRequest(); xhr.open('GET',url); xhr.send(); xhr.onload = () => { if(xhr.status == 200){ successCallback(Json.parse(xhr.response)); }else{ failureCallback(xhr.status); } }; }; get('https:/jsonplaceholder.typicode.com/posts/1'); console.log(todos); // undefined
JavaScript
복사
콜백 함수를 통해 비동기 처리 결과에 대한 후속 처리를 수행하는 비동기 함수가 비동기 처리 결과를 가지고 또 다시 비동기 함수를 호출해야한다면 콜백 함수 호출이 중첩되어 복잡도가 높아진다 → 콜백 헬

프로미스의 생성

프로미스 생성자 함수는 비동기 처리를 수행할 콜백 함수를 인수로 전달받는다.
프로미스는 비동기 처리가 어떻게 진행되고 있는지를 나타내는 상태 정보를 갖는다
pending: 아직 수행되지 않은 상태
fulfilled: 수행된 상태(성공) → resolve함수 호출
rejected: 수행된 상태(실패) → reject 함수 호출
프로미스 상태는 resolve 또는 reject함수를 호출하는 것으로 결정된다.
프로미스는 비동기 처리 상태와 처리 결과를 관리하는 객체

후속 처리 메서드

후속 처리 메서드에 인수로 전달한 콜백함수가 선택적으로 호출된다.
then, catch, finally

then

두 개의 콜백함수를 인수로 전달받음
첫번째는 성공이 되면 호출됨. 두 번째는 실패가 되면 호출됨.
new Promise(resolve => resolve('fulfilled')) .then(v=>console.log(v), e => console.log(e));
JavaScript
복사
then 메서드는 언제나 프로미스를 반환한다.

catch

한개의 콜백함수. rejected 상태인 경우만 호출된다.

finally

fulfilled 또는 rejected 와 상관없이 무조건 한 번 호출된다.
const promiseGet = url => { return new Promise((resolve,reject){ const xhr = new XMLHttpRequest(); xhr.open(GET,url); xhr.send(); xhr.onload = (){ if(xhr.status == 200) { resolve(JSON.parse(xhr.response)); }else { reject(new Error(xhr.status)); } } }); }; promiseGet(’https://jsonplaceholder.typicode.com/posts/1) .then(res ⇒ console.log(res)) .catch(err ⇒ console.log(err)) .finally(()⇒ console.log(’Bye!));
JavaScript
복사

프로미스의 에러처리

then 메서드 내부에서 일어난 에러까지 처리하기 위해서 catch함수를 쓰는 것이 좋다.
const url = 'https://jsonplaceholder.typicode.com'; promiseGet(`${url}/posts/1`) .then({userId})=> promiseGet(`${url}/users/${userId}`)) .then(userInfo => console.log(userInfo)) .catch(userInfo => console.log(userInfo))
JavaScript
복사

fetch

fetch함수에는 url,메서드, 요청헤더, 페이로드 등을 설정한 객체를 전달함
const promise = fetch(url,[,options])
fetch 함수는 response 객체를 래핑한 promise 객체를 반환한다.
fetch함수가 반환하는 프로미스는 기본적으로 HTTP 에러가 발생해도 에러를 reject하지 않고, 불리언 타입의 ok상태를 false로 설정한 Response 객체를 resolve한다. 요청이 완료되지 못한 경우에만 reject한다.
fetch(wrongUrl) .then(response => { if(!response.ok) throw new Error(response.statusText); return response.json(); }) .then(todo => console.log(todo)) .catch(err => console.log(err));
JavaScript
복사

46.제너레이터와 async,await

async/await

async/await를 사용하면 프로미스의 then/catch/finally 후속 처리 메서드에 콜백 함수를 전달해서 비동기 처리 결과를 후속 처리할 필요 없이 동기 처리처럼 프로미스를 사용할 수 있다. 프로미스의 후속 처리 메서드 없이 마치 동기 처리처럼 프로미스가 처리 결과를 반환하도록 구현할 수 있다.
async function fetchTodo(){ const url = ‘https://jsonplaceholder.typicode.com/todos/1; const response = await fetch(url); const todo = await response.json(); console.log(todo); }
JavaScript
복사

async 함수

await 키워드는 반드시 async 함수 내부에서 사용해야한다.
async 함수는 async 키워드를 사용해 정의하며 언제나 프로미스를 반환

await 키워드

await 키워드는 프로미스가 settled 상태가 될때까지 대기하다가 settle 상태가 되면 프로미스가 resolve한 처리 결과를 반환한다.
await 키워드는 반드시 프로미스 앞에서 사용해야함.
다음 실행을 일시 중지시켰다가 프로미스가 settled 상태가 되면 다시 재개함
→ try catch 문을 사용할 수 있다.