NodeJS/Basic
[NodeJS] Promise, Await
hvoon
2022. 9. 14. 17:29
함수와 비슷한 기능을 갖고 있는 객체. 객체 내의 익명함수의 내용을 실현하고 결과를 보관하고 있다가 결과가 필요할 때 전달 받아 사용할 수 있게 해주는 구조의 객체
// const pm = new Promise(/*익명함수*/); // promise 객체의 전달인수 없는 선언문
// 익명함수 한개를 품고 있는 객체 생성 & 객체 변수에 저장
// promise 객체는 생성자의 전달인수로 익명함수를 전달하여야 생성되는데
// 이 익명함수는 promise의 기능이기도 함
// func = (resolve, reject) => {}
// const pm = new Promise(func);
// 또는 const pm = new Pormise((resolve, reject)=>{});
// 전달인수로 전달되는 익명함수의 내용
// const condition = true;
// (resolve, reject) => {
// if(condition) resolve('성공'); // 괄호가 붙어서 함수처럼 호출
// else reject('실패');
// }
let condition = true;
const pm = new Promise(
(resolve, reject)=>{
if(condition){
resolve('성공');
} else{
reject('실패');
}
}
);
// 결과 처리 이전에 다른 코드가 작성될 수 있음
console.log('1'); console.log('2'); console.log('3');
// 이제 결과를 이용한 작업 시작
// then과 catch와 finally에 익명함수가 전달인수로 전달되어 실행되게 함
// -Resolve(성공리턴 값) -> then으로 연결
// -Reject(실패리턴 값) -> catch로 연결
// -finally -> 성공과 실패 리턴값에 상관없이 무조건 실행되는 영역
pm
.then(
(message)=>{
console.log(message); // resolve가 호출된 경우 실행
}
// (message)=>{}: resolve가 호출되어 도착했을 때 실행될 익명함수. message 변수에 '성공' 전달
)
.catch(
(error)=>{
console.error(error); // reject가 호출된 경우 실행
}
// (error)=>{}: reject가 호출되어 도착했을 때 실행될 익명함수. reject 변수에 '실패' 전달
)
.finally(
()=>{
console.log('무조건 실행');
// 성공실패 중 하나와 함께 반드시 실행
}
);

// promise를 사용하지 않았을 때(동기식으로 무언가를 실행 => 비동기명령 삽입)
const printString = (string, callback) => {
var k = Math. floor(Math.random()*1000) +1; // 0~9초 사이의 랜덤한 시간 계산(밀리초)
setTimeout(()=>{
console.log(string+' '+k);
}, k); // setTimeout: 지정한 시간(k)만큼 딜레이된 후 익명함수 실행(비동기함수)
callback();
}
// printString( 'A',()=>{printString("B",function(){});} );
printString( 'A',()=>{printString("B",()=>{});} );

// 동기실행의 예(동기실행을 비동기 실행처럼 보이게 하기 위해 억지로 코드를 구현)
console.log('작업 시작');
console.log('작업1: 오래걸림');
const wakeUpTime = Date.now() + 3000; // 현재시간에 3초를 더한값을 wakeUpTime 변수에 저장
while(Date.now()<wakeUpTime){}
// 오래 걸리는 작업이 오래 걸리는 것처럼 보이게 하기 위해 일부러 시간을 이용한 반복실행을 사용
// 계속해서 현재시간을 wakeUpTime과 비교해서 그보다 커질때까지 반복실행
console.log('작업1 종료');
console.log('작업2: 오래걸리는 작업의 다음작업');
console.log('작업2 종료');
// 동시 실행은 완성할 수 없으며 동시 실행인 것처럼 비동기인 것처럼 코드를 꾸밀 수는 있음
console.log('결론: 작업1, 작업2 순서에 맞춰 작업 종료');

// 비동기 실행
function longRunningTash(){
console.log('작업1의 내용 모두 종료 후 끝');
}
console.log('시작');
console.log('작업1: 오래걸리는 작업 시작');
console.log('작업1을 비동기 실행으로 전환');
setTimeout(longRunningTash, 3000); // setTimeout이 3초 후에 longRunningTash 함수를 호출함
// setTimeout은 비동기함수이기 때문에 별도의 실행스레드가 실행을 담당.
// 현재스레드는 다음 명령으로 실행포커스가 이동함
console.log('작업2: 오래 걸리는 작업의 다음 작업 시작');
console.log('작업2만 일단 끝');

