ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Javascript] 프로미스
    Javascript 2024. 4. 11. 10:09

    - 콜백 지옥

    setTimeout(() => {
      console.log(1);
      setTimeout(() => {
        console.log(2);
          setTimeout(() => {
            console.log(3);
            setTimeout(() => {
              console.log(4);
              setTimeout(() => {
                console.log(5);
              }, 500);
            }, 500);
          }, 500);
      }, 500);
    }, 500);
    • 연속적으로 비동기 코드를 써야 하는 경우
    • 위와 같이 콜백 함수 안에 또 다른 콜백 함수를 넣어야 하는 상황 발생 - 콜백 지옥
    • 횟수가 많을수록 가독성도 낮아지고 직관성이 떨어짐
    • 실전에서는 더더욱 복잡하고 난해해짐

    프로미스 promise : (보통 시간이 걸리는) 어떤 과정 이후 주어진 동작을 실행할 것이란 약속

    중첩된 비동기 코드를 직관적이고 연속적인 코드로 작성할 수 있도록 함

    let promise = new Promise(function(resolve, reject) { //실행함수는 프로미스 생성자 함수에 인자로 전달
      // executor (실행자, 실행함수)
    });

     

    new Promise에 전달되는 함수는 executor(실행자, 실행 함수) 라고 부릅니다. executor는 new Promise가 만들어질 때 자동으로 실행

    executor의 인수 resolve와 reject는 자바스크립트에서 자체 제공하는 콜백입니다. 

    대신 executor에선 결과를 즉시 얻든 늦게 얻든 상관없이 상황에 따라 인수로 넘겨준 콜백 중 하나를 반드시 호출해야 합니다.

    • resolve(value) — 일이 성공적으로 끝난 경우 그 결과를 나타내는 value와 함께 호출
    • reject(error) — 에러 발생 시 에러 객체를 나타내는 error와 함께 호출

     executor는 자동으로 실행되는데 여기서 원하는 일이 처리됩니다. 처리가 끝나면 executor는 처리 성공 여부에 따라 resolve나 reject를 호출합니다.

    한편, new Promise 생성자가 반환하는 promise 객체는 다음과 같은 내부 프로퍼티를 갖습니다.

    • state — 처음엔 "pending"(보류)이었다 resolve가 호출되면 "fulfilled", reject가 호출되면 "rejected"로 변합니다.
    • result — 처음엔 undefined이었다 resolve(value)가 호출되면 value로, reject(error)가 호출되면 error로 변합니다.

    const borrow = 20;
    
    // 빌린 돈의 10%를 더해 값겠다는 약속
    // reject는 지금 사용하지 않음
    const payWith10perc = new Promise((resolve, reject) => {
      resolve(borrow * 1.1);
    });
    
    payWith10perc
    .then(result => {
      console.log(result + '만원'); //22만원
    });

    생성자 Promise

    • 새로운 약속을 하는 코드
    • 인자로 받는 콜백함수의 첫 번째 인자 resolve ( 이름은 관례 ) - 약속 이행 성공시, 반환할 값 넣어 실행

    프로미스 인스턴스(만들어진 약속)의 then 메서드

    • resolve를 통해 ( 약속대로 ) 반환된 결과를 인자로 하는 콜백 함수를 넣음
    • ⭐ 또 다른 프로미스를 반환 - 체이닝 가능
    const borrow = 20;
    
    const payWith10perc = new Promise((resolve, reject) => {
      setTimeout(() => {
        if (Math.random() < 0.5) {
          // 💡 돈을 갚을 수 없게 되었을 때
          reject('사업 망함'); // 보통 실패사유나 관련 설명을 넣음
        }
        resolve(borrow * 1.1);
      }, 1000); // 1초 후 갚겠음
    });
    
    payWith10perc
    .then(result => {
      console.log(result + '만원');
    }
    // 💡 두 번째 인자로 reject를 받는 콜백을 넣을 수 있지만
    // 아래처럼 catch로 진행하는 것이 더 깔끔함
    )
    .catch(msg => {
      console.error(msg);
    })
    .finally(() => {
      console.log('기한 종료');
    });

     

    생성자 Promise

    • 인자로 받는 콜백함수의 두 번째 인자 reject ( 이름은 관례 ) - 약속 이행 실패시, 반환할 값 넣어 실행
    • reject가 실행되면 resolve는 무시됨

    프로미스 인스턴스의

    • catch 메서드 : reject를 통해 ( 실패로 인해 ) 반환된 결과를 인자로 하는 콜백 함수를 넣음
    • finally 메서드 : 성공하든 실패하든 실행할 콜백 함수 - 필요할 때만 사용
    • then과 더불어 메서드 체이닝으로 사용'
    // ⭐ then은 연속적으로 메서드 체이닝 가능
    
    new Promise((resolve) => {
      resolve(2);
    })
    .then(i => i * 4) //8
    .then(i => i - 3) //5
    .then(i => i ** 2) //25
    .then((i) => {
      console.log(i); //25
    });

     

     

    여러 프로미스를 병렬 처리하기 위한 프로미스의 정적 메서드

    // 다섯 주자들이 동시에 질주
    // 데드라인(밀리초) 안에 들어오지 못하면 탈락
    let DEADLINE = 1450;
    
    function getRunPromise (name) {
      return new Promise((resolve, reject) => {
        const time = 1000 + Math.random() * 500;
    
        setTimeout(() => {
          if (time < DEADLINE) {
            console.log(`🚩 ${name} 도착 - ${(time)/1000}초`);
            resolve({name, time});
    
          } else {
            reject((`${name} 시간초과`));
          }
        }, time);
      });
    }

     

    1. all

    • 프로미스의 배열을 받아 동시에 진행
    • 모두 성공하면 resolve된 값들을 배열로 반환 - then으로 받음
    • 하나라도 실패하면 catch 실행
    // 한 명이라도 탈락하면 전체 탈락
    Promise.all(
      '철수,영희,돌준,정아,길돈'
      .split(',')
      .map(getRunPromise)
    )
    .then(console.log)
    .catch(console.error)
    .finally(() => {
      console.log('- - 경기 종료 - -');
    });

    // 성공시 탑3 표시
    Promise.all(
      '철수,영희,돌준,정아,길돈'
      .split(',')
      .map(getRunPromise)
    )
    .then(arr => {
      return arr.sort((a, b) => {
        return a.time - b.time
      })
      .map(({name}) => name)
      .splice(0, 3)
      .join(', ');
    })
    .then(top3 => {
      console.log(`탑3: ${top3}`);
    })
    .catch(console.error)
    .finally(() => {
      console.log('- - 경기 종료 - -');
    });

    2. allSettled 

    • 주어진 프로미스들의 결과를 배열로 출력
    • 실패 유무 관계없이 then으로 배열 반환
    Promise.allSettled(
      '철수,영희,돌준,정아,길돈'
      .split(',')
      .map(getRunPromise)
    )
    .then(console.log)
    // ⚠️ catch는 동작하지 않음
    .finally(() => {
      console.log('- - 경기 종료 - -');
    });

    Promise.allSettled(
      '철수,영희,돌준,정아,길돈'
      .split(',')
      .map(getRunPromise)
    )
    .then(arr => {
      return {
        succ: arr.filter(result => {
          return result.status === 'fulfilled'
        }),
        fail: arr.filter(result => {
          return result.status === 'rejected'
        })
      }
    })
    .then(res => {
      res.succ.sort((a, b) => {
        return a.value.time - b.value.time;
      });
      console.log(
        `완주: ${res.succ.length}명 (1등: ${res.succ[0].value.name})`
      );
      console.log(
        `탈락: ${res.fail.length}명`
      );
    })
    
    .finally(() => {
      console.log('- - 경기 종료 - -');
    });

    3. any

    • 가장 먼저 성공한 프로미스의 결과를 then으로 반환
    • 모두 실패시 오류 발생
    Promise.any(
      '철수,영희,돌준,정아,길돈'
      .split(',')
      .map(getRunPromise)
    )
    .then(console.log)
    // ⚠️ 모두 실패해도 catch는 동작하지 않음
    .finally(() => {
      console.log('- - 경기 종료 - -');
    });

    4. race : 성공이든 실패든 첫 결과물 then 또는 catch로 반환

    // 다섯 주자들이 선택한 도착지로 질주
    // 도착지에 '꽝'이 있으면(50% 확률) 실패
    function getBombRunPromise (name) {
      return new Promise((resolve, reject) => {
        const time = 1000 + Math.random() * 500;
    
        setTimeout(() => {
          console.log(`🚩 ${name} 도착 - ${(time)/1000}초`);
          if (Math.random() < 0.5) {
            resolve((`🙌 ${name} 승리!`));
          } else {
            
            reject((`💣 ${name} 꽝!`));
          }
        }, time);
      });
    }

    'Javascript' 카테고리의 다른 글

    [Javascript] 비동기 홀짝 문제  (0) 2024.04.15
    [Javascript] async & await  (0) 2024.04.11
    [Javascript] 비동기식 프로그래밍  (0) 2024.04.10
    [Javascript] 프로토타입과 상속  (0) 2024.04.10
    [Javascript] Prototype 프로토타입  (0) 2024.04.09
Designed by Tistory.