31-1. 정의
31-2. 장점
31-3. 상태의 유형
31-4. 메소드(method)
32. 옵셔널 체이닝(Optional Chaining)
31. 프로미스(promise)
31-1. 정의
Javascript 비동기 처리에 사용되는 객체.
비동기적으로 처리되는 작업의 결과를 나중에 처리하기 위해 사용.
주로 서버에서 받아온 data를 화면에 표시할 때 사용.
31-2. 장점
비동기 처리 시점을 명확히 표현할 수 있음.
연속된 비동기 처리 작업을 유연하게 수정, 삭제, 추가하기가 편함.
비동기 처리 작업 시 성공/실패 등의 상태 정보를 갖게 됨.
코드의 유지 보수성이 증가.
31-3. 상태의 유형
매개변수로 사용.
Pending: 작업이 아직 완료되지 않은 상태.
Resolve: 작업이 성공적으로 완료된 상태.
Reject: 작업이 실패한 상태.
31-4. 메소드(method)
then(): 작업이 성공적으로 완료된 경우에 호출.
catch(): 작업이 실패한 경우에 호출.
finally(): 최종적으로 처리할 일을 수행할 경우에 호출.
then() 메소드와 catch() 메소드는 '메소드체인'을 이용하여 여러 개의 작업을 연속적으로 처리 가능.
const 프로미스객체 = () => new Promise ( ( resolve , reject ) => { }); |
비동기 처리 작업이 완료될 때까지 기다리지 않고 다른 작업을 수행하는 방식. 비동기 처리는 대개 네트워크 요청, 파일 처리, 타이머와 같이 시간이 오래 걸리는 작업을 수행할 때 사용. 이를 통해 사용자 경험을 향상시키고, 애플리케이션의 성능을 향상시킬 수 있음. 공부한 내용 중 비동기 처리의 예시: 1. setTimeout 함수: 지정된 시간이 지난 후에 코드를 실행. 애니메이션 및 타이머와 같은 기능을 구현할 수 있음. 2. 이벤트 핸들러: 클릭, 마우스 오버, 키보드 입력 등과 같은 사용자 동작을 비동기적으로 처리할 수 있음. 이를 통해 사용자는 페이지와 상호작용하면서 다른 작업도 동시에 수행할 수 있음. 3. Promise: Promise 객체를 사용하여 비동기적인 작업을 처리할 수 있음. Promise는 작업이 완료될 때까지 기다리지 않고, 다른 작업을 수행할 수 있도록 도와줌. |
예) console에 '3초후 알림이 뜨는 타이머'를 만드려는 경우.
function runInDelay(seconds){ return new Promise((resolve, reject) => { if (!seconds || seconds<0) { reject (new Error('seconds가 0보다 작음')); // seconds가 없거나, 0보다 작다면 Error가 발생. } setTimeout(resolve, seconds*1000); // ( 1000 = 1초 ) }); } runInDelay(3) .then(()=>console.log('타이머가 완료되었습니다.')) // 메소드체인. 가독성을 위해 온점(.)을 다음 줄에 내려서 사용. .catch(console.error) .finally(()=>console.log('모든 작업이 끝났습니다.')); |
예) console에 '🐤=>🐔=> 🥚=>🍳'가 차례대로 출력되는 경우
function fetchEgg(chicken){ return Promise.resolve(`${chicken} => 🥚`); // Promise가 성공하면 실행 } function fryEgg(egg){ return Promise.resolve(`${egg}=>🍳`); // Promise가 성공하면 실행 } function getChicken(){ return Promise.resolve(`🐤=>🐔`); // Promise가 성공하면 실행 } // 비동기 처리 실행 예정. getChicken() .then((chicken) => { return fetchEgg(chicken); }) .then((egg)=>fryEgg(egg)) .then((friedegg) =>console.log(friedegg)) .catch(()=>'🐥'); // 바로 위의 코드를 축약형으로 사용할 수 있는 방법. getChicken() .then(fetchEgg) .then(fryEgg) .then(console.log) .catch(()=>'🐥'); |
예) 1초 후에 '🍌', 3초 후에 '🍎', Error 발생시 '오렌지는 다팔림'을 출력하는 각각의 function을 생성.
이후, '🍌' 와 '🍎'를 동시에 Array로 출력해 console에 저장. (동시에 출력 시 총 4초+a정도의 시간이 소요)
function getBanana(){ return new Promise((resolve)=>{ setTimeout(()=>{ resolve('🍌'); }, 1000); }); } function getApple(){ return new Promise((resolve)=>{ setTimeout(()=>{ resolve('🍎'); }, 3000); }); } function getOrange(){ return Promise.reject( new Error('오렌지는 다팔림')); } getBanana() .then((banana)=> getApple() .then((apple)=>[banana, apple])) .then(console.log); // banana, apple을 동시에 array로 출력 |
Promise.all
병렬적으로 한 번에 모든 Promise를 실행하는 기능.
여러 개의 console을 출력 시 우선적으로 Promise.all이 출력.
Promise.all([getBanana(), getApple()]) .then((fruits)=>console.log('Promise.all: ', fruits)); |
예) Promise.all에 getOrange()를 추가.
Promise.all([getBanana(), getApple(), getOrange()]) .then((fruits)=>console.log('Error: ', fruits)) .catch(console.log); |
'Error: 오렌지는 다팔림 at getOrange (3.프로미스3.html:30:35) at 3.프로미스3.html:49:51'
라는 Error내용이 먼저 출력된 후, 나머지가 순차적으로 출력됨.
하나의 요소가 Error일 경우에도 전체적인 Error가 발생.
Promise.allSettled
Error가 발생하더라도, 모든 promise들의 결과를 반환.
Promise.allSettled([getBanana(), getApple(), getOrange()]) .then((fruits)=>console.log('Promise.allSettled: ', fruits)) .catch(console.log); |
Promise.race
주어진 Promise 중에서 가장 빨리 수행되는 것을 출력.
Promise.race([getBanana(), getApple()]) .then((fruit) => console.log('Promise.race: ', fruit)); // fruits가 아닌, fruit |
32. 옵셔널 체이닝(Optional Chaining)
비교적 최근에 추가된 문법. (ECMA Script 11버전에 추가)
null 또는 undefined를 확인할 때 쓰이는 연산자.
객체의 중첩된 속성 값에 접근할 때 발생할 수 있는 오류를 방지하기 위해 사용.
옵셔널 체이닝 연산자( ?. )는 왼쪽 피연산자 값이 null 또는 undefined인 경우,
바로 undefined를 반환하며 오류를 방지.
코드의 안정성을 높일 수 있음.
예) 옵셔널 체이닝(Optional Chaining)을 사용하지 않았을 때 오류가 발생하는 경우.
const user = { name: 'John', address: { city: 'New York', zipcode: 10001 } }; console.log(user.address.country.code); // TypeError: Cannot read property 'code' of undefined |
user 객체에는 address 프로퍼티가 존재하고, address 객체에는 country 프로퍼티가 존재하지 않음.
따라서 user.address.country.code와 같은 코드는 TypeError를 발생.
예) 위의 오류에서 옵셔널 체이닝(Optional Chaining)을 사용하여 Error 방지를 하는 경우.
const user = { name: 'John', address: { city: 'New York', zipcode: 10001 } }; console.log(user?.address?.country?.code); // undefined |
Error가 발생하지 않지만, 해당 프로퍼티의 값이 undefined로 평가됨.
논리 연산자(&&, ||)를 이용하는 경우
const obj1 = {name:'김사과'}; const obj2 = {name:'반하나', lover:'이메론'}; if (obj1 || obj2 ){ console.log('둘 다 또는 둘 중에 하나가 true'); // 둘 다 또는 둘 중에 하나가 true } let result = obj1 & & obj2 ; // obj1과 obj2 모두 값이 존재하여 true. and 연산이므로 최종값은 true. console.log(result); // lover: "이메론" name: "반하나" result = obj1 | | obj2 ; // obj1과 obj2 모두 값이 존재하여 true. or 연산이므로 최종값은 true. console.log(result); // name: "김사과" // obj2는 코드에서 선언만 되고 실제로 사용되지 않았기 때문에 result 변수에 할당되지 않음. function changeLover(obj){ if(!obj.lover){ throw new Error('애인이 없어'); // obj에 lover라는 필드값이 없다면, '애인이 없어'라는 Error를 출력. } obj.lover = '애인이 바뀜'; // 반대로 lover라는 필드값이 있다면, '애인이 바뀜'을 출력 } function makeNewLover(obj){ if(obj.lover){ throw new Error('애인이 있어'); // obj에 lover라는 필드값이 있다면, '애인이 있어'라는 Error를 출력. } obj.lover = '새로운 애인이 생김'; } obj1.lover & & changeLover(obj1 ); // obj1.lover의 값이 없으므로 false. → changeLover(obj1)이 사용될 필요가 없음. console.log(obj1); // name: "김사과" obj2.lover & & changeLover(obj2 ); // obj2.lover:'이메론'. true. → changeLover(obj2)에서 '애인이 바뀜'으로 변경. console.log(obj2); // lover: "애인이 바뀜" name: "반하나" |
null 또는 undefined가 이용되는 경우
let item = {price:1000}; const price = item && item .price; // item 객체를 확인한 후 true라면, 순차적으로 item.price를 확인. and 연산자를 실행했을 때 결과적으로 둘 다 값이 있어서 true → price에서 1000이라는 값을 출력. console.log(price); // 1000 |
let item2 = {price:1000}; const price2 = item2 ?. price; // item2 && item2.price; 와 동일한 코드. console.log(price2); // 1000 |
Javascript에 data가 없을때의 기본값(default parameter)은 undefined이다.
예)
print()값에 data가 없으면 undefined 대신에 'hello'가 출력.
function print(message){ const text = message || 'hello'; console.log(text); // text를 출력 시 print 안의 'message'가 출력되거나, 'hello'가 출력됨. } print('안녕'); // 안녕 print(); // hello print(undefined); // hello print(null); // hello print(''); // hello |
let num = 0; console.log(num ||'-1'); // -1. num = 0이므로 false. '-1'은 true. → or연산자에 따라 true인 '-1'이 출력. console.log(num ?? '-1'); // 0. and연산자에 따라 0이 출력. |
TIP
* day7에 배우는 내용들은 직접적으로 data를 가져다 뿌릴 수 있게 만드는,
프론트엔드 개발자의 핵심적인 부분이므로 중요함.
* 주석
// 한줄
/* ... */ 여러줄
/** ... */ JSDoc 주석 (실제로 실무에서 많이 사용하는 주석처리방법.)
JSDoc 사용법:
@param {*} path 문자
@returns 파일객체
...