도해Promise 실현 원리(4)-Promise 정적 방법 실현
사용 방법, 기본은 Promise 객체를 제공합니다.더 많은 프로미스에 대한 소개는 완일봉 선생님의 ES6 입문 프로미스 대상을 참고하세요.
많은 학우들이 Promise를 공부할 때 그 이유를 알면서도 그 이유를 몰라서 그 중의 용법을 이해하지 못한다.이 시리즈의 글은 간단명료함에서 깊이까지 프로미스를 점차적으로 실현하고 흐름도, 실례와 애니메이션을 결합시켜 프로미스의 용법을 깊이 이해하는 목적을 달성한다.
이 시리즈는 다음과 같은 몇 개의 장으로 구성되어 있다.
앞말
이전 섹션에서는 Promise의 원형 방법을 구현했습니다.이상 상태 증가,catch 및finally 포함.지금까지 Promise의 구현은 다음과 같습니다.
class Promise {
callbacks = [];
state = 'pending';//
value = null;//
constructor(fn) {
fn(this._resolve.bind(this), this._reject.bind(this));
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
this._handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
});
});
}
catch(onError) {
return this.then(null, onError);
}
finally(onDone) {
if (typeof onDone !== 'function') return this.then();
let Promise = this.constructor;
return this.then(
value => Promise.resolve(onDone()).then(() => value),
reason => Promise.resolve(onDone()).then(() => { throw reason })
);
}
_handle(callback) {
if (this.state === 'pending') {
this.callbacks.push(callback);
return;
}
let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected;
if (!cb) {// then
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
cb(this.value);
return;
}
let ret;
try {
ret = cb(this.value);
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
} catch (error) {
ret = error;
cb = callback.reject
} finally {
cb(ret);
}
}
_resolve(value) {
if (value && (typeof value === 'object' || typeof value === 'function')) {
var then = value.then;
if (typeof then === 'function') {
then.call(value, this._resolve.bind(this), this._reject.bind(this));
return;
}
}
this.state = 'fulfilled';//
this.value = value;//
this.callbacks.forEach(callback => this._handle(callback));
}
_reject(error) {
this.state = 'rejected';
this.value = error;
this.callbacks.forEach(callback => this._handle(callback));
}
}
다음은 Promise에서 정적 방법의 실현, 예를 들어 Promise를 소개한다.resolve、Promise.reject、Promise.all 및 Promise.race.다른 정적 방법의 실현도 유사하다.
2. 정적 방법
1、Promise.resolve && Promise.reject
앞에서 언급한 Promise 실례의 원형 방법을 제외하고 Promise는 Promise를 제공했다.resolve 및 Promise.reject 메서드.비 Promise 인스턴스를 Promise 인스턴스로 포장하는 데 사용됩니다.예를 들면 다음과 같습니다.
Promise.resolve('foo')
//
new Promise(resolve => resolve('foo'))
Promise.resolve의 매개 변수에 따라 대응하는 처리도 다르다. 만약에Promise.resolve의 매개 변수는 하나의 Promise의 실례입니다. 그러면 Promise.resolve는 변경 사항을 하지 않고 이 프로미스 실례를 되돌려줍니다. 예를 들어 상례의 문자열, 프로미스.resolve는 새 Promise 인스턴스를 반환합니다.이렇게 해서 우리가 얻은 대상이 도대체 프로미스의 실례인지 아닌지 알 수 없을 때 통일된 행위를 확보하기 위해 프로미스.resolve가 아주 유용해졌어요.다음 예를 참조하십시오.
const Id2NameMap = {};
const getNameById = function (id) {
if (Id2NameMap[id]) return Id2NameMap[id];
return new Promise(resolve => {
mockGetNameById(id, function (name) {
Id2NameMap[id] = name;
resolve(name);
})
});
}
getNameById(id).then(name => {
console.log(name);
});
위의 장면에서 우리는 자주 만날 수 있다. 요청을 줄이기 위해 데이터를 캐시한다. 우리는 id에 대응하는 이름을 얻은 후에 Id2 NameMap 대상에 저장한다. 다음에 id를 통해 id에 대응하는 name을 요청할 때 Id2 NameMap에 있는지 확인하고 있으면 대응하는name로 직접 돌아가고 없으면 비동기 요청을 해서 얻은 다음에 Id2 NameMap에 넣는다.
사실 위의 코드에 문제가 있습니다. 만약 Id2 NameMap의 값을 명중시키면 getNameById가 되돌아오는 결과는name입니다. Promise의 실례가 아니라name입니다.getNameById (id).then이 틀릴 거야.우리가 되돌아온 것이 Promise의 실례인지 알 수 없는 상황에서 Promise를 사용할 수 있습니다.포장을 위한 resolve:
Promise.resolve(getNameById(id)).then(name => {
console.log(name);
});
이렇게 되면 getNameById (id) 가 되돌아오는 것이 무엇이든지 논리에 문제가 없습니다.다음 Demo를 보십시오.
demo-Promise.resolve의 원본 코드
Promise를 구현하고 있습니다.resolve 를 시작하기 전에 매개 변수가 어떻게 나뉘는지 살펴보겠습니다.
(1) 매개변수는 Promise 인스턴스입니다.
매개변수가 Promise 인스턴스인 경우 Promise.resolve는 수정 없이 이 실례를 그대로 되돌려줍니다.
(2) 매개 변수는 thenable 대상이다
thenable 대상은 then 방법을 가진 대상을 가리킨다. 예를 들어 아래의 대상을 말한다.
let thenable = {
then: function(onFulfilled) {
onFulfilled(42);
}
};
Promise.resolve 방법은 이 대상을Promise 대상으로 바꾸고 thenable 대상의then 방법을 즉시 실행합니다.
let thenable = {
then: function(onFulfilled) {
onFulfilled(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
위 코드에서 thenable 대상의then 방법이 실행되면 대상p1의 상태는resolved로 바뀌어 마지막 then 방법이 지정한 리셋 함수를 즉시 실행하고 42를 출력합니다.
(3) 매개 변수는then 방법을 가진 대상이 아니거나 아예 대상이 아니다
만약 매개 변수가 원시 값이거나then 방법이 없는 대상이라면Promise.resolve 메서드는 resolved 상태로 새 Promise 객체를 반환합니다.
(4) 작업 매개 변수 없음
Promise.resolve 방법은 호출할 때 파라미터를 사용하지 않고 resolved 상태의Promise 대상을 직접 되돌려줍니다.
static resolve(value) {
if (value && value instanceof Promise) {
return value;
} else if (value && typeof value === 'object' && typeof value.then === 'function') {
let then = value.then;
return new Promise(resolve => {
then(resolve);
});
} else if (value) {
return new Promise(resolve => resolve(value));
} else {
return new Promise(resolve => resolve());
}
}
Promise.Reject 및 Promise.resolve 유사, 차이점Promise.reject는 항상 하나의 상태의 Rejected의 Promise 실례를 되돌려줍니다. Promise.resolve의 매개 변수가 Promise 실례라면 매개 변수에 대응하는 Promise 실례로 되돌아오기 때문에 상태가 일정하지 않습니다.
Promise.Reject의 실현 원본 코드
2、Promise.all && Promise.race
Promise.all는 프로미스 실례의 그룹을 받아들여 모든 프로미스 실례가fulfilled인 후에Promise 실례의 순서에 따라 상응하는 결과의 그룹을 되돌려줍니다.
const p1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('p1'), 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('p2'), 5000)
})
Promise.all([p1, p2]).then(rets => {
console.log(rets) // ['p1','p2']
})
Promise.all의 실현은 다음과 같다.
static all(promises) {
return new Promise((resolve, reject) => {
let fulfilledCount = 0
const itemNum = promises.length
const rets = Array.from({ length: itemNum })
promises.forEach((promise, index) => {
Promise.resolve(promise).then(result => {
fulfilledCount++;
rets[index] = result;
if (fulfilledCount === itemNum) {
resolve(rets);
}
}, reason => reject(reason));
})
})
}
Promise.all의 실현 원본 코드
Promise.race도 Promise 실례의 그룹을 받아들여 Promise와 연결합니다.all는 다르기 때문에 되돌아오는 결과는 이 Promise 실례 중 가장 먼저fulfilled이다.
const p1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('p1'), 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('p2'), 5000)
})
Promise.race([p1, p2]).then(ret => {
console.log(ret) // 'p1'
})
Promise.레이스의 실현은 다음과 같다.
static race(promises) {
return new Promise(function (resolve, reject) {
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(function (value) {
return resolve(value)
}, function (reason) {
return reject(reason)
})
}
})
}
Promise.레이스의 실현 원본 코드
3. 총결산
처음에 Promise 원본을 볼 때 then과 Resolve 함수의 운행 기리를 잘 이해하지 못하지만 마음을 가라앉히고 반대로 Promise를 실행할 때의 논리에 따라 추론하면 이해하기 어렵지 않다.여기서 반드시 주의해야 할 점은 Promise 안의 then 함수는 후속적으로 실행해야 할 코드만 등록한 것이고 진정한 실행은 Resolve 방법에서 실행된 것이다. 이 층을 정리한 다음에 원본 코드를 분석하면 훨씬 힘을 절약할 수 있다.
이제 Promise의 실현 과정을 살펴보면 주로 디자인 모델 중의 관찰자 모델을 사용했다.
이 시리즈의 도문은 Promise의 사상을 설명하는데 실현된 내용은 Promise/A+규범의 모든 요구를 완전히 만족시킬 수 없다.
4. 참고 자료
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Promise 단순화텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.