본문 바로가기
Web/Node.js

03. timeout, promise, async

by 사라리24 2024. 4. 23.
SMALL

1. timeout

  

 

  • 동기식 (순차적 실행)
    프로그램 흐름에 시간(노드)이 걸려있어도 일단 마무리하고 다음으로 프로그램 진행
  
       < js >

       
        function func1(){
            for(let i=0; i<10000000000; i++);
            return 10;
        }

        function func2(){
            return func1() + 10;
        }

        function func3(){
            return func2() + 10;
        }

        console.log('프로그램이 시작됩니다.')
        const result = func3();
        console.log(result);
 
 
       </js >
  
 프로그램이 시작됩니다
30

 

  • 비동기식 (동시 다발적 실행)
    프로그램을 실행할 때 시간이 걸리거나 대기시간이 있다면 다음 문장을 미리하고 다시 돌아옴
 
      < js >

               //timeout
               function timeout() {
                console.log('1번 문장 실행!');
                setTimeout(() => {
                    console.log('2번 문장 실행!');
                }, 3000)  //3초 후의 실행 // 화살표함수: 비동기
                console.log('3번 문장 실행!');
            }
   
            timeout();
 
       </js >
  
1번 문장 실행!
3번 문장 실행!
2번 문장 실행!

 

  • 문제
    주어진 초가 지나면 callback 함수를 호출하는 함수 작성해보자
    (단 주어진 초가 0보다 작으면 에러 발생, callback 함수가 없으면 에러 발생) 
  
      < js >

        function run(callback, seconds){
            if (!callback) { //콜백함수가 없어서 false라면
                throw new Error('callback 함수가 없습니다');
            }
            if (!seconds || seconds < 0) { //초가 넘어오지 않거나 초가 0보다 작다면
                throw new Error('seconds는 0보다 커야함');
            }
            setTimeout(callback, seconds); //콜백함수, 초 넘겨주기
        }

        // run 실행 : ( 화살표함수:익명함수, 3초) 
        run(() => { console.log('타이머 완료!'); }, 3000); //3초 뒤에 '타이머 완료'
       //run(() => { console.log('타이머 완료!'); }, -3000); //에러
 
       console.log('----------------------------')

        // 오류처리(3000 입력)
        try {
            run(() => { console.log('타이머 완료!'); }, 3000); /3초 뒤에 '타이머 완료'
 
        } catch (error) {//에러를 발생하는 문장
            console.log(error);
            console.log('에러발생 후 정상적인 종료');
        }
 
       console.log('----------------------------')
 
        // 오류처리(-3000 입력
        try {
            run(() => { console.log('타이머 완료!'); }, -3000); /에러
        } catch (error) {//에러를 발생하는 문장
            console.log(error);
            console.log('에러발생 후 정상적인 종료');
        }
       </js >
  
 
/3초 뒤/ 타이머 완료!
에러(주석처리)
---------------------------------------------

/3초 뒤/  타이머 완료!

