본문 바로가기
Front-end/Web

JavaScript 기초 - Promise, async function과 await

by 안녕주 2021. 2. 23.

1. Promise

01. Promise-1

  • ES6 부터 JS의 표준 내장 객체로 추가되었다.
  • ES6를 지원하는 브라우저나 Node.js에서 전역에 있는 Promise를 확인할 수 있다.

생성자를 통해서 프로미스 객체를 만들 수 있고, 생성자의 인자로 excutor 라는 함수를 이용한다.

- excutor 함수는 resolve와 reject를 인자로 가진다. (resolve, reject ) => {...}

- resolve와 reject는 함수다. resolve(), reject()

- 생성자를 통해서  프로미스 객체를 만드는 순산 pending(대기) 상태라고 한다.

new Promise(/*excutor */(resolve,reject) => {});

 

- excutor 함수 인자 중 하나인 resolve 함수를 실행하면, fulfilled(이행) 상태가 된다.

new Promise((resolve,reject) => {
    //Pending
    //처리
    resolve(); //fulfilled
});

 

- excutor 함수 인자 중 하나인 reject 함수를 실행하면, rejected (거부) 상태가 된다.

new Promise((resolve,reject) => {
    reject(); //rejected
});

 

/*
p 라는 프로미스 객체는 1000ms 후에 fulfilled 된다.
fulfilled 되는 시점에, p.then 안에 설정한 callback 함수가 실행된다.
*/

const p = new Promise((resolve, reject)=>{
    // Pending 
    setTimeout(()=>{
        resolve(); //fullfilled
    },1000);
});

p.then((/*callback*/)=>{

})

 

 

02. Promise-2

- p.then 으로 callback 함수를 지정했기 때문에 fulfilled 되면서 callback이 실행된다.

const p = new Promise((resolve, reject)=>{
    // Pending 
    setTimeout(()=>{
        resolve(); //fullfilled
    },1000);
});

p.then(()=>{
    console.log('1000ms 후에 fulfilled된다.')
})

 

- then을 설정하는 시점을 명확히 하고, 함수의 실행과 동시에 프로미스 객체를 만들면서 pending이 시작하도록 하기 위해 프로미스 객체를 생성하면서 리턴하는 함수 (p)를 만들어 함수(p) 실행과 동시에 then을 설정한다.

function p(){
    return new Promise((resolve, reject)=>{
        // Pending 
        setTimeout(()=>{
            resolve(); //fullfilled
        },1000);
    });
}
p().then(()=>{
    console.log('1000ms 후에 fulfilled 됩니다.');
});

 

- promise 객체가 rejected 되는 시점에 p.catch 안에 설정한 callback 함수가 실행된다.

function p(){
    return new Promise((resolve, reject)=>{
        // Pending 
        setTimeout(()=>{
            reject(); //rejected
        },1000);
    });
}
p().then(()=>{
    console.log('1000ms 후에 fulfilled 됩니다.');
}).catch(()=>{
    console.log('1000ms 후에 rejected 됩니다.');
});

 

- excutor의 resolve 함수를 실행할 때 인자를 넣어 실행하면, then의 callback 함수의 인자로 받을 수 있다.

function p(){
    return new Promise((resolve, reject)=>{
        // Pending 
        setTimeout(()=>{
            resolve('hello'); //인자 넣기
        },1000);
    });
}
p().then((message)=>{ //message , 비동기...머..?
    console.log('1000ms 후에 fulfilled 됩니다.',message);
}).catch(()=>{
    console.log('1000ms 후에 rejected 됩니다.');
});

- excutor의 reject 함수를 실행할 때 인자를 넣어 실행하면, catch의 callback 함수의 인자로 받을 수 있다.

function p(){
    return new Promise((resolve, reject)=>{
        // Pending 
        setTimeout(()=>{
            reject('error') //인자 넣기
        },1000);
    });
}
p().then((message)=>{
    console.log('1000ms 후에 fulfilled 됩니다.',message);
}).catch((reason)=>{
    console.log('1000ms 후에 rejected 됩니다.', reason);
});

 

