개발/JavaScript

2023.04.12 JavaScript의 프로미스,옵셔널체이닝

상달군 2023. 4. 12. 15:03
728x90

목차

1. JavaScript의 프로미스(Promise)

  • 프로미스를 사용시 장점
  • 사용법
  • 프로미스를 리턴받는 객체

2. JavaScript의  옵셔널 체이닝(Optional Chaining) 연산자

 


1. JavaScript의 프로미스(Promise)

  • 자바스크립트 비동기 처리에 사용되는 객체
     (- 비동기란? -> 시간이 걸리는 처리를 잠깐 멈춰두고 다하고 다시 시작)
  • 주로 서버에서 받아온 데이터를 화면에 표시할 때 사용

1-1. 프로미스를 사용시 장점

  • 비동기 처리 시점을 명확하게 표현할 수 있다.
  • 연속된 비동기 처리 작업을 수정, 삭제, 추가하기 편하고 유연하게 만들수 있다.
  • 코드의 유지 보수성이 증가한다. 

1-2. 프로미스 사용법

                                                                       성공       실패
                                                                      ----------  -------
    const 프로미스객체 = () => new Promise((resolve, reject) => {

    });


    ✔비동기 처리가 성공 또는 실패 등의 상태 정보를 갖게 되는데 
    resolve가 호출된 경우: 성공 (뭔가 처리가 잘 처리 된것)
    reject가 호출된 경우: 실패

 

1-3. 프로미스를 리턴받은 객체

    .then(정상적으로 프로미스 객체가 리턴되었다면 필요한 일을 수행 하는메소드)
    .catch(에러 객체가 리턴되었다면 에러를 처리)
    .finally(최종적으로 처리할 일을 수행)

 

프로미스 예시 1)

    <h2>프로미스1</h2>
    <script>
        function runInDelay(seconds){
            return new Promise((resolve, reject)=> {
                if(!seconds || seconds < 0){
                    reject(new Error('seconds가 0보다 작다!'));
                }
                setTimeout(resolve, seconds * 1000);// 밀리초기때문에 1000을 곱해주면 초단위가 된다.
            });
        }

        //메소드 체이닝(프로미스는 이러한 형태로 체이닝을 이용하여 많이들 쓴다.)
        // 매개변수인 3초를 준 소스
        // runInDelay(3)
        //     .then(()=>console.log('타이머가 완료 되었습니다.'))
        //     .catch(console.error)
        //     .finally(() => console.log('모든 작업이 끝났습니다.'));

        // (실패해보기) 매개변수seconds를 넣지 않으면 값이 없기때문에 함수의 if문 안으로 걸러지게 된다.  
        // 매개변수인 초를 주지 않았을때 소스 (에러가 발생한다)
        runInDelay()
            .then(()=>console.log('타이머가 완료 되었습니다.'))
            .catch(console.error)
            .finally(() => console.log('모든 작업이 끝났습니다.'));
    </script>

주석 처리 되어있는 소스에서 매개변수로 전달한 3초 후에 성공한 내용이 결과값으로 보인다. 

실패한 소스를 실행시켰을시에는 아래와같이 에러가 전달되게된다.


프로미스2 예시)

    <script>
        function fetchEgg(chicken) {
            return Promise.resolve(`${chicken} => 🥚`);
        }

        function fryEgg(egg){
            return Promise.resolve(`${egg} => 🍳`);
        }

        function getChicken(){
            return Promise.resolve(`🐤 => 🐓`);
            //return Promise.reject(new Error('치킨집 망함.'));
        }

        getChicken()
            .then((chicken) => {
                return fetchEgg(chicken);
            })
            .then((egg) => fryEgg(egg))
            .then((friedEgg)=> console.log(friedEgg))
            .catch(()=> '🐥'); // catch는 위치가 중요하다. 에러가 발생했을때 멈추는게아니고 밑에 then이 있다고 하면 then에 값을 가지고 간다.

        // 위 코드 축약형 
        // getChicken()
        //     .then(fetchEgg)
        //     .then(fryEgg)
        //     .then(console.log)
        //     .catch(()=> '🐥');

    </script>


