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);});