[인프런] 맛집지도 만들기 (8)
비전공자를 위한 풀스택 맛집지도 만들기 프로젝트!: Front, Back-end 그리고 배포까지
비전공자를 위한 풀스택 맛집지도 만들기 프로젝트!: Front, Back-end 그리고 배포까지 - 인프런 | 강
내가 좋아하는 유튜버의 맛집지도를 만들면서 프론트엔드, 백엔드, 카카오맵 API 사용법, 배포까지 한번에 배울 수 있는 풀스택 맛집지도 강의입니다., - 강의 소개 | 인프런...
www.inflearn.com
※ 해당 링크 강의 내용을 바탕으로 작성된 포스팅입니다.
JS DOM과 비동기처리
JS로 HTML과 CSS를 컨트롤하는 방법
JS에서 HTML 요소 선택 방법
메서드 | 설명 |
document.querySelector(선택자) | 해당 선택자로 선택되는 요소 선택. |
document.querySelectorAll(선택자) | 해당 선택자로 선택되는 요소 모두 선택(배열). |
document.getElementsByTagName(태그이름) | 해당 태그 이름의 요소 모두 선택(배열). |
document.getElementById(아이디) | 해당 아이디 요소 선택. |
document.getElementsByClassName(클래스이름) | 해당 클래스에 속한 요소 모두 선택(배열). |
html
<!DOCTYPE html>
<html lang="en">
<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>
<div></div>
<div id="hi"></div>
<div class="welcome"></div>
<script src="dom.js"></script>
</body>
</html>
js
// 엘리먼트 선택 예제
console.log(document.querySelector("div.welcome"));
console.log(document.querySelectorAll("div"));
console.log(document.getElementsByTagName("div"));
console.log(document.getElementById("hi"));
console.log(document.getElementsByClassName("welcome"));
HTMLCollection(동적)과 NodeList(정적)의 차이
HTMLCollection vs NodeList - 한현상 블로그
DOM을 조작할 때 접하게 되는 유사배열들이다. getElementsByClassName()과 querySelectorAll()이 거의 같은 것이라 인식하고 있는 사람들이 있을 것이다. 결정적으로 다른 부분이 있다. 바로 그 결과가 각각 H
tillog.netlify.app
JS에서 HTML 요소 Read, Update를 위한 속성
이름 | 설명 |
innerText = "content" | 요소 내부 컨텐츠 조회, 수정. 들어온 값을 Text로 인식. |
innerHTML = "html" | 요소 내부 엘리먼트 전체 조회, 수정. 들어온 값을 HTML로 인식. |
style.property = "css property value" | 요소 스타일 조회, 수정 |
divTag.innerText = "<h1>안녕하세요.</h1>"
divTag.innerHTML = "<h1>안녕하세요.</h1>"
html
<!DOCTYPE html>
<html lang="en">
<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>
<div>안녕</div>
<script src="dom.js"></script>
</body>
</html>
js
// <div> 가져오기
const divTag = document.querySelector("div");
console.log(divTag);
// color에 접근해 색을 red로 바꾼다.
divTag.style.color = "red";
JS에서 중첩된 태그 선택
관계를 기반으로 요소 선택.
이름 | 설명 |
parentElement | 부모 태그 |
children | 자식 태그 리스트 |
nextElementSibling | 인접 형제 태그 |
html
<!DOCTYPE html>
<html lang="en">
<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>
<div class="container">
<div class="inner first">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
<div class="inner second">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
</div>
<script src="dom.js"></script>
</body>
</html>
js
const container = document.querySelector(".container");
console.log(container);
// 부모 태그
console.log(container.parentElement);
// 자식 태그
console.log(container.children);
// 형제 태그
console.log(container.nextElementSibling);
JS에서 태그 추가
- document.createElement() : 태그 만들기
- document.createTextNode(): text 노드 만들기
- element.appendChild(): 자식 노드 추가하기
- element.setAttribute(attribute, value): 요소에 속성 추가하기
정석적인 방법
html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="container">
<div class="inner"></div>
</div>
<script src="dom.js"></script>
</body>
</html>
js
// div.inner를 선택
let inner = document.querySelector(".inner");
// <div>태그 생성
let element = document.createElement("div");
// text 노드 hello 생성
let hello = document.createTextNode("hello");
// <div>hello</div>로 만들기
element.appendChild(hello);
// div.inner에 element 추가
inner.appendChild(element);
간편한 방법(ES6 템플릿 리터널)
문자열 안에 변수, 표현식 등을 넣어 사용 가능. 백틱(``)과 $와 중괄호(${})를 사용.
비어있는 div 태그 생성.
html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="dom.js"></script>
</body>
</html>
네트워크 요청을 통해 서버에서 상품 정보를 받아왔다고 가정.
div#app 태그에 div.item을 넣는다.
js
const prouductData = { title: "감자칩", weight: 300 };
// div#app 태그 선택
const app = document.querySelector("div#app");
// 템플릿 리터럴과 innerHTML 속성을 사용
app.innerHTML = `<div class="item">상품명 : ${productsData.title}, 무게 ${productsData.weight}g</div>`;
JS Event 처리
이벤트는 웹 브라우저가 인식하는 사건으로, 키보드를 누르거나, 마우스를 클릭하는 것이 예시.
이벤트 타입
발생한 이벤트의 종류를 나타내는 문자열.
이름 | 설명 |
load | 웹 브라우저 상에서 HTML, CSS가 모두 로드 완료되었을 때 발생 |
keydown, keyup | 키를 누를 때, 키에서 손을 뗐을 때 발생 |
change | 변동이 있을 때 발생(input) |
click | 클릭했을 때 발생 |
focus | 커서 포커스를 얻을 때 발생(input) |
이벤트 등록 방법
1. 프로퍼티로 등록하는 방법(잘 사용하지 않음)
html
<!DOCTYPE html>
<html lang="en">
<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>
<p onclick="alert('문자열을 클릭했어요!')">이 문자열을 클릭해 보세요!</p>
<script src="event.js"></script>
</body>
</html>
2. 메소드에 이벤트 리스너를 전달하는 방법
html
<!DOCTYPE html>
<html lang="en">
<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="btn">클릭</button>
<p id="text"></p>
<script src="event.js"></script>
</body>
</html>
js
const showBtn = document.getElementById("btn"); // 아이디가 "btn"인 요소를 선택함.
//element.addEventListener(이벤트 타입, 이벤트 핸들러, 이벤트 전파방식)
showBtn.addEventListener("click", function () {
document.getElementById("text").innerHTML = "짜잔~!! 텍스트가 나타났어요!!";
}); // 선택한 요소에 click 이벤트 리스너를 등록함.
const showBtn = document.getElementById("btn");
showBtn.addEventListener("click", eventHandler); //eventHandler()로 쓰면 함수가 바로 실행된다.
function eventHandler() {
document.getElementById("text").innerHTML = "짜잔~!! 텍스트가 나타났어요!!";
} //이렇게 사용해도 됨
이벤트 객체
이벤트가 일어났을 때의 정보를 자세하게 저장.
js
function eventHandler(event) { //이벤트 객체가 전달됨
console.log(event);
}
JS 헬구간! 비동기 처리
동기/비동기
- 동기(synchronous): 한 번에 한 가지 일만 처리. 실행이 끝난 후 다음 코드로 넘어간다.
- 비동기(asynchronous): 동시에 여러 가지 일 처리. 완료 여부와 관계없이 다름 코드로 넘어간다.
실행이 오래 걸리는 코드가 있을 경우 비동기로 실행하는 것이 효율적.
비동기 동작 예시
setTimeout(callback, ms)
setTimeout(() => {
console.log(1);
}, 2000) //2초 뒤에 전달된 함수를 실행.
console.log('1등!');
setTimeout(function() {
console.log('2등!');
}, 2000); // 2초 후 등장
setTimeout(function() {
console.log('3등!');
}, 2000); // 2초 후 등장
이와 같이 네트워크 요청(API)도 비동기적으로 이루어진다.
실행 순서가 중요한 상황이면 문제가 발생할 수 있다.
코드의 실행 순서를 보장받아야만 하는 상황에서는 비동기적으로 처리되는 함수를 동기적으로 바꿔 준다(동기화 시킨다, 비동기 처리).
JS 비동기 처리
- 콜백 함수
- promise 객체
- async await
콜백 함수 내부에 넣기
함수가 많아지면 콜백 지옥... 코드가 읽기 어려워질 수 있다.
console.log('1등!');
setTimeout(function() {
console.log('2등!');
setTimeout(function() {
console.log('3등!');
}, 2000); //콜백함수 안에 넣어 준다
}, 2000);
promise 객체
ES6부터 등장.
promise는 3가지의 상태값이 존재.
- 대기(pending): promise 객체를 새로 생성한 상태. 대기.
- 이행(fulfiled): resolove 가 실행된 상태. 비동기 로직이 완료된 상태.
- 거부(rejected): reject가 실행된 상태. 비동기 로직에서 에러가 난 경우.
// const 변수명 = new Promise((resolve, reject) => {
// resolve("good"); //then 호출
// reject("fail"); //catch 호출
// });
// 변수명.then((res) => console.log(res)).catch((err) => console.log(err));
resolve가 호출 된다 → 이행상태 → promise 객체의 then() 메서드 호출
reject가 호출된다 → 거부 상태 → promise 객체의 catch() 메서드 호출
const helloPromise = new Promise((resolve, reject) => {
// 생성 자체는 pending
let isSuccess = true;
if (!isSuccess) {
reject(false); // catch 호출
return;
}
console.log("1등");
setTimeout(() => {
resolve(); // then 호출
}, 2000);
});
helloPromise
.then((res) => {
console.log("2등");
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), 2000); //아래 then 호출
});
})
.then((res) => {
console.log("3등");
})
.catch((err) => { //에러 처리
console.log(err);
});
async await
promise를 기반으로 동작. promise에서 resolve로 넘어온 값이 await 구문에 반환. 사람이 읽기 쉽다.
// async fuction 함수명(){
// await 비동기처리함수();
// }
async function asyncFunction() {
console.log(1);
const result = await getResult(); //getResult를 비동기 처리
console.log(result);
}
function getResult() { //Promise 반환
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2); //2가 result에 전달.
}, 2000); //2초 뒤에 resolve 실행.
});
}
asyncFunction();
async function asyncFunction() { //메인
console.log("1등"); //실행 1
await second(); //Promise를 반환하는 함수
await third(); //Promise를 반환하는 함수
}
function second() { //실행 2
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("2등");
resolve(); //await가 작업을 끝냈다고 인식. 다음 코드로 넘어감.
}, 2000);
});
}
function third() { //실행 3
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("3등");
resolve();
}, 2000);
});
}
asyncFunction();
클라이언트 - 서버 통신간에서 비동기 처리 기법이 중요.
try-catch
async/await 구문 에러를 처리하기 위해서는 try-catch 이해가 필요.
try-catch는 비동기 처리 이외에도 일반적인 에러까지도 잡아낸다.
try {
소스코드; //에러가 나면
} catch (err) { //여기로 넘어감
console.log(err);
}
async function asyncFunction() {
try {
console.log(1);
const result = await getResult();
console.log(result);
console.log(3);
} catch (err) { //에러 발생 시 여기로
console.log(err);
}
}
function getResult() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error("에러발생 예시")); //일부로 에러 발생
}, 500);
});
}
asyncFunction();