Class: 제로베이스
Created: December 27, 2022 7:10 AM
Type: Javascript
강의 명: 초심자도 빈틈없이 학습하는 자바스크립트
동기(동시에 발생함)의 반의어로, 동시에 발생하지 않음을 뜻함. → 순차적으로 발생
비동기로 코드를 짜야하는 이유는, a 작업이 수행된 후에 얻게된 데이터를 이용해서 b 작업을 수행해야 하기 때문
동기 코드
비동기 코드
const A = (callback) => {
const a = 'A 함수 실행 후 생기는 데이터';
callback(a);
};
const B = (a) => {
console.log(`${a}를 이용하는 B`)
};
A(B); // 출력 : A 함수 실행 후 생기는 데이터를 이용하는 B
// A 함수가 실행되며 데이터 a가 생성되고,
// a 데이터를 인자로 받는 B 함수가 순차적으로 실행
구독이라는 방법을 이용하는 비동기 구현 방법.
콜백 함수 대신 유용하게 쓸 수 있는 오브젝트.
state : pending → fulfulled or rejected
Producer vs Consumer
producer
새로운 promise 가 만들어질 때는, 전달한 executor라는 함수가 자동으로 실행된다.
new Promise 생성자 함수를 통해 생성 가능. 매개변수로 함수를 받는다.
resolve와 reject 함수가 그 매개변수.
then 메서드 - 성공시 넘어오는 값을 result로 코드 구현
catch 메서드 - 실패시 넘어오는 에러 error 로 코드 구현
하지만, 프라미스 역시 then 절이 계속 이어지는 식으로 체이닝이 발생하기 때문에 복잡해질수록 코드 파악 어렵.
const A2 = () => new Promise((resolve, reject) => {
const a = 'A 함수 실행 후 생기는 데이터';
resolve(a);
})
const B2 = (a) => {
console.log(`${a}를 이용하는 B`);
};
A2()
.then((a) => {
console.log('A2 실행 성공!');
B2(a);
})
.catch((error) => {
console.log(error.message);
})
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve('🐓'), 500);
});
const getEgg = (hen) =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${hen} => 🥚`), 500);
});
const cook = (egg) =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`), 500);
});
getHen()
.then((hen) => getEgg(hen))
//.then(getEgg) -> then으로 받은 value를 바로 넘겨줄 때는 이렇게 작성 가능
.then((egg) => cook(egg))
.then((meal) => console.log(meal));
// 1.5초 후에 🐓 => 🥚 => 🍳 출력
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve('🐓'), 500);
});
const getEgg = (hen) =>
new Promise((resolve, reject) => {
setTimeout(() => reject(new Error(`error! ${hen} => 🥚`)), 500);
});
const cook = (egg) =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`), 500);
});
getHen()
.then((hen) => getEgg(hen))
.catch(error => {
return '👀';
})
.then((egg) => cook(egg))
.then((meal) => console.log(meal))
.catch(console.log);
// 1.5초 후에 👀 => 🍳 출력
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(
(id === 'james' && password ==='asdf') ||
(id === 'kody' && password === 'asdf')
) {
resolve(id);
} else {
reject(new Error('not found'));
}
}, 1000);
});
}
getRoles(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(id === 'james') {
resolve({ name: 'james', 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)
// userStorage에 loginUser 함수를 호출해서 id와 password를 prompt 창으로 받는다.
.then(userStorage.getRoles)
// resolve를 통해 나온 정보를 getRole이 받아서 id가 james 라면 resolve 실행.
.then(id => alert(`Hello ${id.name}, you have a ${id.role} role`))
// 받은 정보로 alert창을 띄움
.catch(console.log);
// 만약 james 가 아닌 다른 정보가 들어온다면, 콘솔창에 error 메세지
프라미스의 개념을 사용한 문법이지만, 보다 가독성 있게 코드를 표현할 수 있다.
비동기로 표현할 함수 앞에 async 라는 키워드를 붙이면, 해당 함수는 항상 프라미스를 반환.
비동기 함수를 호출하며, 호출 코드 앞에 await를 붙이면, 프라미스가 값을 반환하기 기다렸다가 반환되는 값을 변수에 할당해 준다.
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("완료!"), 1000)
});
let result = await promise; // 프라미스가 이행될 때까지 기다림 (*)
alert(result); // "완료!"
}
f();
자바스크립트는 await
키워드를 만나면 프라미스가 처리될 때까지 기다립니다(await는 '기다리다’라는 뜻을 가진 영단어입니다 – 옮긴이). 결과는 그 이후 반환. await는 async 함수 내부에서만 동작한다.
함수를 호출하고, 함수 본문이 실행되는 도중에 (*)
로 표시한 줄에서 실행이 잠시 '중단’되었다가 프라미스가 처리되면 실행이 재개됩니다. 이때 프라미스 객체의 result
값이 변수 result에 할당.
따라서 위 예시를 실행하면 1초 뒤에 '완료!'가 출력
const A3 = async() => {
const a = 'A 함수 실행 후 생기는 데이터';
return a;
};
const B3 = (a) => {
console.log(`${a}를 이용하는 B`)
};
const func = async () => {
const b = await A3();
console.log('A3 실행 성공!!!');
B3(b);
};
func(); // A 함수 실행 후 생기는 데이터를 이용하는 B
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(
(id === 'james' && password ==='asdf') ||
(id === 'kody' && password === 'asdf')
) {
resolve(id);
} else {
reject(new Error('not found'));
}
}, 1000);
});
}
getRoles(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(id === 'james') {
resolve({ name: 'james', 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");
async function checkUser() {
try {
const userId = await userStorage.loginUser(id, password);
const user = await userStorage.getRoles(userId);
alert(`Hello ${user.name}, you have a ${user.role}`);
} catch (error) {
console.log(error);
}
}
checkUser();
function sum(a, b, callback) {
let result = a + b;
callback(result)
}
let callback = (result) => {
console.log(result)
}
sum(10, 20, callback)
//30
function info (name, age, callback) {
let result = {
name: name,
age: age
}
callback(result)
}
let print = function(result) {
console.log(`난 ${result.age}살 ${result.name} 입니다.`)
}
info('Kody', 25, print)
//난 25살 Kody 입니다.
/* 프라미스를 이용한 비동기 1 */
function sum2(a, b) {
return new Promise((resolve, reject) => {
if(a==null || b==null) {
reject(new Error(null))
} else {
resolve(a + b);
}
})
}
sum2(10, 20)
.then((result) => console.log(result))
.catch((error) => console.log("실패 " + error))
/* 프라미스를 이용한 비동기 2 */
function info2(name, age) {
return new Promise((resolve, reject) => {
if(typeof name != 'string' || typeof age != 'number' || age<1 ) {
reject(new Error(undefined))
} else {
resolve({
name: name,
age: age
})
}
})
}
info2('Kody', 25)
.then((result) => console.log(`Name: ${result.name}, Age: ${result.age}`))
.catch((error) => console.log("실패 " + error))
// Name: Kody, Age: 25
/* async await 을 이용한 비동기 1 */
async function sum3(a, b) {
let promise = new Promise((resolve, reject) => {
if(a==null || b==null) {
reject(new Error(null))
} else {
resolve(a + b);
}
})
try{
console.log(await promise)
} catch(error) {
console.log("실패 " +error)
}
}
sum3(10, 20) // 30
/* async await 을 이용한 비동기 2 */
async function info3(name, age) {
let promise = new Promise((resolve, reject) => {
if(typeof name != 'string' || typeof age != 'number' || age<1 ) {
reject(new Error(undefined))
} else {
resolve({
name: name,
age: age
})
}
})
try{
let result = await promise;
console.log(`Name: ${result.name}, Age: ${result.age}`)
} catch(error) {
console.log("실패 " + error)
}
}
info3('Kody', 25) // Name: Kody, Age: 25
function subtraction(a,b) {
const test = new Promise((resolve, reject) => {
if(a > b) resolve(a-b);
else resolve(b-a)
})
return test
}
function promiseTest() {
return subtraction(10, 20)
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error);
};
promiseTest(); // 10
async function promiseAsync() {
try {
const result = await subtraction(10, 20);
console.log(result)
} catch(error) {
console.log(error)
}
}
promiseAsync(); // 10