0 에서 Promise 를 실현 하 다.
① Promise 는 하나의 클래스 또는 함수 로 내부 에 3 개의 상태 가 있 는데 각각 pending (대기), fulfilled (실행, 완성), rejected (거부, 미 완성) 이다.기본 값 은 pending 상태 입 니 다. 즉, Promise 대상 이 처음 만 들 어 졌 을 때 상 태 는 pending 이 고 pending 상 태 는 fulfilled 또는 rejected 로 전환 할 수 있 습 니 다.fulfilled 와 rejected 는 최종 상태 로 fulfilled 나 rejected 로 바 뀌 면 다른 상태 로 바 꿀 수 없습니다.
② Promise 는 대외 적 으로 then 방법 을 제공 해 야 한다.
promise.then(onFulfilled, onRejected)
선택 가능 한 인자 인 onFulfilled 와 onRejected 가 함수 가 아 닐 때 무시 해 야 합 니 다.
onFulfilled 와 onRejected 함 수 는 모두 비동기 로 실행 되 어야 합 니 다.
onFulfilled 함 수 를 호출 할 때 현재 Promise 의 값 을 매개 변수 로 입력 하고 한 번 만 호출 할 수 있 습 니 다.
onRejected 함 수 를 호출 할 때 현재 Promise 의 실패 원인 을 매개 변수 로 입력 하고 한 번 만 호출 할 수 있 습 니 다.
then 함수 의 반환 값 은 체인 호출 을 위해 Promise 입 니 다.
③ resolve Promisethen 방법 은 Promise 대상 을 만 들 고 되 돌려 줍 니 다. then 에 등 록 된 리 셋 함 수 는 여러 값 을 되 돌려 줍 니 다. 반드시 검증 해 야 합 니 다.
then 방법 이 되 돌아 오 는 promise 는 then 에서 되 돌아 오 는 함수 반환 값 x 와 같 을 수 없습니다. 그렇지 않 으 면 오 류 를 던 져 야 합 니 다.
then 반전 함수 반환 값 이 비 Promise 대상 이 라면 then 에서 돌아 오 는 promise 대상 의 resolve 방법, resolve (x) 를 사용 하면 됩 니 다.
then 리 셋 함수 가 값 x 를 Promise 대상 또는 then 방법 이 있 는 대상 이나 함수 로 되 돌려 준다 면 then 방법 으로 리 셋 을 등록 하고 Promise 나 클래스 Promise 대상 의 값 을 then 이 되 돌아 오 는 promise 의 값 으로 가 져 가 야 합 니 다. 값 이 Promise 대상 이 라면 재 귀 작업 이 필요 합 니 다.
2. Promise 실현
① 첫 번 째 규범 에 따 르 면 Promise 는 하나의 클래스 나 함수 이기 때문에 우 리 는 먼저 Promise 를 하나의 클래스 로 정의 하고 내부 에 세 가지 상태 가 있 으 며 우 리 는 이 를 상수 로 정의 한다.
var PENDING = "pending"; //
var FULFILLED = "fulfilled"; // 、
var REJECTED = "rejected"; // 、
class Promise {
constructor() {
this.state = PENDING; // Promise
}
}
② 저 희 는 Promise 를 만 들 때 하나의 함수 가 들 어 옵 니 다. 이 함 수 는 Promise 대상 을 만 들 때 바로 실 행 됩 니 다. 또한 현재 Promise 대상 을 실행 하거나 거부 하 는 두 개의 인 자 를 받 습 니 다. 즉, 현재 Promise 대상 의 상 태 를 수정 하 는 것 입 니 다.Promise 는 비동기 처리 에 사용 되 기 때문에 Promise 상태 가 완 료 될 때 비동기 작업 이 실 행 된 결 과 를 받 을 수 있 고 Promise 상태 가 완료 되 지 않 았 을 때 실패 원인 을 받 을 수 있 기 때문에 Promise 내부 에 비동기 작업 의 결과 value, 실패 원인 reason 을 저장 해 야 합 니 다.
......
class Promise {
constructor(executor) { //
......
this.value = undefined; //
this.reason = undefined; //
const resolve = (value) => {
this.value = value;
this.state = FULFILLED; // Promise
}
const reject = (reason) => {
this.reason = reason;
this.state = REJECTED; // Promise
}
try {
executor(resolve, reject); // ,
} catch(e) {
reject(e);
}
}
}
③ 여기에 또 하나의 문제 가 존재 한다. 바로 Promise 는 반드시 한 번 에 실행 되 어야 한 다 는 것 이다. Promise 의 상 태 는 pending 상태 에서 fulfilled 또는 rejected 로 바 뀌 면 더 이상 변화 가 일어나 지 않 고 fulfilled 에서 fulfilled 로 바 뀌 어도 안 된다. 즉, resolve 또는 reject 는 한 번 만 수행 할 수 있다 는 것 이다.따라서 resolve 와 reject 내 부 를 판단 해 야 합 니 다. 상태 가 바 뀌 었 다 면 더 이상 실행 하지 않 습 니 다. 예 를 들 어:
......
class Promise {
constructor(executor) { //
......
const resolve = (value) => {
if (this.state === PENDING) { // resolve, resolve
......
}
}
const reject = (reason) => {
if (this.state === PENDING) { // reject
......
}
}
......
}
}
④ Promise 에 then 함 수 를 추가 합 니 다. then 함 수 는 onFulfilled, onRejected 두 함 수 를 매개 변수 로 하여 Promise 완료 시 와 미 완성 시의 반전 함 수 를 처리 합 니 다. 함수 가 아니라면 하나의 함수 로 초기 화 합 니 다. 예 를 들 어:
class Promise {
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => { // onFulfilled ,
return value;
};
onRejected = typeof onRejected === "function" ? onRejected : (reason) => { // onRejected ,
throw reason; //
}
}
}
⑤ then 방법 은 리 셋 을 등록 하 는 과정 입 니 다. then 을 호출 한 이 Promise 대상 의 상태 가 완성 상태 로 바 뀌 면 onFulfilled 리 셋 함 수 를 실행 할 수 있 습 니 다. Promise 대상 의 상태 가 거부 상태 로 바 뀌 면 onRejected 리 셋 함 수 를 실행 할 수 있 습 니 다.그래서 리 셋 함수 의 실행 은 then 을 호출 하 는 Promise 상태 에 의존 합 니 다.또한 체인 호출 을 지원 하기 위해 then 방법 은 Promise 대상 을 되 돌려 야 합 니 다.앞의 Promise 규범 에 따라 들 어 오 는 반전 함 수 는 비동기 로 실행 되 어야 합 니 다. 여 기 는 setTimeout 으로 시 뮬 레이 션 을 합 니 다.
class Promise {
then(onFulfilled, onRejected) {
......
let promise;
switch(this.state) {
case FULFILLED: // then , Promise ,
promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
} catch(e) {
console.log(e); //
reject(e);
}
});
});
break;
case REJECTED:
promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
} catch(e) {
reject(e);
}
});
}
break;
case PENDING:
promise = new Promise((resolve, reject) => {
// TODO
});
break;
}
return promise;
}
}
⑥ then 의 Promise 대상 이 pending 상태 에 있 을 때, then 을 통 해 등 록 된 리 셋 함 수 는 즉시 실행 되 지 않 으 며, Promise 의 상태 가 최종 상태 로 변 할 때 까지 기 다 려 야 등 록 된 리 셋 함 수 를 실행 할 수 있 습 니 다.여기에 게시 구독 모드 가 포함 되 어 있다.우 리 는 먼저 리 셋 함 수 를 저장 할 수 있 습 니 다. 그러면 언제 Promise 가 최종 상태 가 될 수 있 습 니까?바로 resolve 나 reject 를 호출 할 때 입 니 다. 따라서 resolve 나 reject 를 호출 할 때 등 록 된 리 셋 함 수 를 꺼 내 실행 하면 됩 니 다.
class Promise {
constructor(executor) {
const resolve = (value) => {
if (this.state === PENDING) { // resolve, resolve
......
this.onFulfilleds.forEach(fn => fn()); // then
}
};
const reject = (reason) => {
if (this.state === PENDING) { // reject
......
this.onRejecteds.forEach(fn => fn()); // then
}
};
}
then(onFulfilled, onRejected) {
......
switch(this.state) {
case PENDING:
promise = new Promise((resolve, reject) => {
this.onFulfilleds.push(() => {
try {
let x = onFulfilled(this.value);
} catch(e) {
console.log(e); //
reject(e);
}
});
this.onRejecteds.push(() => {
try {
let x = onRejected(this.reason);
} catch(e) {
reject(e);
}
});
});
break;
}
}
}
⑦ 다음은 then 이 등록 한 리 턴 함수 의 리 턴 값 을 처리 하 는 것 입 니 다. 리 턴 함수 의 리 턴 값 은 여러 가지 상황 일 수 있 기 때문에 일반적인 값 일 수도 있 고 Promise 대상 일 수도 있 고 then 방법 을 가 진 대상 일 수도 있 으 므 로 일일이 처리 해 야 합 니 다.여기 서 우 리 는 하나의 단독 방법 으로 resolve Promise () 를 사용 하여 여러 가지 상황 을 처리 합 니 다. 예 를 들 어:
// then() Promise , x,then() Promise resolve、reject
const resolvePromise = function(promise, x, resolve, reject) {
// TODO
}
class Promise {
constructor(executor) { //
......
}
then(onFulfilled, onRejected) {
case FULFILLED:
promise = new Promise((resolve, reject) => {
......
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject); //
});
case REJECTED:
promise = new Promise((resolve, reject) => {
......
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject); //
});
case PENDING:
this.onFulfilleds.push(() => {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject); //
});
this.onRejecteds.push(() => {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject); //
});
}
}
3. resolvePromise 실현
① 리 턴 함수 리 턴 값 이 then () 방법 에서 만 든 Promise 대상 과 같 으 면 오 류 를 던 집 니 다. 이 는 자신 이 죽 을 때 까지 기다 리 는 것 과 같 습 니 다.
let p1 = new Promise((resolve, reject) => {
resolve(1);
})
let p2 = p1.then((value) => { // p2 then Promise
return p2;
});
// , Chaining cycle detected for promise #
const resolvePromise = function(promise, x, resolve, reject) {
if (promise === x) { // resolve
throw new Error("Chaining cycle detected for promise #");
}
}
② 리 셋 함수 가 Promise 대상 또는 then 방법 을 가 진 클래스 Promise 대상 또는 하나의 함수 로 되 돌아 오 면 함수 에 then 방법 이 있 을 수 있 으 므 로 then 방법 을 꺼 내 실행 해 야 합 니 다. Promise 대상 에 게 then 방법의 실행 은 해당 하 는 리 셋 함 수 를 등록 합 니 다.Promise 상태 가 최종 상태 로 바 뀌 면 대응 하 는 리 셋 함 수 를 실행 하고 리 셋 함 수 를 실행 하면 Promise 대상 의 value 값 을 받 은 다음 이 value 값 을 then 방법 으로 만 든 Promise 대상 의 value 값 으로 호출 합 니 다.
const resolvePromise = function(promise, x, resolve, reject) {
......
if ((x && typeof x === "object") || typeof x === "function") { // , then
let executed;
try {
let then = x.then; // then
if (typeof then === "function") { // then , Promise then
then.call(x, function (y) { // then , Promise , , , , Promise value
if (executed) return;
executed = true; //
resolvePromise(promise, y, resolve, reject); // Promise ,
}, function (e) {
if (executed) return;
executed = true;
reject(e);
});
} else { // then , resolve
resolve(x);
}
} catch(e) {
if (executed) return;
executed = true;
reject(e);
}
} else {
resolve(x);
}
}
4. catch 실현
catch 는 특수 한 then 방법 으로 볼 수 있 습 니 다. 내부 에서 then () 방법 을 호출 하지만 거부 하 는 리 셋 함수 만 등록 합 니 다. 이것 이 바로 then (onFulfilled, onRejected) 과 then (onFulfilled). catch (onRejected) 의 차이 입 니 다. onRejected 를 then 에 쓰 면 then 의 onFulfilled 에 오류 가 발생 했 을 때 onRejected 는 오 류 를 포착 할 수 없습니다.catch 에 쓰 면 다음 then () 방법 에 해당 하기 때문에 이전 then () 방법 에서 발생 한 오 류 를 포착 할 수 있 습 니 다.
class Promise {
catch(onRejected) {
return this.then(null, onRejected); //
}
}
총화
Promise 는 내부 에 state, value, reason 등 속성 이 있 는데 각각 현재 Promise 의 상태, 실행 성공 후의 반환 값 을 저장 하 는 데 사용 되 고 실행 실패 의 원인 이 되 며 내부 에 resolve, reject 두 가지 방법 도 제공 된다. 이 두 가지 방법 은 Promise 의 상 태 를 수정 하기 위해 매개 변수 형식 으로 실행 기, 즉 외부 로 전달 된다.Promise 는 리 셋 함 수 를 등록 하 는 데 사용 되 는 then 방법 도 제공 했다. 리 셋 을 등록 할 때 현재 Promise 의 상태 와 관련 이 있 고 최종 상태 라면 즉시 실행 하 며 대기 상태 라면 저장 하고 resolve 나 reject 방법 을 호출 할 때 리 셋 을 꺼 내 실행 하 는 것 이다.등 록 된 리 셋 함 수 는 여러 가지 값 을 되 돌려 줄 수 있 습 니 다. 일반 값 으로 되 돌아 오 면 then 에서 돌아 오 는 Promise 의 resolve 방법 으로 resolve 를 사용 하면 됩 니 다.Promise 대상 이나 then 방법 이 있 는 대상 이나 함 수 를 되 돌려 준다 면 then 방법 을 호출 하고 현재 Promise 의 값 을 받 기 위해 사용자 정의 리 셋 을 등록 해 야 합 니 다. 이 Promise 가 최종 상태 로 바 뀌 면 리 셋 을 실행 하면 value 를 받 을 수 있 습 니 다. 마지막 으로 then 이 되 돌아 오 는 Promise 의 value, 즉 resolve (x) 로 사용 할 수 있 습 니 다.전체 원본 코드 는 다음 과 같 습 니 다.
var PENDING = "pending"; //
var FULFILLED = "fulfilled"; // 、
var REJECTED = "rejected"; // 、
// then() Promise , x,then() Promise resolve、reject
const resolvePromise = function(promise, x, resolve, reject) {
if (promise === x) { // resolve
throw new Error("Chaining cycle detected for promise #");
}
if ((x && typeof x === "object") || typeof x === "function") { // , then
let executed;
try {
let then = x.then; // then
if (typeof then === "function") { // then , Promise then
then.call(x, function (y) { // then , Promise , , , , Promise value
if (executed) return;
executed = true; //
resolvePromise(promise, y, resolve, reject); // Promise ,
}, function (e) {
if (executed) return;
executed = true;
reject(e);
});
} else { // then , resolve
resolve(x);
}
} catch(e) {
if (executed) return;
executed = true;
reject(e);
}
} else {
resolve(x);
}
}
class Promise {
constructor(executor) { //
this.state = PENDING; // Promise
this.value = undefined; //
this.reason = undefined; //
this.onFulfilleds = []; // then
this.onRejecteds = []; // then
const resolve = (value) => {
if (this.state === PENDING) { // resolve, resolve
this.value = value;
this.state = FULFILLED; // Promise
this.onFulfilleds.forEach(fn => fn()); // then
}
};
const reject = (reason) => {
if (this.state === PENDING) { // reject
this.reason = reason;
this.state = REJECTED; // Promise
this.onRejecteds.forEach(fn => fn()); // then
}
};
try {
executor(resolve, reject); // ,
} catch(e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => { // onFulfilled ,
return value;
};
onRejected = typeof onRejected === "function" ? onRejected : (reason) => { // onRejected ,
throw reason; //
}
let promise;
switch(this.state) {
case FULFILLED: // then , Promise ,
promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} catch(e) {
console.log(e);
reject(e);
}
});
});
break;
case REJECTED:
promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch(e) {
reject(e);
}
});
});
break;
case PENDING:
promise = new Promise((resolve, reject) => {
this.onFulfilleds.push(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} catch(e) {
reject(e);
}
});
this.onRejecteds.push(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch(e) {
reject(e);
}
});
});
break;
}
return promise;
}
catch(onRejected) {
return this.then(null, onRejected); //
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Thymeleaf 의 일반 양식 제출 과 AJAX 제출텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.