---------------------------------------------
Error: seconds는 0보다 커야함
    at run (C:\Sarr\KDT\Web\JavaScript\Day6\1_timeout.js:40:23)
    at Object.<anonymous> (C:\Sarr\KDT\Web\JavaScript\Day6\1_timeout.js:51:13)
    at Module._compile (node:internal/modules/cjs/loader:1369:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1427:10)
    at Module.load (node:internal/modules/cjs/loader:1206:32)
    at Module._load (node:internal/modules/cjs/loader:1022:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at node:internal/main/run_main_module:28:49
에러발생 후 정상적인 종료
타이머 완료!

 

2. Promise

  - 비동기 (특정작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있음)
  - 작업을 다루는 객체

 

  • 프로미스 상태
    - 대기: 비동기 작업이 아직 수행되지 않은 상태
    - 이행: 비동기 작업이 성공적으로 완료된 상태. resolve() 호출
    - 거부: 비동기 작업이 실패한 상태. reject() 호출

  

 
        const myPromise = new Promise((resolve, reject) => {
            // 비동기 작업 수행
            // 작업이 성공하면 resolve() 호출
            // 작업이 실패하면 reject() 호출
            });
 

        myPromise
            .then((result) => {
                // 성공했을 때의 처리
            })
            .catch((error) => {
                // 실패했을 때의 처리
            });
  
 
 

 

  •  원래 함수 (  Promise 전 )
 
 
        //콜백지옥 (원래)
        getUserInfo(userid,(user)=>{
            getPosts(user.id, (posts=>{
                displayPosts(posts);
            }, (error)=> {
                handleError(error);
            });
        }, (error)=> {
            handleError(error);
        });
 
 
        //바꿔보기
        getUserInofo(userid)
            .then((user)=>{
                return getPosts(user.id);
            })
            .then((posts) => {
                displayPost(posts);
            })
            .catch((error)=>{
                handleError(error);
            });
 
  

 

  • Promise로 바꿔보기
  
      < js >

 
            function run(callback, seconds){
                if (!callback) {
                    throw new Error('callback 함수가 없습니다');
                }
                if (!seconds || seconds < 0) {
                    throw new Error('seconds는 0보다 커야함');
                }
                setTimeout(callback, seconds);
            }
 
 
              [Promise로 바꿔주기]
              _ 콜백함수 겹쳐쓰지 않아도 됨
              _ 가독성이 좋음
 
 
            function run(seconds) {
                return new Promise((resolve, reject) => {
                    if (!seconds || seconds < 0) {
                        reject(new Error('seconds가 0보다 작음!'));
                    }
                    setTimeout(resolve, seconds);
                })
            }

            run(3000)
                .then(() => console.log('타이머 완료!')) //성공했다면
                .catch(console.error) //오류라면
                .finally(() => console.log('프로그램 종료!')); //끝냈다면
 
       </js >
  
 
/3초 뒤/

타이머 완료!
프로그램 종료!

 

  • Promise 활용(1)
 
      < js >
 
        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()
            .catch(() => '🐔')
            .then(fetchEgg) //getChicken()성공시 fetchEgg()호출!
            .then(fryEgg) //fetchEgg()성공시 fryEgg()호출!
            .then(console.log); //fryEgg() 실행!
 
       </js >
  
첫번째 결과 : 🐓=>🍗=>🥚=>🍳
두번째 결과 :  🐔=>🥚=>🍳


-----------------------------------------

.catch(() => '🐔') 두번째인 경우
🐔 =>🍳

.catch(() => '🐔') 세번째인 경우
🐔

 

  • Promise 활용(2)
  
      < js >

        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('오렌지 없음!'));
        }

       </js >
  
 
 /4초 뒤/
[ '🍌', '🍎' ]  

 

  • Promise 활용(3)
 
      < js >

        // Promise.all: 병렬적으로 한 번에 Promise들을 실행
        Promise.all([getBanana(), getApple()])
            .then((fruits) => console.log('all', fruits)); //3초 뒤 //all [ '🍌', '🍎' ]
 
       </js >
  
/3초 뒤/
all [ '🍌', '🍎' ]

/4초 뒤/
[ '🍌', '🍎' ]  

 

  • Promise 활용(4)
  
      < js >

        // Promise.race: 주어신 Promise중에 제일 빨리 수행된 것이 실행
        Promise.race([getBanana(), getApple()])
            .then((fruit) => console.log('race', fruit)); //race 🍌
 
       </js >
  
 
/ 먼저 실행/
race 🍌 

/3초 뒤/
all [ '🍌', '🍎' ]

/4초 뒤/
[ '🍌', '🍎' ]  

 

  • Promise 활용(5)
 
      < js >

        // promise all은 하나의 promise라도 실패하면 에러로 처리
        // 하나라도 실패하면 걍 catch로 가버림
        Promise.all([getBanana(), getApple(), getOrange()])
            .then((fruits) => console.log('all', fruits))
            .catch(console.log);
 
       </js >
  