console.log('시작');
let longRunningTash = new Promise(
(resolve,reject)=>{
console.log('작업1: 오래걸리는 작업시작');
setTimeout(()=>{console.log('작업1: 종료');},3000);
resolve();
}
);
console.log('딴짓');console.log('딴짓');console.log('딴짓');
longRunningTash
.then(
()=>{
console.log('작업2: 오래걸리는 작업의 다음작업');
console.log('작업2: 종료');
}
);

console.log('시작');
let longRunningTash = new Promise(
(resolve,reject)=>{
console.log('작업1: 오래걸리는 작업시작');
setTimeout(()=>{console.log('작업1: 종료');},3000);
resolve();
}
);
var k = Math.floor(Math.random()*1000) + 1;
const wakeUpTime = Date.now() + 3000;
while(Date.now()<wakeUpTime){}
longRunningTash
.then(
()=>{
console.log('작업2: 오래걸리는 작업의 다음작업');
console.log('작업2: 종료');
}
);

EX) 홀수, 짝수 출력
const k = 25;
const pm = new Promise(
(resolve, reject)=>{
if(k%2==0){ resolve('짝수입니다');
} else{ reject('홀수입니다');
}
}
);
pm
.then( (message)=>{ console.log(message); } )
.catch( (error)=>{ console.error(error); } )

printString
const printString =(string)=>{
return new Promise((resolve, reject)=>{
var k = Math.floor(Math.random()*1000)+1; // 램덤시간 생성
console.log('비동기실행 시작');
console.log('동기실행 시작');
setTimeout(()=>{ // 생성시간 후 화면에 전달된 String 데이터를 출력
console.log(string+' '+k);
console.log('비동기실행 종료');
}, k);
resolve();
// 비동기 실행 시작후 동기 실행으로 resolve() 호출
// -> then 안에 있는 ()=>{} 익명함수 실행
});
}
// promise 객체 생성 시 익명함수 안에 reject 함수 호출이 없다면 .catch 생략
printString("A").then( ()=>{
console.log('동기실행 종료');
} );
// 리턴된 promise 객체를 변수에 저장하지 않고 바로 then과 catch로 처리
// printString("A").then().catch();
/*
함수의 리턴값이 promise 객체에서 그 객체를 저장한 변수로 then과 catch 처리
let p = printString("A");
p
.then()
.catch();
*/

연속 Promise()의 then과 resolve 사용
const pm1 = new Promise((resolve, reject)=>{
resolve("first resolve");
});
pm1.then((msg)=>{
var k = Math.floor(Math.random()*1000)+1;
setTimeout(()=>{
console.log(msg);
}, k);
return new Promise((resolve, reject)=>{
resolve("second resolve");
});
}).then((msg)=>{
console.log(msg);
return new Promise((resolve, reject)=>{
resolve("third resolve");
});
}).then((msg)=>{
console.log(msg);
}).catch((error)=>{
console.error(error);
})
Promise 결과를 별도의 함수 안에서 활용할 때 많이 사용하는 방법
await
-promise의 비동기 실행 결과를 필요할 때 꺼내쓰기 위한 키워드. 함수 안에서 promise 결과를 사용해야 한다면 반드시 써야하는 키워드
const condition = true;
const promise1 = new Promise((resolve, reject)=>{
if(condition) resolve('success');
else reject('failure');
});
// await를 사용한 명령은 반드시 async로 만들어진 함수 안에서 사용해야 함
async function abcd(){
try{
const result = await promise1; // promise1 객체를 result 변수에 저장
//
console.log('1', result);
// await promise로 결과를 꺼냈다는건 resolve가 보내준 "success"을 꺼낸것이고
// 그 과정에서 오류가 발생하면 reject가 보내준 "failure" error 변수에 빋음
}catch(error){
console.error('2'+error);
// console.error의 error 함수는 log 함수와 기능이 같으며 주로 오류내용을 출력할 때 사용
}
}
abcd();

await promise의 연속 실행
const promise = new Promise((resolve, reject)=>{
resolve('first resolve');
});
async function func01(){
try{
const result = await promise;
console.log( result);
return "second resolve"; // new Promise 객체에 resolve 호출
}catch(err){
console.error(err);
}
}
func01()
.then((result)=>{console.log(result);})
.catch((error)=>{console.error(error);});
