[JS] promise 직접 만들어 본 사람?

준리·2022년 9월 23일
0

비동기 프로그래밍

목록 보기
6/10
post-thumbnail

씹고 뜯고 맛봐야 비로소 이해할 수 있다. promise 너도 그렇다.

✨Promise 함수 직접 구현 DIY✨

//다음과 같이 실행되는 나만의 Promise 함수를 작성하시오.

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    const now = Date.now();
    if (now % 2 === 0)
      resolve(console.log('fulfill', now));
    else reject(new Error('어디로?'));
  }, 1000);
});


console.log('111>>', p);
setTimeout(() => console.log('222>>', p), 2000);

function Promise(cb) {

}

🎈문제정의

  1. 빌트인 객체인 new promise를 사용하지 않는다.

  2. 생성자함수를 사용한다.
    const p = new HjPromise((resolve, reject) => { new를 사용했기에.

    생성자 함수(constructor function)와 일반 함수에 기술적인 차이는 없습니다. 다만 생성자 함수는 아래 두 관례를 따릅니다.
    -함수 이름의 첫 글자는 대문자로 시작합니다.
    -반드시 'new' 연산자를 붙여 실행합니다.

  3. p가 가진 값은 프로미스 객체처럼 보여야한다는 것

  • 특정 상태 Pending / resolve / reject (settled) 를 가진다.
  1. HjPromise 함수는 resolvereject 함수(메서드) 를 가지고 있다.

🎃나만의 Promise 구현


const p = new HjPromise((resolve, reject) => {
  setTimeout(() => {
    const now = Date.now();
    if (now % 2 === 0)
      resolve(console.log('fulfill', now));
    else reject(new Error('어디로?'));
  }, 1000);
});


console.log('111>>', p);
setTimeout(() => console.log('222>>', p), 2000);



function HjPromise(cb) {
    this.state = "<pending>";

    const resolve = (res) => {
        console.log("성공>>>", res);
        this.state = "<resolve>";
    };
    const reject = (error) => {
        console.log("실패>>>", error);
        this.state = "<reject>";

        return this.state;
    };

    cb(resolve, reject);
}

생성자 함수는 빈 객체를 생성한다.

const p = new HjPromise();

function HjPromise(cb) {}

console.log("111>>", p);

이렇게만 찍으면 111>> HjPromise {} 이렇게 나오게 된다.
빈 객체가 생성된 것이다.
이 객체에 상태값을 주기위해선 this를 할당하고 this에 새로운 프로퍼티를 추가해서 this를 수정하고 반환하는 식으로 작동 시킵니다.

this에 새로운 프로퍼티를 추가한다.

function HjPromise(cb) {
    this.state = "<pending>";
}

console.log("111>>", p);

//결과값
// 111>> HjPromise { state: '<pending>' }

HjPromise 객체에 state 프로퍼티가 추가된 것을 볼 수 있다. 이 상태가 우리가 promise를 말할 때 아무일도 시작안한 상태 pending 값이다.

callback 함수 resolve, reject 만들자

    // callback을 위한 메서드 생성
    const resolve = (res) => {
        console.log("성공===>", res);
        this.state = "<resolve>";
    };

    const reject = (error) => {
        console.log("실패===>", error);
        this.state = "<reject>";
    };

여기서 중요한점 resolve & reject 함수를 작성할 때는 반드시 화살표 함수를 사용해야한다. 왜냐하면 화살표 함수의 경우 상위 스코프의 this를 바인딩 하기 때문인데, 여기서 function(){} 을 사용하면 상황에 따른 바인딩이 되긴하지만, 대체로 전역공간의 this, 또는 메소드 호출 시 메소드 내부의 this를 바인딩한다. 하지만 화살표 함수는 화this라는 변수 자체가 존재하지 않기 때문에 그 상위 환경에서의 this를 참조하게 된다.

Resolve
if (now % 2 === 0) resolve(console.log("fulfill", now));

resolve 함수를 탄 인자는 resolve 함수의 매개변수로 들어와서 res로서 활용된다.
성공의 값을 찍어주고 this.state 를 resolve로 재할당한다.

Reject
else reject(new Error("어디로?"));

Reject 함수를 탄 인자는 Reject 함수의 매개변수로 들어와서 error로서 활용된다.
new Error로 던져진 값을 에러와 함께 출력한다.

cb함수의 활용

function HjPromise(cb) {
    //this에 새로운 프로퍼티 추가
    this.state = "<pending>";
 
  ...(중략)

    cb(resolve, reject);

여기서 우린 매개변수로 받아온 cb(콜백함수)에 이 함수(메서드)들을 태워서 보내야한다. 여기 cb는 어떻게 생긴 놈인지 알고 있는가? 다시 위로 올라가보자.

const p = new HjPromise((resolve, reject) => {
    setTimeout(() => {
        const now = Date.now();
        if (now % 2 === 0) resolve(console.log("fulfill", now));
        else reject(new Error("어디로?"));
    }, 1000);
});

여기서 cb를 추려낼 수 있는 사람?
여기서 cb는 HjPromise의 인자이다.

(resolve, reject) => {
    setTimeout(() => {
        const now = Date.now();
        if (now % 2 === 0) resolve(console.log("fulfill", now));
        else reject(new Error("어디로?"));
    }, 1000);
}


//

cb(resolve, reject);

이만큼이 콜백함수이다. 약간은 cb(resolve, reject); 이 모습과 닮아있지 않은가? 타고타고타고타고타고 들어가는 함수형 프로그래밍을 이해해야한다.

마지막으로 return this.state를 해주면 원하는 결과를 출력할 수 있다.


성공시!

실패시!

정답에 근접한 코드

function myPromise(cb) {
    myPromise.prototype.then = (tcb) => {
        myPromise.prototype.thenFn = tcb;
        return this;
    };

    myPromise.prototype.catch = (ccb) => {
        myPromise.prototype.catchFn = ccb;
        return this;
    };

    const resolve = (succ) => {
        console.log("RESOLVE!!👍🏽", succ);
        this.state = "resolve";
        this.thenFn(succ);
    };

    const reject = (error) => {
        console.log("REJECT!!👎🏽", error);
        this.state = "reject";
        this.catchFn(error);
    };

    cb(resolve, reject);

    if (new.target) this.state = "pending";
}

결론

Promise 가지고 있는 resolve와 reject의 쓰임에 대해 이해하니 promise가 좀 더 가까워진 기분이다. 앞으로 new Promise를 사용할 때도 내가 만든 코드마냥 내부를 이해하며 사용할 수 있겠지. 그러길빈다.

출처

SSAC 영등포 교육기관에서 풀스택 실무 프로젝트 과정을 수강하고 있다. JS전반을 깊이 있게 배우고 실무에 사용되는 프로젝트를 다룬다. 앞으로 그 과정 중의 내용을 블로그에 다루고자 한다.

profile
트렌디 풀스택 개발자

0개의 댓글