- error 객체 사용

function p(){
    return new Promise((resolve, reject)=>{
        // Pending 
        setTimeout(()=>{
            reject(new Error('bad')) //인자 넣기
        },1000);
    });
}
p().then((message)=>{
    console.log('1000ms 후에 fulfilled 됩니다.',message);
}).catch((error)=>{
    console.log('1000ms 후에 rejected 됩니다.', error);
});

 

 

03. Promise-3

- fulfilled되거나 rejected된 후에 최종적으로 실행할 것이 있다면, .finally()를 설정하고, 함수를 인자로 넣는다.

function p(){
    return new Promise((resolve, reject)=>{
        // Pending 
        setTimeout(()=>{
            reject(new Error('bad')) //인자 넣기
        },1000);
    });
}
p().then((message)=>{
    console.log('1000ms 후에 fulfilled 됩니다.',message);
})
.catch((error)=>{
    console.log('1000ms 후에 rejected 됩니다.', error);
})
.finally(()=>{
    console.log('end');
});

 

- 보통 비동기 작업을 할 때, callback 함수를 인자로 넣어 로직이 끝나면 callback 함수를 호출한다. 이런 경우 함수가 아래로 진행되지 않고, callback 함수 안으로 진행된다.

function c(callback){
    setTimeout(()=>{
        callback();
    },1000);
}

c(()=>{
    console.log('1000ms후에 callback 함수가 실행')
});

c(()=>{
    c(()=>{
        c(()=>{
            console.log('3000ms후에 callback 함수가 실행')
        });
    });
});

 

-then 함수에서 다시 프로미스 객체를 리턴하는 방법을 통해 체이닝 하면, 비동기 작업을 순차적으로 아래로 표현할 수 있다. then에 함수를 넣는 여러 방법을 확인해보자.

function p(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve();
        },1000);
    });
}

 
p().then(()=>{ //p()에서 1초 걸림, .then()에서 1초 뒤
    return p();
})
.then (()=>p()) //2초뒤
.then(p) //43초 뒤
.then(()=>{ //4초뒤
    console.log('4000ms 뒤에 fulfilled된다.')
})

 

 

04. Promise-4

- value 가 프로미스 객체인지 아닌지 알 수 없는 경우, 사용하면 연결된 then 메서드를 실행한다. 

value가 프로미스 객체면, resolve된 then 메서드를 실행

value가 프로미스 객체가 아니면, value를 인자로 보내면서 then 메서드를 실행한다.

Promise.resolve(/* value */);

Promise.resolve(new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('foo');
    },1000);
})).then((data)=>{
    console.log('프로미스 객체인 경우, resolve된 결과를 받아서 then이 실행',data);
});

Promise.resolve('bar').then(data =>{
    console.log('then 메서드가 없는 경우, fulfilled 된다.',data);
})

 

- Promise.reject 를 사용하면, catch로 연결된 rejected 상태로 변경된다.

Promise.reject(/* value */);

Promise.reject(new Error('reason'))
    .then(error=>{})
    .catch(error=>{
        console.log(error);
    });

 

- 프로미스 객체를 여러개 생성하여, 배열로 만들어 인자로 넣고 Promise.all을 실행하면, 배열의 모든 프로미스 객체들이 fulfilled 되었을 때, then의 함수가 실행된다. then의 함수의 인자로 프로미스 객체들의 resolve 인자값을 배열로 돌려준다.

//Promise.all([프로미스 객체들]);

function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve();
        },ms);
    })
}

Promise.all([p(1000), p(2000), p(3000)]).then(()=>{
    console.log('모두 fulfilled된 이후에 실행됩니다.');
});

 

- 프로미스 객체를 여러개 생성하여, 배열로 만들어 인자로 넣고 Promise.race를 실행하면, 배열의 모든 프로미스 객체들중 가장 먼저  fulfilled 된 것으로, then의 함수가 실행된다. then의 함수의 인자로 가장 먼저 fulfilled된 프로미스 객체의 resolve 인자값을 돌려준다.

//Promise.all([프로미스 객체들]);

function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(ms);
        },ms);
    })
}

