console.log('1');
setTimeout(function() {
console.log('2');
}, 1000);
console.log('3');
setTimeout(function() {
console.log('2');
}, 1000);
//동일한 의미
setTimeout(() => console.log('2'), 1000);
function printImmediately(print) {
print();
}
console.log('1');
setTimeout(() => console.log('2'), 1000);
console.log('3');
printImmediately(() => console.log('hello'));
출력순서
1 - 3 - hello - 2
function printImmediately(print) {
print();
}
function printWithDelay(print, timeout) {
setTimeout(print, timeout);
}
console.log('1'); //동기
setTimeout(() => console.log('2'), 1000); //비동기
console.log('3'); // 동기
printImmediately(() => console.log('hello')); //동기
printWithDelay(() => console.log('async callback'), 2000); //비동기
출력순서
1 - 3 - hello - 2 - async callback
콜백지옥 EXAMPLE
function delay(sec, callback) {
setTimeout(() => {
callback(new Date().toISOString());
}, sec * 500);
}
delay(1, (result) => {
console.log(1, result);
delay(1, (result) => {
console.log(1, (result) => {
delay(1, (result) => {
console.log(1, result);
});
});
});
});
⇒ 그러므로 가독성이 상당히 좋지 못한 코드가 되어버림 / 그래서 PROMISE의 개념 등장!
const promise = new Promise(function(resolve, reject) {
if (성공이면) {
resolve(성공값);
} else {
reject(실패메세지);
}
});
resolve와 reject를 받게 되는 콜백을 남기게 됨
포인트 2가지 : 1) STATE와 2) PRODUCER, CONSUMER
- STATE : 프로세스가 기능 수행중인지 성공했는지 실패했는지
PRODUCER VS CONSUMER : 데이터를 제공하는 API와 제공된 데이터를 사용하는 API
Producer : promise는 executor라는 콜백함수 전달, executor가 resolve와 reject를 받음
Consumer : then, catch, finally를 이용해서 데이터 받아옴
resolve : 할 일을 다 하였을 때 호출하는 것 (기능을 정상적으로 수행하여 데이터 전달)
reject : 할 일을 하다가 에러가 났을 때 호출하는 것
function delay(sec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(new Date().toISOString());
}, sec * 500);
});
}
delayP(1).then((result) => {
console.log(1, result);
return delayP(1);
}).then((result) => {
console.log(2, result);
return delayP(1);
}).then((result) => {
console.log(3, result);
return delayP(1);
});
const promise = new Promise((resolve, reject) => {
console.log("doing something");
setTimeout(() => {
resolve("sojeong"); //성공적으로 기능 수행하면 resolve라는 콜백함수 실행
reject(new Error("no network")); //성공적으로 받아오거나 데이터 resolve를 통해 전달
}, 2000);
});
promise
.then((value) => { //원하는 기능 수행하는 callback 함수
console.log(value);
})
.catch((error) => { //에러를 핸들링 하려면 catch 사용, 에러발생시 처리방법 콜백함수 등록
console.log(error);
})
.finally(() => {
console.log("finally"); //promise의 성공과 실패상관없이 호출
});
비동기의 🌸이자 하이라이트라고 불리는 async/await
새로운 것이 아닌 Promise에 조금 더 간편한 API를 제공함
→ class가 프로토타임을 베이스로 하는 것과 같이
깔끔하게 프로미스를 사용하게 하는 방법의 일종
단, 프로미스에서 async/await 으로 100% 변환해야한다 x
->프로미스 유지
promise의 단점을 보완하기 위해.
즉, .catch
로 에러를 잡을 때 , 정확히 어디서 발생했는지 알아내기 어렵..
async
를 넣어주고await
을 넣어주면 됨.async
function fetchUser() {
return new Promise((resolve, reject) => {
resolve ('shhhak');
});
}
const user = fetchUser();
user.then(console.log);
console.log(user);
<promise만> 예시...
async function fetchUser() {
return 'shhhak';
}
const user = fetchUser();
user.then(console.log);
console.log(user);
<async 사용> 예시...
💡 번거롭게 Promise를 쓰지 않아도 자동적으로 함수 안에 있는 Promise 블록들이 프로미스로 변환되어진다.await
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function process() {
console.log('안녕하세요!');
await sleep(1000); // 1초쉬고
console.log('반갑습니다!');
}
process();
// "안녕하세요"
// "반갑습니다"
👆처럼
해당 프로미스가 끝날 때까지 기다렸다가 다음 작업이 가능하다.
Next!
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getmung() {
await delay(2000);
return 'mung';
}
async function getwal() {
await delay(2000);
return 'wal';
}
function mungwal() {
return getmung().then(mung => {
return getwal().then(wal => '${mung} + ${wal}');
});
}
mungwal().then(console.log);
<Promise로 합체!(?)>
콜백지옥이 떠오른다.!!
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getmung() {
await delay(2000);
return 'mung';
}
async function getwal() {
await delay(2000);
return 'wal';
}
async function mungwal() {
const mung = await getmung();
const wal = await getwal();
return '${mung} + $(wal)';
}
mungwal().then(console.log);
<async를 써보자>
return
도 편하게 사용 ㄱㄴ💦주의: await 단독으로 사용은 불가
→ async가 있는 함수 안에서만 사용 가능
async 함수에서 에러를 발생 시킬때에는 throw
를 사용하고, 에러를 잡아낼 때에는 try/catch
문을 사용한다.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function makeError() {
await sleep(1000);
const error = new Error();
throw error;
}
async function process() {
try {
await makeError();
} catch (e) {
console.error(e);
}
}
process();
await sleep()이 부분을 비우면 바로 실행
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const getDog = async () => {
await sleep(1000);
return '멍멍이';
};
const getRabbit = async () => {
await sleep(500);
return '토끼';
};
const getTurtle = async () => {
await sleep(3000);
return '거북이';
};
async function process() {
const dog = await getDog();
console.log(dog);
const rabbit = await getRabbit();
console.log(rabbit);
const turtle = await getTurtle();
console.log(turtle);
}
process();
getDog 는 1초, getRabbit 은 0.5초, getTurtle 은 3초가 걸리고 . 총 4.5초
동시에 작업을 시작하고 싶다면, 다음과 같이 Promise.all
을 사용
async function process() {
const results = await Promise.all([getDog(), getRabbit(), getTurtle()]);
console.log(results);
}
만약에 여기서 배열 비구조화 할당 문법을 사용한다면 각 결과값을 따로 따로 추출해서 조회 할 수 있음
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const getDog = async () => {
await sleep(1000);
return '멍멍이';
};
const getRabbit = async () => {
await sleep(500);
return '토끼';
};
const getTurtle = async () => {
await sleep(3000);
return '거북이';
};
async function process() {
const [dog, rabbit, turtle] = await Promise.all([
getDog(),
getRabbit(),
getTurtle()
]);
console.log(dog);
console.log(rabbit);
console.log(turtle);
}
process();
Promise.all
를 사용 할 때에는, 등록한 프로미스 중 하나라도 실패하면, 모든게 실패 한 것으로 간주함.
이번에는Promise.race
라는 것에 대해서 알아봅시다. 이 함수는 Promise.all
과 달리, 여러개의 프로미스를 등록해서 실행했을 때 가장 빨리 끝난 것 하나만의 결과값을 가져
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const getDog = async () => {
await sleep(1000);
return '멍멍이';
};
const getRabbit = async () => {
await sleep(500);
return '토끼';
};
const getTurtle = async () => {
await sleep(3000);
return '거북이';
};
async function process() {
const first = await Promise.race([
getDog(),
getRabbit(),
getTurtle()
]);
console.log(first);
}
process(); // 토끼
시작 전 알아야 할 점
Vanilla JavaScript란?
→ 별도의 라이브러리/프레임워크를 사용하지 않는 형태
DOM이란?
→ 각 태그에 대한 정보를 지니고 있는 JavaScript 객체
TMI : JS는 95%가 객체로 이루어짐
사용자의 인터랙션 (상호작용)에 따라 동적으로 UI를 업데이트하고 싶다면, JavaScript를 연동해 주어야 한다.
보통 인터랙션이 많은 경우에는 Vanilla JavaScript 를 사용해서 하기에는 코드의 양도 많아지고 코드 관리도 어려운 편이라 보통 React, Vue, Angular 등의 도구를 사용한다.
👊🏻 start
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<h2 id="number">0</h2> // id 하나
<div>
<button id="increase">+1</button> // id 둘
<button id="decrease">-1</button> // id 셋
</div>
<script src="src/index.js"></script> // **<-** 요 부분
</body>
</html>
이처럼 id
값을 설정해주면 JavaScript에서 쉽게 해당 DOM을 선택할 수 있다.
const number = document.getElementById("number");
const increase = document.getElementById("increase");
const decrease = document.getElementById("decrease");
console.log(number);
console.log(increase);
console.log(decrease);
요 getElementById
로 DOM 선택 완완 🐣
DOM에 내장된 기능
console.log(number.innerText); // 내용 // **0**
console.log(increase.offsetTop); // top 위치 // **70**
console.log(decrease.id); // id // **decrease**
Element.blah blah
😗🥱
여기 에 위 세 가지 기능 외에 다양한 Properties가 소개되어 있다.
: on이벤트이름 값에 함수를 설정하면 된다.
정말 다양한 DOM 이벤트가 있다.
버튼들이 클릭 됐을 때 콘솔에 텍스트를 출력하는 이벤트
const number = document.getElementById("number");
const increase = document.getElementById("increase");
const decrease = document.getElementById("decrease");
increase.onclick = () => {
console.log("increase 가 클릭됨");
};
decrease.onclick = () => {
console.log("decrease 가 클릭됨");
};
잘 출력되는 것을 볼 수 있다.
👆🏻👆🏻이 렇 게 하 려 면 ?
👇👇
const number = document.getElementById("number");
const increase = document.getElementById("increase");
const decrease = document.getElementById("decrease");
increase.onclick = () => {
const current = parseInt(number.innerText, 10);
number.innerText = current + 1;
};
decrease.onclick = () => {
const current = parseInt(number.innerText, 10); // 요기
number.innerText = current - 1;
};
// 요기 줄에 parseInt
는 문자열을 숫자로 변환해주는 함수이며,
10 은 10진수로 숫자를 받아오겠다는 의미
모달이란, 다음 이미지와 같이 기존의 내용을 가리고 나타나는 메시지박스 같은 형태의 UI 를 의미한다.
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<h1>안녕하세요!</h1>
<p>내용내용내용</p>
<button id="open">버튼 열기</button>
<div class="modal-wrapper" style="display: none;">
<div class="modal">
<div class="modal-title">안녕하세요</div>
<p>모달 내용은 어쩌고 저쩌고..</p>
<div class="close-wrapper">
<button id="close">닫기</button>
</div>
</div>
</div>
<script src="src/index.js"></script>
</body>
</html>
id
값 설정src
로 JavaScript연동style="display: none;" // 모달 열고 닫기
→ modal-wrapper : 모달이 열릴 때 모달의 background 를 감싸는 클래스
→ modal : 모달창을 감싸는 클래스
body {
font-family: sans-serif;
}
.modal-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
}
.modal {
background: white;
padding: 24px 16px;
border-radius: 4px;
width: 320px;
}
.modal-title {
font-size: 24px;
font-weight: bold;
}
.modal p {
font-size: 16px;
}
.close-wrapper {
text-align: right;
}
background: rgba(0, 0, 0, 0.5);
뒷배경을 회색 50%로 지정 및 가운데 정렬border-radius
버튼 둥글게import "./styles.css";
const open = document.getElementById("open");
const close = document.getElementById("close");
const modal = document.querySelector(".modal-wrapper");
open.onclick = () => {
modal.style.display = "flex";
};
close.onclick = () => {
modal.style.display = "none";
};
import "./styles.css";
css 연동id
가 아닌 클래스로 DOM을 선택하고 싶을 땐 document.getElementsByClassName
또는 document.querySelector
를 사용하면 된다. document.querySelector
를 사용하여 class 값으로 DOM 을 선택할 때에는 텍스트 앞에 .
을 붙여주어야 한다.완 성 ! 🥱