Error: 오렌지 없음!
    at getOrange (C:\Sarr\KDT\Web\JavaScript\Day6\4_promise-all.js:18:35)
    at Object.<anonymous> (C:\Sarr\KDT\Web\JavaScript\Day6\4_promise-all.js:40:39)
    at Module._compile (node:internal/modules/cjs/loader:1369:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1427:10)
    at Module.load (node:internal/modules/cjs/loader:1206:32)
    at Module._load (node:internal/modules/cjs/loader:1022:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at node:internal/main/run_main_module:28:49

/ 먼저 실행 /
race 🍌 


/ 3초 뒤 /
all [ '🍌', '🍎' ]


/ 4초 뒤 /
[ '🍌', '🍎' ]  

 

  • Promise 활용(5)
  
      < js >

        // settled는 여러 프로미스를 병렬적으로 처리하되 하나의 프로미스가 실패해도 무조건 이행
        Promise.allSettled([getBanana(), getApple(), getOrange()])
            .then((fruits) => console.log('all', fruits))
            .catch(console.log);
 
       </js >
  
 
Error: 오렌지 없음!
    at getOrange (C:\Sarr\KDT\Web\JavaScript\Day6\4_promise-all.js:18:35)
    at Object. (C:\Sarr\KDT\Web\JavaScript\Day6\4_promise-all.js:40:39)
    at Module._compile (node:internal/modules/cjs/loader:1369:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1427:10)
    at Module.load (node:internal/modules/cjs/loader:1206:32)
    at Module._load (node:internal/modules/cjs/loader:1022:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at node:internal/main/run_main_module:28:49

/ 먼저 실행 /
race 🍌 


/ 3초 뒤 /
all [ '🍌', '🍎' ]


/ 상태 추가 /
all [
  { status: 'fulfilled', value: '🍌' },
  { status: 'fulfilled', value: '🍎' },
  {
    status: 'rejected',
    reason: Error: 오렌지 없음!
        at getOrange (C:\Sarr\KDT\Web\JavaScript\Day6\4_promise-all.js:18:35)
        at Object.<anonymous> (C:\Sarr\KDT\Web\JavaScript\Day6\4_promise-all.js:47:54)
        at Module._compile (node:internal/modules/cjs/loader:1369:14)
        at Module._extensions..js (node:internal/modules/cjs/loader:1427:10)
        at Module.load (node:internal/modules/cjs/loader:1206:32)
        at Module._load (node:internal/modules/cjs/loader:1022:12)
        at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
        at node:internal/main/run_main_module:28:49
  }
]

/ 4초 뒤 /
[ '🍌', '🍎' ]  



 

3. async / await 

- 자바 스크립트에서 비동기 코드를 더 쉽게 작성하고 관리할 수 있는 기능
- 비동기 작업이 순차적으로 실행되는 것처럼 코드를 작성할 수 있음
- async 함수는 항상 promise를 반환하여, await 키워드는 async 함수 내에서만 사용

 

  • async 활용(1)
    * 비동기 함수를 순차적으로 실행하기
     - 방법: 순차적으로 실행한 후에 묶어서 호출
     - 사용이유: 비동기라 하더라도 순차적으로 실행해야 하는 경우가 많음
  
       < js >

            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('오렌지 없다!'));
            }

            // 바나나와 사과를 같이 가지고 오는 async 함수 만들기
            // 방법: 순차적으로 실행한 후에 묶어서 호출
            // 비동기라 하더라도 순차적으로 실행해야 하는 경우가 많음
            async function fetchFruits() {
                const banana = await getBanana();
                // 비동기함수 getBanna실행값이 banana에 담김
                const apple = await getApple();
                // 비동기함수 getApple실행값이 banana에 담김
                return [banana, apple];
            }

            fetchFruits().then((fruits) => console.log(fruits))
            // 정상적으로 끝났다면 fruits 출력
 
       </js >
  
[ '🍌', '🍎' ]

 

  • async 활용(2) _ Promise-egg 코드 바꿔보기
 
      < js >

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

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

        function getChicken() {
            return Promise.reject(new Error('치킨을 가지고 올 수 없음!'));
        }

        async function makeFriedEgg() {
            let chicken;
            try {
                chicken = await getChicken()
            } catch {
                chicken = '🐔';
                const egg = await fetchEgg(chicken);
                return fryEgg(egg);
            }
        }

        makeFriedEgg().then(console.log)
 
       </js >
  
🐔=>🥚=>🍳

 

'Web > Node.js' 카테고리의 다른 글

06. 버퍼(buffer), 스트림(Steam)  (0) 2024.04.24
05. Console, This, file  (0) 2024.04.23
04. JSON  (0) 2024.04.23
02. 이터레이터, 이터러블, 스프레드  (0) 2024.04.19
01. Node.js  (0) 2024.04.19