Promise.race([p(1000), p(2000), p(3000)]).then((message)=>{
    console.log('모두 fulfilled된 이후에 실행됩니다.',message);
});

 

 


2. async function과 await

01.async function과 await-1

async function 함수이름(){}
const 함수이름 = async() => {}
// Promise 객체를 리턴하는 함수
function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(ms);
        },ms);
    });
}

// Promise 객체를 이용해서 비동기 로직을 수행할 때
p(1000).then(ms =>{
    console.log(`${ms} ms후에 실행된다.`);
});

// Promise 객체를 리턴하는 함수를 await 로 호출하는 방법
const ms = await p(1000);
console.log(`${ms} ms후에 실행된다.`);

//SyntaxError: await is only valid in async function

 

- await를 사용하는 경우, 항상 async 함수 안에서 사용되어야한다.

function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(ms);
        },ms);
    });
}

 (async function main(){
const ms = await p(1000);
console.log(`${ms} ms 후에 실행된다.`);
 })();

 

- Promise 객체가 rejected된 경우의 처리를 위해 try catch를 이용

function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            reject(new Error('reason'));
        },ms);
    });
}

 (async function main(){
     try{
        const ms = await p(1000);
     }
     catch(error){
        console.log(error);
     }
 })();

 

- async function에서 return 되는 값은 Promise.resolve 함수로 감싸서 리턴된다.

function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            reject(new Error('reason'));
        },ms);
    });
}

async function asyncP(){
    return 'Mark';
}

 (async function main(){
     try{
        const name = await asyncP();
        console.log(name);
     }
     catch(error){
        console.log(error);
     }
 })(); 

 //Mark 출력

 

 

02.async function과 await-2

- async 에서 await p(1000)로 부르기 -> resolve

function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{ //진행
            resolve(ms);
            // reject(new Error('reason'));
        },ms);
    });
}

async function asyncP(){
    const ms = await p(1000); //P를 먼저 해결하러 떠남
    return 'Mark: '+ ms;
}

 (async function main(){
     try{
        const name = await asyncP();
        console.log(name);
     }
     catch(error){
        console.log(error);
     }
 })(); 

 //Mark: 1000 출력

- async 에서 await p(1000)로 부르기 -> reject

function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{ //진행
            // resolve(ms);
            reject(new Error('reason'));
        },ms);
    });
}

async function asyncP(){
    const ms = await p(1000); //P를 먼저 해결하러 떠남
    return 'Mark: '+ ms;
}

 (async function main(){
     try{
        const name = await asyncP();
        console.log(name);
     }
     catch(error){ //error
        console.log(error);
     }
 })(); 

 //에러 호출

 

-try,catch, finally 사용

function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{ //진행
            resolve(ms);
            // reject(new Error('reason'));
        },ms);
    });
}

async function asyncP(){
    const ms = await p(1000); //P를 먼저 해결하러 떠남
    return 'Mark: '+ ms;
}

 (async function main(){
     try{
        const name = await asyncP();
        console.log(name);
     }
     catch(error){ //error
        console.log(error);
     }
     finally{
         console.log('end');
     }
 })(); 

 

- 비동기 처리를 Promise와 async await비교

function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{ //진행
            resolve(ms);
            // reject(new Error('reason'));
        },ms);
    });
}

//Promise
p(1000),then(()=>p(1000)).then(()=>p(1000)).then(()=>{
    console.log('3000ms 후에 실행');
});

//async await
(async function main(){
    await p(1000);
    await p(1000);
    await p(1000);
    console.log('3000ms 후에 실행');
})();

 

- Promise.all 과 Promise.race

function p(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{ //진행
            resolve(ms);
            // reject(new Error('reason'));
        },ms);
    });
}

/*Promise.all
(async function main(){
    const results = await Promise.all([p(1000),p(2000),p(3000)]);
    console.log(results); //[ 1000, 2000, 3000 ]출력
})();
*/

//Promise.race
(async function main(){
    const results = await Promise.race([p(1000),p(2000),p(3000)]);
    console.log(results); //1000 출력
})();

댓글