프로미스3 예시)

    <script>
        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('오렌지는 다 팔림!!'));
        }

        // 후 처리 메소드 사용
        // 바나나와 사과 동시에 가져오기 
        // 순차적으로 처리 -> 총 4초가 걸림
        // 바나나와 사과를 배열에 저장해서 콘솔에 출력  
        getBanana()
            .then((banana)=>
                getApple()
                    .then((apple) => [banana, apple]))
                    .then(console.log);
        
        // Promise.all (병렬적으로 실행하는것)
        // 병렬적으로 한번에 모든 Promise들을 실행 
        Promise.all([getBanana(), getApple()])
            .then((fruits)=>console.log('Promise.all:', fruits));

        // all의 특징: 하나라도 실패하면 전체가 실패 한다. 
        Promise.all([getBanana(), getApple(), getOrange()])
            .then((fruits)=> console.log('Error:', fruits))
            .catch(console.log);

        // Promise.allSettled
        // 에러가 발생하더라도 모든 프로미스들의 결과를 반환 받을수 있다. 
        Promise.allSettled([getBanana(), getApple(), getOrange()])
            .then((fruits)=>console.log('Promise.allSettled:', fruits))
            .catch(console.log);

        // Promise.race
        // 주어진 프로미스 중에서 가장 빨리 수행된 것을 출력해주는 메소드
        Promise.race([getBanana(), getApple()])
            .then((fruit)=>console.log('Promise.race:', fruit));


2. JavaScript의  옵셔널 체이닝(Optional Chaining) 연산자

  • 우리가 배우는 문법중 제일 최근에 추가된 애
  • ECMA Script 11버전에 추가 된 내용
  • null 또는 undefined를 확인할 때 쓰이는 연산자
  • ?. , ??

예시 )
    let dog = {} //값이 비어있는 dog
    
    dog && dog.name && dog.age // 값이 비어있는걸 확인 하는 방법 
    dog?.dog.name //dog이 있니?.dog의 name
    dog.name?.age 

    <script>
        // 논리 연산자 (&&, ||)
        const obj1 = {name:'김사과'};
        const obj2 = {name:'반하나', lover:'이메론'};
        const bool1 = false;

        if(obj1 || obj2){// obj1,obj2둘다 값이 존재 하기때문에 true
            console.log('둘중 하나는 true');
        }

        let result = obj1 && obj2;// obj1가 참이고 넘어가서 obj2를 확인해서 obj2가 참이면 obj2를 result로 값을 저장한다. obj1이 거짓이면 뒤로 obj2는 확인조차 하지 않고 obj1을 저장하게 된다.
        console.log(result);

        result = obj1 || obj2;// obj1이 참이면 둘중 하나만 참이면 되니깐 굳이 obj2까지 갈필요가 없어서 obj1이 result에 저장된다.
        console.log(result);

        function changeLover(obj){
            if(!obj.lover){
                throw new Error('애인이 없어!');
            }
            obj.lover = '애인이 바뀜';
        }

        function makeNewLover(obj){
            if(obj.lover){
                throw new Error('애인이 있어!');
            }
            obj.lover = '새로운 애인이 생김';
        }

        console.log('-----------');
        obj1.lover && changeLover(obj1);// obj1에는 lover이 존재 하지 않기 때문에 changeLover함수가 실행 조차 되지 않는다. 그래서 obj1의 값이 그냥 출력 된다. 
        console.log(obj1);
        console.log('-----------');
        obj2.lover && changeLover(obj2);
        console.log(obj2);
        console.log('-----------');

        // null 또는 undefined인 경우를 확인할 때 
        let item = {price:1000};
        const price = item && item.price;// item객체가 존재 하는지 확인하고 item의 price객체를 price객체에 저장
        console.log(price);
        console.log('-----------');

        // 기본값을 설정 
        // 자바스크립트의 default parameter: undefined이다.
        function print(message){
            const text = message || 'hello';
            //print('안녕'): message에 "안녕"이 존재 하기 때문에 hello로 가지 않는다. 
            //print(): message에 존재 하지 않기 때문에 hello로 출력 
            console.log(text);
        }

        print('안녕');      // 안녕
        print();            // hello
        print(undefined);   // hello
        print(null);        // hello
        print('');          // hello
        console.log('-----------');

        let item2 = {price: 1000};
        const price2 = item2?.price; //=> 'item && item.price'랑 같은 이야기
        console.log(price2);
        console.log('-----------');

        let banana = {name:'반하나', lover:{name:'오렌지'}};

        function printLoverName(obj){
            const loverName = obj?.lover?.name;
            console.log(loverName);
        }

        printLoverName(banana);
        console.log('-----------');
        
        //let num = null;
        let num = 0;
        console.log(num || '-1'); // num은 0이기 때문에 false 그래서 '-1'이 출력된다.
        console.log(num ?? '-1');//null, undefined 이라면 대체값을 출력
        // ?? = 대체값 (=앞이 false라면 뒷에 값으로 대체 해줘라) 
        console.log(banana.lover?.name??'이메론');

    </script>

728x90