자바스크립트, 입문!

자바스크립트, 입문!

핵심만 쏙쏙, 바로 보고 실습하는 JavaScript!

21 프로미스(Promise), 비동기 처리를 더 깔끔하게

# 프로미스, 비동기 처리를 더 깔끔하게 ## 미션 프로미스(Promise)를 활용하여, 콜백지옥을 개선하시오. ## 개념 콜백을 무분별하게 중첩할 경우, 문제가 생길 수 있다. 이를 해결하기 위한 객체가 바로 프로미스다. ### 중첩된 콜백의 문제점 콜백은 중첩되면 될 수록 더럽다. 스파게티 코드가 된다. 다음 코드를 보라. 대표적인 스파게티 코드라 하겠다. 이러한 코드를 콜백 지옥(callback hell)이라 한다. ``` getData(function(data) { getMoreData(data, function(moreData) { getMoreDataAgain(moreData, function(evenMoreData) { displayData(evenMoreData); }); }); }); ``` ### 프로미스의 등장 더러운 콜백지옥을 뿌시자. 프로미스를 사용해서! 프로미스를 사용하면, 콜백지옥을 다음과 같이 개선할 수 있다. ``` getData() .then(function(data) { return getMoreData(data); }) .then(function(moreData) { return getMoreDataAgain(moreData); }) .then(function(evenMoreData) { displayData(evenMoreData); }) .catch(function(error) { console.error(error); }); ``` ### 프로미스 객체와 상태 프로미스는 객체다. 비동기 작업을 수행할 객체. 프로미스가 비동기 처리에 성공하면, resolve 콜백이 수행된다. 실패하는 경우, reject 콜백이 호출된다. 이러한 동작을 위해, 프로미스는 상태값을 갖는다. - 대기(pending): 아직 비동기 처리가 수행되지 않음 - 이행(fulfilled): 비동기 처리에 성공 - 거부(rejected): 비동기 처리에 실패 ### 프로미스 예제 코드 다음은 paymentAPI() 함수는, 결제를 위해 프로미스를 활용한 예다. 반반 확률로 성공 또는 실패하는 프로미스를 반환한다. ``` function paymentAPI(amount) { return new Promise((resolve, reject) => { // 50% 확률로 결제 성공 const isSuccess = Math.random() < 0.5; // 비동기 처리 수행 setTimeout(() => { if (isSuccess) { resolve(`[결제 완료] ${amount}원`); } else { reject('[결제 실패] 잔액이 부족합니다'); } }, 1000); // 1초 후에 결제 결과 반환 }); }; ``` ### 프로미스 호출 예 실제 호출 코드는 다음과 같이 작성했다. 9900입력으로 함수를 호출하면, 프로미스 객체가 반환된다. 그러면 1초뒤에 성공 또는 실패한다. ``` // 사용 예 paymentAPI(9900) .then((result) => { console.log(result); // [결제 완료] 9900원 }) .catch((error) => { console.log(error); // [결제 실패] 잔액이 부족합니다 }); ``` 성공했다면 resolve() 콜백이 호출되는데, 해당 콜백은 then()절 내부에 작성되어있다. 따라서 "[결제 완료] 9900"원이 출력된다. 실패했다면 reject() 콜백에 의해, catch()절 내부에 작성된 콜백이 수행된다. 따라서 "[결제 실패] 잔액이 부족합니다"가 출력된다. ## 실습 ### 기본파일 작성 promise.html ``` <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Promise</title> <!-- custom --> <link rel="stylesheet" href="promise.css"> <!-- bootstrap 5.2 --> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> <Script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> </head> <body class="container"> <h1 id="heading">프로미스</h1> <article id="practice-1"> <h2>배달앱 주문부터 식사까지</h2> <p>야심한 밤, 배가고픈 홍팍. 그는 치킨이 먹고 싶었다..</p> <ul class="list-group"> <li class="list-group-item">1. 배달앱 주문</li> <li class="list-group-item">2. 결제하기</li> <li class="list-group-item">3. 배달도착</li> <li class="list-group-item">4. 리뷰작성</li> </ul> </article> </body> </html> ``` promise.css ``` /* * CSS 관련 구글링 * 👉 site:developer.mozilla.org {연관_키워드} */ body { padding-top: 1rem; } article { padding-top: 1rem; padding-bottom: 1rem; } ``` promise.js ``` // JavaScript 관련 구글링 // 👉 site:developer.mozilla.org {연관_키워드} 'use strict'; ``` ### 콜백지옥이란 ``` // 1. 콜백 지옥(callback hell) // - 콜백 함수가 또 다른 콜백을 부르는 상황 // - 비동기 처리흐름 파악이 어려움 // 주문하기 function orderAPI(doNext) { setTimeout(() => { console.log("[주문] 완료!"); doNext(); }, 1000); } // 결제하기 function paymentAPI(doNext) { setTimeout(() => { console.log("[결제] 완료!"); doNext(); }, 1000); } // 배달하기 function deliveryAPI(doNext) { setTimeout(() => { console.log("[배달] 완료!"); doNext(); }, 1000); } // 리뷰작성 function reviewAPI(doNext) { setTimeout(() => { console.log("[리뷰] 완료!"); doNext(); }, 1000); } // 콜백을 활용한 비동기처리: 콜백 지옥 발생.. // 코드 파악이 어려움: 코드 흐름이 눈에 잘 들어오지 않음 orderAPI(() => { paymentAPI(() => { deliveryAPI(() => { reviewAPI(() => { console.log("== END =="); }); }); }); }); ``` ### 프로미스 개요 ``` // 2. 프로미스(Promise) // - 콜백 지옥을 개선하는 객체 // - 비동기 처리 흐름을 파악하기 좋음 // 👉 https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise // 프로미스 만들기 const promise1 = new Promise((resolve, reject) => { // 비동기 처리 작업.. setTimeout(() => { if (Math.random() < 0.5) { resolve("성공"); } else { reject("실패"); } }); }); console.log(promise1); // 프로미스 호출 promise.then((result) => { console.log(result) }) .catch((err) => { console.log(err) }) .finally(() => { console.log("== 끝 ==") }); ``` ### 프로미스로, 콜백지옥 개선하기 ``` // 3. 기존 콜백을 프로미스로 개선하기 // - 콜백 지옥은 기존 콜백을 직접호출해서 생김 // - 프로미스로 감싸면, 콜백 지옥을 없앨 수 있음 // 주문하기 function orderAPI() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() < 0.8) { console.log("[주문] 완료!"); resolve(); } else { reject("[주문] 실패.."); } }, 1000); }); } // 결제하기 function paymentAPI() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() < 0.8) { console.log("[결제] 완료!"); resolve(); } else { reject("[결제] 실패.."); } }, 1000); }); } // 배달하기 function deliveryAPI() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() < 0.8) { console.log("[배달] 완료!"); resolve(); } else { reject("[배달] 실패.."); } }, 1000); }); } // 리뷰작성 function reviewAPI() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() < 0.8) { console.log("[리뷰] 완료!"); resolve(); } else { reject("[리뷰] 실패.."); } }, 1000); }); } // "주문-결제-배달-리뷰"를 프로미스로 개선하여 호출 orderAPI().then(() => { return paymentAPI() }) .then(() => { return deliveryAPI() }) .then(() => { return reviewAPI() }) .catch((err) => { console.log(err) }) .finally(() => { console.log("== 끝 ==")}); ``` ## 구글링 학습 🔥 - 자바스크립트 콜백지옥 - 자바스크립트 프로미스란 - 자바스크립트 프로미스 상태값 - 자바스크립트 프로미스 resolve와 reject - 자바스크립트 프로미스 예외처리