동기는 순차적, 직력적으로 테스크를 수행한다.
비동기는 병렬적으로 테스크를 수행한다.
아래의 사진을 보면서 동기와 비동기를 이해해보자!
출처: https://simju9397.tistory.com/45
만약 우리가 데이터를 서버에서 받아오는 앱을 만든다고 가정해보자.
먼저, 서버로부터 데이터를 받아오는 코드가 실행되어야 한다. 만약 비동기로 처리하지 않고, 동기적으로 구성을 하게 된다면, 데이터를 받아오기까지 기다린 다음에 앱이 실행될 것이다. 서버에 가져오는 데이터 양이 많을 수록 앱의 실행속도는 기하급수적으로 느려진다. 데이터를 불러오기까지 앱이 대기하는 상태가 발생된다. 이런 불편을 없애기 위해서 데이터를 수신하는 코드와 페이지를 표시하는 것은 비동기적으로 처리를 해야한다. 가장 대표적인 예가 setTimeOut과 AJax다.
출저: https://velog.io/@lsj8367/Javascript-동기와-비동기방식의-차이점
동기 처리
console.log(1);
console.log(2);
console.log(3);
//1
//2
//3
비동기 처리
console.log(1);
setTimeout(() => {
console.log(2)
},2000)
console.log(3);
//1
//3
//2
콜백함수란?
이름 그대로 나중에 호출되는 함수를 말한다.
특정함수에 매개변수로 전달된 함수를 의미한다.
콜백 함수는 코드를 통해 명시적으로 호출하는 함수가 아니라, 개발자는 단지 함수를 등록 하기만 하고, 어떤 이벤트가 발생했거나 특정 시점에 도달했을 때 시스템에서 호출하는 함수를 말한다.
콜백은 좀 더 쉽게 이해해보기 🔻
콜백 함수의 동작 방식은 일종의 식당 자리 예약과 같습니다. 일반적으로 맛집을 가면 사람이 많아 자리가 없습니다. 그래서 대기자 명단에 이름을 쓴 다음에 자리가 날 때까지 주변 식당을 돌아다니죠. 만약 식당에서 자리가 생기면 전화로 자리가 났다고 연락이 옵니다. 그 전화를 받는 시점이 여기서의 콜백 함수가 호출되는 시점과 같습니다. 손님 입장에서는 자리가 날 때까지 식당에서 기다리지 않고 근처 가게에서 잠깐 쇼핑을 할 수도 있고 아니면 다른 식당 자리를 알아볼 수도 있습니다.
자리가 났을 때만 연락이 오기 때문에 미리 가서 기다릴 필요도 없고, 직접 식당 안에 들어가서 자리가 비어 있는지 확인할 필요도 없습니다. 자리가 준비된 시점, 즉 데이터가 준비된 시점에서만 저희가 원하는 동작(자리에 앉는다, 특정 값을 출력한다 등)을 수행할 수 있습니다.
출저: 캡팁판교 비동기/동기
콜백 함수에는 동기,비동기가 있다.
console.log(1);
setTimeout(() => {
console.log(2)
},2000)
console.log(3);
// synchronous callback
function printImmediately(print){
print()
}
printImmediately(() => console.log('hello'))
//Asynchrouns callback
function printWithDelay(print, timeout){
setTimeout(print, timeout)
}
printWithDelay(() => console.log('async callback), 2000)
//1
//3
//'hello'
//'async callback'
//hoisting 된모습
// synchronous callback
function printImmediately(print){
print()
}
//Asynchrouns callback
function printWithDelay(print, timeout){
setTimeout(print, timeout)
}
console.log(1); ----> 동기
setTimeout(() => {
console.log(2)
},2000) -----> 비동기
console.log(3);
printImmediately(() => console.log('hello')) ----> 동기
printWithDelay(() => console.log('async callback), 2000) ----> 비동기
function Callback(callback){
console.log('콜백 함수');
callback();
}
Callback(() => {
console.log('콜백을 받는곳!')
})
const getThreePromise = () => new Promise((resolve, reject) => {
resolve(3);
});
getThreePromise().then(console.log);
//producer
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("hello world!!!!");
// reject(new Error('no network'))
}, 2000);
});
//consumer : then, catch, finally
promise
.then((value) => {
console.log(value);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
console.log("finally");
});
Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태
Pending
아래와 같이 new Promise() 메서드를 호출하면 대기 상태가 된다.
new Promise()
Fullfilled -이행
콜백 함수의 인자 resolve를 아래와 같이 실행하면 이행 상태가 된다.
function getData(){
return new Promise((resolve, reject) => {
let data = 100;
resolve(data);
})
}
getData().then(data => console.log(data));
//100
rejected - 실패
function getData(){
return new Promise((resolve,reject) => {
reject(new Error('에러발생'))
})
}
getData().then().catch(console.log)
//[object Error] {....}
출처 : 프로미스 흐름 처리
여러 개의 프로미스 연결하기 (Promise Chaining)
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
fetchNumber
.then((num) => num * 2) //2
.then((num) => num * 3) //6
.then((num) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num - 1), 1000); //5
});
})
.then((num) => console.log(num)); //5
//5
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve("🐓"), 1000);
});
const getEgg = (hen) =>
new Promise((resolve, reject) => {
// setTimeout(() => resolve(`${hen} => 🥚`), 1000);
setTimeout(() => reject(new Error(`${hen} => 🥚`) ), 1000);
});
const cook = (egg) =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`));
});
getHen() //
.then(getEgg)
.catch(error => {
return '🥖'
})
.then(cook)
.then(console.log)
.catch(console.log);//🥖 => 🍳
callback 함수
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (
(id === "min" && password === "dream") ||
(id === "coder" && password === "wecode")
) {
resolve(id);
} else {
reject(new Error("not found"));
}
}, 2000);
})
}
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (user === "min") {
resolve({ name: "min", role: "admin" });
} else {
reject(new Error("no access"));
}
}, 1000);
});
}
}
const userStorage = new UserStorage();
const id = prompt("enter your id");
const password = prompt("enter your password");
userStorage.loginUser(id, password)
.then(userStorage.getRoles)
.then( user => alert(`Hello ${user.name}, you have a ${user.role} role`))
.catch(console.log)
promise 함수 바꾼 것
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (
(id === "min" && password === "dream") ||
(id === "coder" && password === "wecode")
) {
resolve(id);
} else {
reject(new Error("not found"));
}
}, 2000);
})
}
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (user === "min") {
resolve({ name: "min", role: "admin" });
} else {
reject(new Error("no access"));
}
}, 1000);
});
}
}
const userStorage = new UserStorage();
const id = prompt("enter your id");
const password = prompt("enter your password");
userStorage.loginUser(id, password)
.then(userStorage.getRoles)
.then( user => alert(`Hello ${user.name}, you have a ${user.role} role`))
.catch(console.log)
async와 await는 자바스크립트의 비동기 처리 패턴 중 가장 최근에 나온 문법이다. 기존의 비동기 처리 방식인 콜백 함수와 프로미스의 단점을 보완하고 개발자가 읽기 좋은 코드를 작성할 수 있게 도와준다.
async function 함수명() {
await 비동기_처리_메서드_명();
}
function fetchItems() {
return new Promise(function(resolve, reject) {
var items = [1,2,3];
resolve(items)
});
}
async function logItems() {
var resultItems = await fetchItems();
console.log(resultItems);
}
logItems();
function delay(ms){
return new Promise((resolve) => setTimeout(resolve => ms))
}
// promise를 사용할때
function getApple(){
return delay(300)
.then(() => console.log('🍎'))
}
// async 를 사용하면 아래와 같이 바꿀수 있다.
async function getApple(){
await delay(3000)
return '🍎'
}
getApple().then(console.log) // "🍎"
function delay(ms){
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getApple(){
await delay(3000);
return '🍎'
}
async function getBanana(){
await delay(3000);
return '🍌'
}
function pickFruits(){
return getApple()
.then(apple => {
return getBanana().then(banana => `${apple} + ${banana}`)
})
}
pickFruits().then(console.log)
// '🍎+🍌'
그렇지만 promise 많이 쓰면 콜백지옥 같은 일이 발생한다.
async function pickFruits(){
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`
}
pickFruits().then(console.log)
// 바나나와 사과를 순차적으로 받아올 필요가 없다.
// Promise가 생성되자마자, 실행된다는 점을 이용해보자
async function pickFruits(){
const applePromise = getApple();
const bananaPromise = getBanana()
const apple = await applePromise;
const banana = await bananaPromise;
return `${apple} + ${banana}`
}
pickFruits().then(console.log)
function delay(ms){
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getApple(){
await delay(1000);
// throw 'error가 발생함';
return '🍎';
}
async function getBanana(){
await delay(1000);
return '🍌'
}
async function pickFruits(){
try{
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`
}catch(err){
console.log(err)
}
}
pickFruits().then(console.log)
Promise.all([ ])
function pickAllFruits() {
return Promise.all([getApple(),getBanana()])
.then(fruits => fruits.join(' + '))
}
pickAllFruits().then(console.log); //"🍎 + 🍌"
Promise.race([])
function delay(ms){
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getApple(){
await delay(2000);
return '🍎'
}
async function getBanana(){
await delay(1000);
return '🍌'
}
function pickOnlyOne(){
return Promise.race([getApple(),getBanana()])
}
pickOnlyOne().then(console.log) // 🍌 ---바나나만 뜸
참고 블로그 :https://resilient-923.tistory.com/308
출처 : https://resilient-923.tistory.com/308
엔진의 주요 두 구성요소는
자바스크립트 엔진은 Memory Heap과 Call Stack으로 구성되어 있다.
자바스크립트는 단일 스레드(싱글 스레드) 프로그래밍 언어인데, 이 말은 Call Stack이 하나 라는 의미이다.
MemoryHeap은 우리가 프로그래밍을 할 때 선언된 변수, 함수 등이 담겨지는, 메모리 할당이 일어나는 곳이다.
Call Stack은 코드가 실행될 때 쌓이는 곳이고, Stack형태로 쌓이게 된다.
Stack은 LIFO(Last In First Out) 선입후출 즉, 가장 마지막에 들어온 게 먼저 나가는 구조이다.