JavaScript : Promise 의 활용 예제
1. 일반적인 동기 처리
'use strict';
// 1. 기본적인 함수 호출 (동기 처리)
function test1() {
return 'my name is...';
}
const username = test1();
console.log(username);
console.log('test');
// 출력결과 (순차적)
// my name is...
// test
2. 일반 동기 처리를 (순차적 처리) 비동기로 바꾸는 방법 중 하나는 Promise 를 사용하는 것이다.
'use strict';
// 동기 처리는 순차적으로 이루어지기 때문에, 해당 처리가 끝나야만 다음 처리로 갈 수 있다.
// Promise 사용하기
// 함수 안에 Promise 를 선언함과 동시에 리턴하게 만든다.
function test() {
return new Promise((resolve, reject) => {
resolve('my name is...');
reject(new Error('no access..'));
});
}
// test() 을 실행시켜 Promise 객체를 리턴 받는다.
// Promise 특성을 이용하여, 비동기 처리로 바꿔놓는다.
// Promise 로 정의된 처리는 실행하겠다고 약속하고, 다음 처리 순서로 넘어가는 것이다(비동기)
const getUserName = test();
getUserName.then(console.log);
console.log('test');
// 출력 결과
// test
// my name is...
3. 동기 처리를 비동기 처리로 바꾸는 또 하나의 방법은 async 를 사용하는 것이다.
'use strict';
// async 를 사용하기
// 번거롭게 Promise 를 정의할 필요없이, async 를 정의해주면 지정한 함수 블럭이 Promise 로 변환된다.
async function test() {
return 'my name is...';
}
const getUserName = test();
getUserName.then(console.log);
console.log('test');
// 출력 결과
// test
// my name is...
4. Promise를 사용하여 체인 걸기
'use strict';
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
// 호출되었을 때 내부 처리를 실행하겠다고 약속하고 밑으로 내려감.
async function test1() {
await delay(2000); // 함수에 await 를 걸어서 딜레이가 끝날 때 까지 기다려 줌.
return 'my name is test1...';
}
// 호출되었을 때 내부 처리를 실행하겠다고 약속하고 밑으로 내려감.
async function test2() {
await delay(1000); // 함수에 await 를 걸어서 딜레이가 끝날 때 까지 기다려 줌.
return 'my name is test2...';
}
// 각 메서드가 서로 연관이 없을 때. 처리되는 순서대로 출력
test1().then(console.log);
test2().then(console.log);
console.log('test');
// 출력 결과
// test
// my name is test2
// my name is test1
// ====================================================================
// 여기서 부터는 프로미스로 걸어둔 처리 끼리, 서로 연관이 있을 때 묶어서 처리하는 방법이다.
// 복수의 프로미스가 전부 실행이 다 끝난 후 (여기서는 3초 후) 출력이 되도록 한다.
function showAllTest() {
return test1().then((a) => {
return test2().then((b) => `result:: ${a}, ${b}`);
});
}
console.log('test');
showAllTest().then(console.log);
// 출력 결과
// test
// result:: my name is test1..., my name is test2...
// test1() 함수의 딜레이 2초 끝나고, test2() 함수 1초. 총 3초 걸림.
// 그러나, 프로미스로 체인을 중첩해서 많이 걸어놓으면, 콜백 지옥이라 불리는 문제가 발생할 수 있다.
// 리턴한 인자 값을 또 다시 리턴하고, 복수의 처리에 정상 처리가 되었을 때, 안됐을 때의 처리를
// 다 구현하게 되면 끝이 없는 계산식 코드가 되어버려서 가독성도 떨어지고 유지보수도 힘들어지는.
// 프로미스도 많은 체인을 걸어놓으면 그와 같은 문제가 발생할 수 있다.
5. 다중의 체인을 걸지 않고 Promise 를 사용하는 방법
'use strict';
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
// 호출되었을 때 내부 처리를 실행하겠다고 약속하고 밑으로 내려감.
async function test1() {
await delay(2000); // 딜레이가 끝날 때 까지 기다려 줌.
return 'my name is test1...';
}
// 호출되었을 때 내부 처리를 실행하겠다고 약속하고 밑으로 내려감.
async function test2() {
await delay(1000); // 딜레이가 끝날 때 까지 기다려 줌.
return 'my name is test2...';
}
// 함수에 async 를 걸어놓고, 해당 함수 안에서 실행하는 함수에 await 를 걸어놓는다.
// 비동기처리를 동기처럼 호출한 순서대로 실행하되, 코드가 간단해 진다.
async function showAllUser() {
const myName1 = await test1();
const myName2 = await test2();
return `${myName1}, ${myName2}`;
}
showAllUser().then(console.log);
console.log('test');
// 출력 결과
// test
// my name is test1..., my name is test2
// 출력 시간은 3초
6. 그러나 test1, test2 메서드 사이에 연관성이 없고, 먼저 처리되는 것에 문제가 없다면 (예를 들면, 값을 이용해서 화면을 바꾼다거나..)
Promise 들을 병렬로 처리하도록 하여, 처리 속도를 빠르게 할 수 있다.
즉, test1, test2 를 비동기 실행을 걸어두고, console("test") 를 실행하고 하고,
test1, test2 중 처리가 끝난 순서대로 값을 받을 수 있다.
방법은, 함수에 async 를 걸어두면 Promise 가 되는데, 해당 함수를 리턴 시켜서 변수로 받으면 Promise 가 된다.
리턴 받은 Promise 에 await 를 걸어두면, 복수의 Promise 가 병렬적으로 실행되어, 먼저 처리가 끝나는 것을 기다릴 필요가 없다.
'use strict';
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
// 호출되었을 때 내부 처리를 실행하겠다고 약속하고 밑으로 내려감.
async function test1() {
await delay(2000); // 딜레이가 끝날 때 까지 기다려 줌.
return 'my name is test1...';
}
// // 호출되었을 때 내부 처리를 실행하겠다고 약속하고 밑으로 내려감.
async function test2() {
await delay(1000); // 딜레이가 끝날 때 까지 기다려 줌.
return 'my name is test2...';
}
// test1() 를 실행시켜서 리턴 값으로 프로미스 객체를 받는다.
// tset2() 를 실행시켜서 리턴 값으로 프로미스 객체를 받는다.
// myName1Promise, myName2Promise 에 둘다 await 를 걸어두면,
// 프로미스 실행이 끝날 때 까지 기다리지만, 2개의 함수를 동시에 실행 (병렬) 시킨다.
// 따라서 이 함수의 처리에 걸리는 총 시간은 2초. test1 딜레이를 1000 로 해놓으면 총 1초 걸림.
async function showAllUser() {
const myName1Promise = test1();
const myName2Promise = test2();
const myName1 = await myName1Promise;
const myName2 = await myName2Promise;
return `${myName1}, ${myName2}`;
}
showAllUser().then(console.log);
console.log('test');
// 출력 결과 (총 2초가 걸린다)
// test
// my name is test2..., my name is test1...
7. 위의 코드를 더 깔끔하게 하는 방법은, Promise 내장 API 를 사용하는 것이다. (Promise.all, Promise.race)
// 실행 속도를 빠르게 하고 싶다면 위와 같이 하면 되지만, 코드가 난잡함으로..
// Promise 객체에서 제공하는 all API 를 사용한다.
// Promise.all() ==> Promise 배열을 전달하게 되면, 모든 프로미스들이 병렬적으로 다 처리가 끝날 때 까지 모아줌.
// 리턴 값은 배열로 나오므로, 스트링으로 출력을 하려면 array.join();
function showAllUserTest() {
return Promise.all([test1(), test2()]).then((members) => members.join());
}
// showAllUserTest().then(console.log);
// console.log('test');
// 만약, 프로미스 배열에서 처리가 가장 먼저 끝난 하나를 찾고 싶다면
// Promise.race() 를 사용한다.
function getFastOne() {
return Promise.race([test1(), test2()]);
}
getFastOne().then(console.log);
console.log('test');
// 출력 결과
// test
// my name is test2...
유투브 강의를 보고 정리 했지만, 정확하게 이해했다고는 생각되지 않는다.
Promise 를 사용해야 하는 상황을 만들어서 사용해 봐야겠다.
'JavaScript' 카테고리의 다른 글
JavaScript - 콜백 함수 (0) | 2020.09.23 |
---|---|
JavaScript : 반복문 (0) | 2020.09.21 |
JavaScript - Array (0) | 2020.09.17 |
JavaScript 기초5 : function expression (0) | 2020.09.15 |
JavaScript 기초4 : function (default parameter, rest parameter) (0) | 2020.09.15 |