손 으로 쓴 Promise. - 기본 적 인 Promise 를 실현 합 니 다.

전단 개발 에서 Promise 를 자주 사용 하지만 일부 사람들 은 Promise 의 원 리 를 잘 모 릅 니 다. 본 고 는 본인 이 Promise 를 공부 할 때 Promis 에 대한 인식 이기 도 합 니 다. 여러분 의 어린이 신발 에 도움 이 되 기 를 바 랍 니 다.
손 으로 쓴 Promise. - 기본 적 인 Promise 를 실현 합 니 다. 수기 Promise - 실례 방법 catch, finally 필기 Promise - 정적 방법 all, any, resolve, reject, race
Promise 를 아 는 것 부터...
/*             */
function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('willem');
        }, 1000);
    });
}

fetchData().then((data) => {
    // after 1000ms
    console.log(data); // willem
    return 'wei';
}, (err) => {}).then((data2) => {
    console.log(data2); // wei
});

위의 예 는 가장 흔히 볼 수 있 는 용법 이 라 고 할 수 있다. 사용 할 때 이상 을 처리 하여 catch 방법 을 대체 하 는 두 번 째 매개 변 수 를 더 많이 사용 할 수 있 지만 then 도 하나의 catch 문법 사탕 에 불과 하 다.
그 중에서 우 리 는 몇 가지 문장 으로 Promise 를 묘사 할 수 있다.
  • promise 는 하나의 클래스 로 구조 함수 가 하나의 함 수 를 받 아들 이 고 함수 의 두 매개 변수 도 모두 함수
  • 입 니 다.
  • 들 어 오 는 함수 에서 resolve 를 실행 하면 성공 을 표시 하고 reject 를 실행 하면 실 패 를 표시 하 며 들 어 오 는 값 은 then 방법의 리 셋 함수
  • 에 전 달 됩 니 다.
  • promise 는 then 이라는 방법 이 있 습 니 다. 이 방법 은 두 개의 매개 변수 가 있 습 니 다. 첫 번 째 매개 변 수 는 성공 한 후에 실 행 된 반전 함수 이 고 두 번 째 매개 변 수 는 실패 한 후에 실 행 된 반전 함수 입 니 다.then 방법 은 resolve 나 reject 가 실 행 된 후에 야 실 행 됩 니 다. then 방법 중의 값 은 resolve 나 reject 에 전 달 된 매개 변수
  • 입 니 다.
  • promise 지원 체인 호출
  • 상응하는 묘사 가 있 으 니, 다음은 한 걸음 한 걸음 실현 되 는 것 이다.
    단판 Promise
    1. promise 는 하나의 클래스 입 니 다. 구조 함수 가 하나의 함 수 를 받 아들 이 고 함수 의 두 매개 변수 도 모두 함수 입 니 다.
    첫 번 째 는 쉬 워 요.
    //       Promise           
    class WPromise {
        constructor(executor) {
            //     this        this     ,this     ,       
            executor(this._resolve.bind(this), this._reject.bind(this));
        }
        
        _resolve() {}
        
        _reject() {}
    }

    2. 들 어 오 는 함수 에서 resolve 를 실행 하면 성공 을 표시 하고 reject 를 실행 하면 실 패 를 표시 하 며 들 어 오 는 값 은 then 방법의 리 셋 함수 에 전 달 됩 니 다.
    성공, 실패, 이것 은 하나의 상 태 를 사용 하여 표 시 를 할 것 이 라 고 생각 하기 쉬 우 며, 실제로 Promise 는 이렇게 한다.Promise 에서 현재 상 태 를 표시 하기 위해 then 를 사 용 했 습 니 다.
  • pending、fulfilled、rejected 초기 상 태 는 성공 도 실패 상태 도 아니다.resolve 나 reject 가 업데이트 상 태 를 호출 할 때 까지 기 다 립 니 다.
  • pending 는 조작 이 성공 적 으로 완성 되 었 다 는 것 을 의미한다.
  • fulfilled 는 조작 실 패 를 의미한다.

  • 주의해 야 할 것 은 이 세 가지 상태 사이 에 두 개의 변환 관계 만 존재 한 다 는 것 이다.
  • rejected 에서 pending 로 전환 되 며, resolve 방법 으로 만 전환 이 완료 된다
  • fulfilled 에서 pending 로 전환 되 며, reject 방법 으로 만 전환 이 완료 된다
  • .
    들 어 오 는 값 은 rejected 의 반전 함수 에 전 달 됩 니 다. 어떻게 전달 합 니까?분명히 우 리 는 resolve 와 reject 의 값 을 저장 할 것 이다.
    위의 상태 와 값 을 Promise 에 추가 합 니 다.
    class WPromise {
        static pending = 'pending';
        static fulfilled = 'fulfilled';
        static rejected = 'rejected';
    
        constructor(executor) {
            this.status = WPromise.pending; //       pending
            this.value = undefined; //    this._resolve           
            this.reason = undefined; //    this._reject           
            executor(this._resolve.bind(this), this._reject.bind(this));
        }
        
        _resolve(value) {
            this.value = value;
            this.status = WPromise.fulfilled; //         
        }
        
        _reject(reason) {
            this.reason = reason;
            this.status = WPromise.rejected; //         
        }
    }

    3. Promise 는 then 이라는 방법 이 있 습 니 다. 이 방법 은 두 개의 매개 변수 가 있 습 니 다. 첫 번 째 매개 변 수 는 성공 한 후에 실 행 된 리 셋 함수 이 고 두 번 째 매개 변 수 는 실패 한 후에 실 행 된 리 셋 함수 입 니 다.then 방법 은 resolve 나 reject 가 실 행 된 후에 야 실 행 됩 니 다. then 방법 중의 값 은 resolve 나 reject 에 전 달 된 매개 변수 입 니 다.
    이 말 은 좀 길다. 주의해 야 할 것 은 이 말 then 이다. 우 리 는 Promise 가 비동기 라 는 것 을 알 고 있다. 즉, then resolve reject 들 어 오 는 함 수 는 바로 실행 할 수 없고 저장 해 야 하 며 resolve 함수 가 실 행 된 후에 야 꺼 내 서 실행 해 야 한다.
    다시 말 하면 이 과정 은 then 과 유사 하 다. 우 리 는 then 을 사용 하여 사건 을 등록 합 니 다. 그러면 언제 이 사건 들 이 실행 되 는 지 알려 줍 니까?정 답 은 resolve 방법 이 실행 되 거나 reject 방법 이 실 행 될 때 입 니 다.
    ok, 우리 의 코드 를 계속 보완 하 세 요.
    class WPromise {
        static pending = "pending";
        static fulfilled = "fulfilled";
        static rejected = "rejected";
    
        constructor(executor) {
            this.status = WPromise.pending; //       pending
            this.value = undefined; //    this._resolve           
            this.reason = undefined; //    this._reject           
            //   then      
            //          ?     Promise then        
            this.callbacks = [];
            executor(this._resolve.bind(this), this._reject.bind(this));
        }
    
        // onFulfilled          
        // onRejected          
        then(onFulfilled, onRejected) {
            //             
            //                  
            this.callbacks.push({
                onFulfilled,
                onRejected,
            });
        }
    
        _resolve(value) {
            this.value = value;
            this.status = WPromise.fulfilled; //         
    
            //       
            this.callbacks.forEach((cb) => this._handler(cb));
        }
    
        _reject(reason) {
            this.reason = reason;
            this.status = WPromise.rejected; //         
    
            this.callbacks.forEach((cb) => this._handler(cb));
        }
    
        _handler(callback) {
            const { onFulfilled, onRejected } = callback;
    
            if (this.status === WPromise.fulfilled && onFulfilled) {
                //       
                onFulfilled(this.value);
            }
    
            if (this.status === WPromise.rejected && onRejected) {
                //          
                onRejected(this.reason);
            }
        }
    }

    이때 의 Promise 는 이미 초기 형 태 를 갖 추 었 으 니, 지금 은 간단하게 테스트 해 볼 수 있다.
    function fetchData(success) {
        return new WPromise((resolve, reject) => {
            setTimeout(() => {
                if (success) {
                    resolve("willem");
                } else {
                    reject('error');
                }
            }, 1000);
        });
    }
    
    fetchData(true).then(data => {
        console.log(data); // after 1000ms: willem
    });
    
    fetchData(false).then(null, (reason) => {
        console.log(reason); // after 1000ms: error
    });

    위의 출력 결 과 를 보면 당분간 아무런 문제 가 없다.다음은 중점적으로 주목 해 야 할 체인 호출 문제 다.
    중 난점: 체인 호출 이 걸 보고 무슨 생각 을 했 는 지 모 르 겠 지만 난 어차피 jQuery 가 생각 났 어.사실 체인 호출 은 하나의 인 스 턴 스 를 되 돌려 주 는 것 일 뿐 입 니 다. 먼저 생각 나 는 것 은 바로 돌아 가 는 것 입 니 다 . 그러나 어쨌든 자신 이 정말 괜 찮 습 니까?
    우 리 는 this 에서 테스트 를 진행 해도 무방 하 다.
    function fetchData() {
        return new WPromise((resolve, reject) => {
            setTimeout(() => {
                resolve('willem');
            }, 1000);
        });
    }
    
    const p1 = fetchData().then(data1 => {return data1 + ' wei'});
    const p2 = p1.then((data2) => {console.log(data2);}); // willem         'willem wei'
    const p3 = p1.then((data3) => {console.log(data3);}); // willem         'willem wei'

    분명히 this 로 직접 돌아 가 는 것 은 틀 렸 을 것 입 니 다. 함수 의 반환 값 을 처리 해 야 합 니 다.이 럴 때 어떤 친구 가 말 할 수 있 습 니 다. 그럼 제 가 처리 하면 끝 이 잖 아 요. 제 가 then 리 턴 함수 의 집행 결 과 를 value 에 할당 하면 끝 이 잖 아 요.답 은 당연히 부정 적 이다. 이번 에는 Promise 내부 의 value 와 callbacks 의 혼란 을 야기 했다.
    그러면 우리 가 채택 한 것 은 당연히 다른 방안 이다. then return this; 이것 은 간단 한 then 데이터 의 방향 이다.간단하게 말 하면 then 함수 에서 돌아 오 는 Promise 의 value 값 은 현재 then 함수 의 onFulfilled 함수 (첫 번 째 매개 변수) 의 실행 결과 then Promise 에서 유래 합 니 다.
    우리 가 쓴 코드 를 보면 value 값 은 resolve 함수 에서 만 부 여 됩 니 다. 분명히 우 리 는 onFulfilled 가 실행 한 결 과 를 resolve 의 실행 을 통 해 다음 Promise 에 전달 할 것 입 니 다.
    체인 호출 처리 추가:
    class WPromise {
        static pending = "pending";
        static fulfilled = "fulfilled";
        static rejected = "rejected";
    
        constructor(executor) {
            this.status = WPromise.pending; //       pending
            this.value = undefined; //    this._resolve           
            this.reason = undefined; //    this._reject           
            //   then      
            //          ?     Promise then        
            this.callbacks = [];
            executor(this._resolve.bind(this), this._reject.bind(this));
        }
    
        // onFulfilled          
        // onRejected          
        then(onFulfilled, onRejected) {
            //       Promise
            return new WPromise((nextResolve, nextReject) => {
                //          Promsie resolve   reject     callback 
                //     onFulfilled       nextResolve      Promise    value 
                this._handler({
                    nextResolve,
                    nextReject,
                    onFulfilled,
                    onRejected
                });
            });
        }
    
        _resolve(value) {
            this.value = value;
            this.status = WPromise.fulfilled; //         
    
            //       
            this.callbacks.forEach((cb) => this._handler(cb));
        }
    
        _reject(reason) {
            this.reason = reason;
            this.status = WPromise.rejected; //         
    
            this.callbacks.forEach((cb) => this._handler(cb));
        }
    
        _handler(callback) {
            const { onFulfilled, onRejected, nextResolve, nextReject } = callback;
            
            if (this.status === WPromise.pending) {
                this.callbacks.push(callback);
                return;
            }
    
            if (this.status === WPromise.fulfilled) {
                //       
                //    onFulfilled , undefined  
                const nextValue = onFulfilled ? onFulfilled(this.value) : undefined;
                nextResolve(nextValue);
                return;
            }
    
            if (this.status === WPromise.rejected) {
                //          
                //      
                const nextReason = onRejected ? onRejected(this.reason) : undefined;
                nextResolve(nextReason);
            }
        }
    }

    우 리 는 다시 시작 한 예 를 가지 고 와 서 테스트 를 해 보 자.
    function fetchData() {
        return new WPromise((resolve, reject) => {
            setTimeout(() => {
                resolve('willem');
            }, 1000);
        });
    }
    
    fetchData().then((data) => {
        // after 1000ms
        console.log(data); // willem
        return 'wei';
    }, (err) => {}).then((data2) => {
        console.log(data2); // wei
    });

    좋아, 문제 없어.그러나 위의 버 전 은 처리 되 지 않 은 문제 가 있 습 니 다. onFulfilled 가 실 행 된 결 과 는 간단 한 값 이 아니 라 Promise 일 때 다음 then 은 실 행 된 후에 실 행 됩 니 다.
    Promise 기본 판 최종 판:
    class WPromise {
        static pending = 'pending';
        static fulfilled = 'fulfilled';
        static rejected = 'rejected';
    
        constructor(executor) {
            this.status = WPromise.pending; //       pending
            this.value = undefined; //    this._resolve           
            this.reason = undefined; //    this._reject           
            //   then      
            //          ?     Promise then        
            this.callbacks = [];
            executor(this._resolve.bind(this), this._reject.bind(this));
        }
    
        // onFulfilled          
        // onRejected          
        then(onFulfilled, onRejected) {
            //       Promise
            return new WPromise((nextResolve, nextReject) => {
                //          Promsie resolve   reject     callback 
                //     onFulfilled       nextResolve      Promise    value 
                this._handler({
                    nextResolve,
                    nextReject,
                    onFulfilled,
                    onRejected
                });
            });
        }
    
        _resolve(value) {
            //   onFulfilled       Promise    
            //             
            //  value instanof WPromise ,    Promise        Promise
            //     then     Promise(   Promise)
            //        value  value (   ,value  promise ,       value   )
            //    value value     ,           value.then onFulfilled  
            //    value           ,        Promise value    value value  
            if (value instanceof WPromise) {
                value.then(
                    this._resolve.bind(this),
                    this._reject.bind(this)
                );
                return;
            }
    
            this.value = value;
            this.status = WPromise.fulfilled; //         
    
            //       
            this.callbacks.forEach(cb => this._handler(cb));
        }
    
        _reject(reason) {
            if (reason instanceof WPromise) {
                reason.then(
                    this._resolve.bind(this),
                    this._reject.bind(this)
                );
                return;
            }
    
            this.reason = reason;
            this.status = WPromise.rejected; //         
    
            this.callbacks.forEach(cb => this._handler(cb));
        }
    
        _handler(callback) {
            const {
                onFulfilled,
                onRejected,
                nextResolve,
                nextReject
            } = callback;
    
            if (this.status === WPromise.pending) {
                this.callbacks.push(callback);
                return;
            }
    
            if (this.status === WPromise.fulfilled) {
                //       
                //    onFulfilled ,value  
                const nextValue = onFulfilled
                    ? onFulfilled(this.value)
                    : this.value;
                nextResolve(nextValue);
                return;
            }
    
            if (this.status === WPromise.rejected) {
                //          
                //      
                const nextReason = onRejected
                    ? onRejected(this.reason)
                    : this.reason;
                nextReject(nextReason);
            }
        }
    }

    오케이, 테스트 해 봐.
    function fetchData() {
        return new WPromise((resolve, reject) => {
            setTimeout(() => {
                resolve('willem');
            }, 1000);
        });
    }
    
    fetchData().then((data) => {
        return new WPromise(resolve => {
            setTimeout(() => {
                resolve(data + ' wei');
            }, 1000);
        });
    }, (err) => {}).then((data2) => {
        console.log(data2); // willem wei
    });

    이로써 간단 한 Promise 가 완성 되 었 습 니 다. 물론 처리 해 야 할 것 이 많 습 니 다. 예 를 들 어 이상 등 입 니 다.다음 글 은 우리 함께 다시 한 번 의 실현 을 배 워 봅 시다.
    더 보기: 상기 아 날로 그 Promise 의 전체 코드

    좋은 웹페이지 즐겨찾기