Promise
Async
Await
Resolve
Rejected
메소드체이닝
then
catch
fulfilled
pending
Pending (대기상태)
: 현재 비동기작업이 진행중이거나 시작할 수 없는 문제가 발생한 상태Fulfilled (성공)
: 비동기작업이 의도한대로 정상적으로 실행되는 상태Rejected (실패)
: 비동기작업이 모종의 이유로 실패했음을 의미하는 상태 (ex. 서버가 응답하지 않거나, 자동으로 취소되는 등)Resolve (해결)
: Pending (대기상태) > Fulfilled (성공)Reject (거부)
: Pending (대기상태) > Rejected (실패)function isPositive(number, resolve, reject) {
setTimeout( () => {
if(type of number === 'number'){
// 성공 resolve
resolve(number >0 ? "양수" : "음수") // 삼항연산자
} else {
// 실패 reject
reject("주어진 값이 숫자형 값이 아닙니다.")
}
}, 2000)
}
isPositive(10, (res)=>{
console.log("성공적으로 수행됨 :", res);
},
(err)=>{
console.log("실패하였음 :", err);
}
); // 성공적으로 수행됨 : 양수
// 만약 10이 아니라 []을 전달하면 2초 뒤 실패하였음 : 주어진 값이 숫자형 값이 아닙니다
function isPositive(number, resolve, reject) {
setTimeout( () => {
if(typeof number === 'number'){
// 성공 -> resolve
resolve( number >=0 ? "양수" : "음수" )
} else {
// 실패 -> reject
reject( "주어진 값이 숫자형이 아닙니다.");
}
}, 2000);
}
// number 파라미터를 똑같이 받음
// executor는 실행자라는 뜻이로 "비동기처리를 실질적으로 수행하는 함수"
function isPositiveP(number){
const executor = (resolve, reject) => {
setTimeout( ()=> {
if(typeof number === 'number'){
// 성공 -> resolve
console.log(number;)
resolve( number >=0 ? "양수" : "음수" )
} else {
// 실패 -> reject
reject( "주어진 값이 숫자형이 아닙니다.");
}
}, 2000);
};
// 실행시키는 방법
// 비동기 작업을 저장할 asyncTask 상수를 만들고
// 새로운 Promise 객체를 생성해 생성자로
// 비동기작업의 실질적인 수행자인 executor를 전달하는 순간 바로 수행됨
const asyncTask = new Promise(excutor);
return asyncTask;
// 반환하면 isPositiveP의 값이 Promise로 바뀐 것 확인 가능
// function isPositiveP(number: any) : Promise<any>
}
// 이 함수가 반환하는 객체를 res 상수에 저장
const res = isPositiveP(101); // 101
// Promise 객체의 비동기처리를 사용하는 방법
// then 콜백함수, catch 콜백함수
// then 메서드 - 작업 성공 resolve
// catch 메서드 - 작업 실패 reject
res
.then((res)=>{
console.log("작업 성공 :", res);
)}
.catch((err)=>{
console.log("작업 실패 :", err);
})
// 작업 성공 : 양수
// []을 전달하게 되면 작업 실패 : 주어진 값이 숫자형 값이 아닙니다
function taskA(a, b, cb){
setTimeout( () => {
const res = a + b;
cb(res);
}, 3000);
}
function taskB(a, cb){
setTimeout( () => {
const res = a * 2;
cb(res);
}, 1000);
}
function taskC(a, cb){
setTimeout( () => {
const res = a * -1;
cb(res);
}, 2000);
}
// 콜백지옥
taskA(3, 4, (res) => {
console.log("task A :", a_res);
taskB(a_res, (b_res) => {
console.log("task B :", b_res);
taskC(b_res, (c_res) => {
console.log("task C :", c_res);
});
});
});
// 3초 뒤 task A : 7
// 1초 뒤 task B : 14
// 2초 뒤 task C : -14
// Promise를 사용하므로 cb는 필요가 없어져서 지워줌
// 비동기처리를 executor로 넣어주기
// 어떤 함수가 Promise 객체를 반환한다는 건 그 함수는 비동기적으로 동작을 하고,
// 지금 반환한 Promise 객체를 이용해서 비동기 처리의 결과값을
// then과 catch로 이용할 수 있게 만들겠다라는 의미.
function taskA(a, b){
return new Promise((resolve, reject) => {
setTimeout( () => {
const res = a + b;
resolve(res);
}, 3000);
});
}
function taskB(a){
return new Promise((resolve, reject) => {
setTimeout( () => {
const res = a * 2;
resolve(res);
}, 1000);
});
}
function taskC(a){
return new Promise((resolve, reject) => {
setTimeout( () => {
const res = a * -1;
resolve(res);
}, 2000);
});
}
taskA(5, 1).then((a_res)=>{
console.log("A RESULT :", a_res);
taskB(a_res).then((b_res)=>{
console.log("B RESULT :", b_res);
taskC(b_res).then((c_res)=>{
console.log("C RESULT :", c_res);
});
});
});
// A RESULT : 6
// B RESULT : 12
// C RESULT : -12
// 그런데 then 사용법 때문에 콜백지옥식으로 나온 코드가 나왔는데 이것을 바꿔보면
function taskA(a, b){
return new Promise((resolve, reject) => {
setTimeout( () => {
const res = a + b;
resolve(res);
}, 3000);
});
}
function taskB(a){
return new Promise((resolve, reject) => {
setTimeout( () => {
const res = a * 2;
resolve(res);
}, 1000);
});
}
function taskC(a){
return new Promise((resolve, reject) => {
setTimeout( () => {
const res = a * -1;
resolve(res);
}, 2000);
});
}
// then 메서드 계속 연결 => then chaining
// taskB, C 결과값 반환해 인자로 전달
taskA(5, 1).then((a_res)=>{
console.log("A RESULT :", a_res);
return taskB(a_res);
})
.then((b_res) => {
console.log("B RESULT :", b_res);
return taskC(b_res);
}
.then((c_res) => {
console.log("C RESULT :", c_res);
});
// A RESULT : 6
// B RESULT : 12
// C RESULT : -12
// Promise를 사용하면 코드를 체이닝으로 늘여쓸 수 있음
// 콜백지옥과 달리 1) 중간에 다른 작업을 끼워넣어도 동일하게 실행가능,
// 2) 좀 더 가독성있는 코드 작성을 도와준다
const bPromiseResult = taskA(5, 1).then((a_res)=>{
console.log("A RESULT :", a_res);
return taskB(a_res);
});
console.log("blahblahblahblahblah");
console.log("blahblahblahblahblah");
console.log("blahblahblahblahblah");
bPromiseResult
.then((b_res) => {
console.log("B RESULT :", b_res);
return taskC(b_res);
}
.then((c_res) => {
console.log("C RESULT :", c_res);
});
// (3) blahblahblahblahblah
// A RESULT : 6
// B RESULT : 12
// C RESULT : -12
function hello() {
return "hello";
}
async function helloAsync(){
return "hello Async";
}
// function helloAsync : Promise<string>
console.log(hello()); // hello
console.log(helloAsynce()); // Promise {<pending>}
// 함수 앞에 async를 붙여주게 되면 Promise 객체로 출력
// (Promise를 리턴하고 있다)
// helloAsynce가 Promise라는 것은 then을 써서 호출도 가능하다는 이야기가 되는데,
helloAsync().then((res)=>{
console.log(res);
});
// hello Async
// async를 붙이고 리턴만 해도 Promise를 리턴하면서
// resolve를 return "hello Async" 값이 res에 들어갈 수 있게 되는 것임
// async를 붙임으로써 그 함수가 Promise를 반환하도록 하게 해줌
// 비동기함수는 Promise를 리턴한다
function delay (ms) {
return new Promise((resolve)=>{
// resolve를 콜백함수 자체로 전달 가능
setTimeout(resolve, ms);
})
}
async function helloAsync() {
// return delay(3000).then(()=>{
// return "hello Async";
// });
await delay(3000);
return "hello Async";
}
helloAsync().then((res)=>{
console.log(res);
});
// 3초 후 hello Async
// 📝 await 함수를 비동기 함수인 delay 앞에 붙이면 동기적으로 호출됨
// (동기적인 함수처럼 동작하게)
// 📝 await 코드라인에서는 모두 동기적으로 수행하게 된다
// 📝 await은 async가 붙은 함수 안에서만 사용 가능
function delay (ms) {
return new Promise((resolve)=>{
setTimeout(resolve, ms);
})
}
async function helloAsync() {
await delay(3000);
return "hello Async";
}
async function main() {
// helloAsync().then((res)=>{
// console.log(res);
// });
const res = await helloAsync();
console.log(res);
}
main();
// hello Async
📚 Promise, async-await부터는 강의 내용이 어려워서 서칭 🕵️
출처
비동기처리 Point : 동시에 여러 작업을 해볼 수 있다
비동기 작업은 여러 작업을 동시에 수행할 수 있는 장점이 있지만, 의존성이 길게 이어져 있는 비동기 작업들을 처리할 때 곤혹에 치를 수 있다. 왜냐하면 비동기 작업이 시작되는 시점은 함수 호출이며, 또한 이 함수 호출 시점에 다음 작업(콜백 함수)도 넘겨줘야 하기 때문에.
async function 함수명() {
await 비동기_처리_메서드_명();
}
실용 예제 - 각각 사용자와 할 일 목록을 받아오는 HTTP 통신 코드
function fetchUser() {
var url = 'https://jsonplaceholder.typicode.com/users/1'
return fetch(url).then(function(response) {
return response.json();
});
}
function fetchTodo() {
var url = 'https://jsonplaceholder.typicode.com/todos/1';
return fetch(url).then(function(response) {
return response.json();
});
}
// 위 함수들을 실행하면 각각 사용자 정보와 할 일 정보가 담긴 프로미스 객체가 반환됩니다.
// 이 두 함수를 이용하여 할 일 제목을 출력해보겠습니다. 살펴볼 예제 코드의 로직은 아래와 같습니다.
// 두 함수를 이용하여 할 일 제목을 출력
// 1. fetchUser()를 이용하여 사용자 정보 호출
// 2. 받아온 사용자 아이디가 1이면 할 일 정보 호출
// 3. 받아온 할 일 정보의 제목을 콘솔에 출력
async function logTodoTitle() {
var user = await fetchUser();
if (user.id === 1) {
var todo = await fetchTodo();
console.log(todo.title); // delectus aut autem
}
}