[ promise, 콜백 지옥 ]
콜백 지옥 : 연속되는 비동기 함수들을 처리할 때 비동기 처리의 결과 값을 사용하기 위해 콜백이 깊어지는 현상
콜백 지옥을 해결하기 위해서 promise 객체를 사용하게 되면은 비동기 처리 함수에 콜백을 줄지어 전달하지 않아도
된다.
< 비동기 작업이 가질 수 있는 3가지 상태 >
비동기 작업 : 먼저 지시된 작업이 종료될 때 까지 기다리지 않고 다음 작업을 실행하는 방식
1. Pending( 대기 상태 ) : 비동기 작업이 진행 중이거나 작업이 시작할 수 없는 문제가 발생했음
2. Fulfilled( 성공 ) : 비동기 작업이 의도대로 정상적으로 동작된 상태
3. Rejected( 실패 ) : 비동기 작업이 모종의 이유로 인해 실패한 상태 ex) 서버 미응답, 시간 초과, 자동 취소
비동기 작업은 작업이 성공하거나 실패하면 그 결과로 작업이 끝나게 된다.
pending 상태에서 fulfilled 상태로 변화하는 과정을 resolve(해결)되었다라고 하고 rejected 상태로 변화하는 과정은
reject(거부) 되었다고 한다.
function isPositive(number, resolve, reject){
setTimeout(()=>{
if( typeof number === 'number'){
// resolve
resolve(number >= 0 ? "양수" : "음수");
}
else{
// reject
reject("숫자형이 아닙니다.");
}
}, 2000)
};
isPositive( 10,
(res)=>{
console.log("성공 :", res);
},
(err)=>{
console.log("실패 :" , err);
});
//성공 : 양수
< promise를 사용해서 비동기 처리해보기 >
new 키워드를 사용해 promise 객체를 생성한다. 객체의 생성자로 비동기함수를 실행하는 함수를 넘겨준다면 전달되는
순간 함수가 바로 실행이 된다.
function isPositiveP(number){
const executor = ( resolve, reject )=>{ // // executor는 실질적으로 비동기작업을 수행하는 실행자 함수
setTimeout(()=>{
if( typeof number === 'number'){
// resolve
console.log(number);
resolve(number >= 0 ? "양수" : "음수");
}
else{
// reject
reject("숫자형이 아닙니다.");
}
}, 2000);
};
const asyncTask = new Promise(executor);
return asyncTask;
}
isPositiveP(101); // 101
asyncTask를 리턴해주면 promise를 반환한다.
함수가 promise를 반환한다는 것은 그 함수는 비동기 작업을 하고 그 작업의 결과를 promise 객체로 반환받아서
사용할 수 있는 함수라는 의미이다.
반환받은 promise 객체를 사용하기 위해 상수에 저장해주면 그 상수는 반환받은 promise 객체를 이용해서
비동기 처리에 대한 resolve나 reject에 대한 결과 값을 아무데서나 사용할 수 있다.
promise 객체 사용법 : promise 객체에 대한 메소드 then, catch를 사용
function isPositiveP(number){
const executor = ( resolve, reject )=>{ // // executor는 실질적으로 비동기작업을 수행하는 실행자 함수
setTimeout(()=>{
if( typeof number === 'number'){
// resolve
resolve(number >= 0 ? "양수" : "음수");
}
else{
// reject
reject("숫자형이 아닙니다.");
}
}, 2000);
};
const asyncTask = new Promise(executor);
return asyncTask;
}
const res = isPositiveP(101); // 101
res
.then((res)=>{
console.log("작업 성공 :", res);
})
.catch((err)=>{
console.log("작업 실패 :", err);
});
// 작업 성공 : 양수
then과 catch를 사용하면 resolve일 때 전달받은 값을 then 콜백 함수에서 받아줄 수 있고, reject일 때 전달받은 값을
catch에서 받아줄 수 있다.
< 콜백 지옥 탈출하기 >
1. 콜백 지옥일 경우
function taskA( a, b, cb ){
setTimeout(()=>{
const res = a+b;
cb(res);
}, 2000);
}
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(2,3,(a_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);
});
});
});
// task A : 5
// task B: 10
// task C : -10
2. 콜백 지옥을 promise 객체를 사용해서 해결하기
어떤 함수가 promise 객체를 반환한다는 것은 그 함수는 비동기적으로 동작을 하고 반환한 promise 객체를 이용해서
비동기 처리의 결과 값을 then, catch로 이용할 수 있게끔 만드는 것이다.
function taskA( a, b ){
const executorA = ( resolve, reject )=>{
setTimeout(()=>{
const res = a+b;
resolve(res);
}, 2000);
};
return new Promise(executorA);
}
// function taskA( a, b, cb ){
// return new Promise((resolve, reject)=>{
// setTimeout(()=>{
// const res = a+b;
// cb(res);
// }, 2000);
// });
// }
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,6).then((a_res)=>{
console.log("task A :", a_res);
taskB(a_res).then((b_res)=>{
console.log("task B :", b_res);
taskC(b_res).then((c_res)=>{
console.log("task C :", c_res);
});
});
});
// task A : 11
// task B : 22
// task C : -22
then chaining : then 메소드를 계속 이어서 붙이는 것
taskA( 5,7 ).then((a_res)=>{
console.log("task A :", a_res);
return taskB(a_res);
}).then((b_res)=>{
console.log("task B :", b_res);
return taskC(b_res);
}).then((c_res)=>{
console.log("task C :", c_res);
});
// task A : 12
// task B : 24
// task C : -24
콜백 식으로 사용할 경우 비동기 처리의 결과 값을 또 다른 비동기 처리의 값으로 끝없이 코드가 한 칸씩 들어가는 식으로
작성해야하는데 promise를 사용할 경우는 코드를 아래로 늘려쓸 수 있다. 또한 promise를 사용할 경우 중간에 다른
코드를 작성하는 것이 가능하기 때문에 비동기 처리를 호출하는 코드와 결과를 처리하는 코드를 분리하는 것이
가능하기 때문에 좀 더 가독성이 있고 깔끔한 비동기 처리를 할 수 있다.
const aaa = taskA( 5,7 ).then((a_res)=>{
console.log("task A :", a_res);
return taskB(a_res);
})
console.log("안녕하세요");
aaa.then((b_res)=>{
console.log("task B :", b_res);
return taskC(b_res);
}).then((c_res)=>{
console.log("task C :", c_res);
});
// 안녕하세요
// task A : 12
// task B : 24
// task C : -24
[ async / await | 직관적인 비동기 처리 ]
promise : 비동기 처리를 도와주는 객체
1. async : 비동기를 다루는 기능이자 promise를 쉽게 다룰 수 있도록 도와준다.
async를 함수 앞에 붙여줄 경우 그 함수는 promise를 반환하게 된다.
function hello(){
return "hello";
}
async function helloAsync(){
return "hello Async";
}
console.log(hello()); // hello
console.log(helloAsync()); // Promise { 'hello Async' }
promise 객체를 그냥 출력하게 되면 promise 객체가 바로 출력이 된다. 즉, 함수 앞에 async를 붙여주게 된다면
그 함수는 자동적으로 promise를 리턴하는 비동기 처리함수가 된다.
function hello(){
return "hello";
}
async function helloAsync(){
return "hello Async";
}
helloAsync().then((res)=>{
console.log(res); // hello Async
})
promise 객체를 리턴하는 비동기 처리 함수에 then를 사용하게 된다면 res에 반환하는 값인 문자열이 들어오게 된다.
즉, async를 붙여준 함수의 리턴 값은 비동기 작업 객체 promise의 resolve 결과 값이 된다.
2. await : 비동기 함수를 동기적으로 처리하게 만드는 키워드
function delay(ms){ // 전달받은 시간만큼 지연되는 함수
return new Promise((resolve)=>{
setTimeout(resolve, ms)
});
}
async function helloAsync(){
return delay(3000).then(()=>{
return "hello Async";
});
}
helloAsync().then((res)=>{
console.log(res); // hello Async
});
* setTimeout()의 콜백함수 부분에는 콜백함수 자체를 전달할 수 있음
function delay(ms){ // 전달받은 시간만큼 지연되는 함수
return new Promise((resolve)=>{
setTimeout(resolve, ms)
});
}
async function helloAsync(){
await delay(3000);
return "hello Async";
}
helloAsync().then((res)=>{
console.log(res); // hello Async
});
await를 비동기 함수 앞에 붙여주게 된다면 비동기 함수가 동기적인 함수처럼 작동하게 된다.
즉, await 키워드가 붙은 함수의 호출은 그 함수가 끝나기 전까지 함수 코드 밑에 있는 부분들을 실행하지 않는다.
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(){
const res = await helloAsync();
console.log(res);
}
main(); // hello Async
async와 await를 이용해서 promise를 반환하는 함수를 동기적인 함수를 호출한 것 처럼 사용할 수 있다.
'Front-End > JAVASCRIPT' 카테고리의 다른 글
[ JavaScript ] 자바스크립트 응용 ② (0) | 2022.08.31 |
---|---|
[ JavaScript ] 자바스크립트 응용 ① (0) | 2022.08.27 |
[ JavaScript ] 자바스크립트 기본 ④ (4) | 2022.08.25 |
[ JavaScript ] 자바스크립트 기본 ③ (0) | 2022.08.21 |
[ JavaScript ] 자바스크립트 기본 ② (0) | 2022.08.21 |