Promise constructs and state declarations
1. Promise is used with the new keyword, so it should be implemented with a constructor or class
class HSPromise {
constructor() {
}
}
Copy the code
2. Define the three state types
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
Copy the code
3. Set the initial status
Class HSPromise {constructor() {// initial state is pending this.status = pending; this.value = null; this.reason = null; }}Copy the code
Resolve and reject methods
1. According to the specification, these two methods will change the status, from pending to fulfilled/rejected.
2. Note that the input parameters of the two functions are value and Reason, respectively
Class HSPromise {constructor() {// initial state is pending this.status = pending; this.value = null; this.reason = null; } resolve(value) { if (this.status === PENDING) { this.status = FULFILLED; this.value = value; } } reject(reason) { if (this.status === PENDING) { this.status = REJECTED; this.reason = reason; }}}Copy the code
Promsie to join
1. The input parameter is a function that takes resolve and reject.
2. Note that this function is executed when the promise is initialized, and any errors are thrown via reject
Class HSPromise {constructor(fn) {// initial state is pending this.status = pending; this.value = null; this.reason = null; try { fn(this.resolve.bind(this), this.reject.bind(this)); } catch (e) { this.reject(e); } } resolve(value) { if (this.status === PENDING) { this.status = FULFILLED; this.value = value; } } reject(reason) { if (this.status === PENDING) { this.status = REJECTED; this.reason = reason; }}}Copy the code
The implementation of the then method
1. This parameter is fulfilled and onRejected
then(onFulfilled, onRejected) {}
Copy the code
2. Check and process parameters. If the parameter is not function, ignore it. This omission refers to returning value or reason as is
isFunction(param) {
return typeof param === 'function';
}
then(onFulfilled, onRejected) {
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled
: (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected
: (reason) => {
throw reason
};
}
Copy the code
3. Call different functions based on the current promise state
then(onFulfilled, onRejected) { const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => { return value; } const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => { throw reason; }; switch (this.status) { case FULFILLED: { fulFilledFn(this.value); break; } case REJECTED: { rejectedFn(this.reason); break; }}}Copy the code
4. In this way, the then function is executed the instant it is called. What if status has not become fulfilled or rejected? It will probably be pending.
Get all the callbacks first, and then execute them at some point. Create two new arrays to store the success and failure callbacks. When we call THEN, we store the Promise in the array if it is still pending.
then(onFulfilled, onRejected) { const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => { return value; } const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => { throw reason; }; switch (this.status) { case FULFILLED: { fulFilledFn(this.value); break; } case REJECTED: { rejectedFn(this.reason); break; } case PENDING: { this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled); this.REJECTED_CALLBACK_LIST.push(realOnRejected); break; }}}Copy the code
5. Perform all callbacks when status changes; The getters and setters of ES6 are used here, which is more semantic.
When status changes, do something. (You can also do it sequentially. After you assign status, add a forEach line below to do something.)
get status(){ return this._status; } set status(newStatus) { switch (newStatus) { case FULFILLED: { this.FULFILLED_CALLBACK_LIST.forEach(callback => { callback(this.value); }); break; } case REJECTED: { this.REJECTED_CALLBACK_LIST.forEach(callback => { callback(this.reason); }); break; }}}Copy the code
Then return value
This will be fulfilled fulfilled. If onFulfilled or onRejected throws an exception e, promise2 must refuse to execute and return rejected e. (You need to catch the code manually, reject the error.)
then(onFulfilled, onRejected) { const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => { return value; } const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => { throw reason; }; const fulFilledFnWithCatch = (resolve, reject) => { try { fulFilledFn(this.value); } catch (e) { reject(e) } }; const rejectedFnWithCatch = (resolve, reject) => { try { rejectedFn(this.reason); } catch (e) { reject(e); } } switch (this.status) { case FULFILLED: { return new HSPromise(fulFilledFnWithCatch); } case REJECTED: { return new HSPromise(rejectedFnWithCatch); } case PENDING: { return new HSPromise((resolve, reject) => { this.FULFILLED_CALLBACK_LIST.push(() => fulFilledFnWithCatch(resolve, reject)); this.REJECTED_CALLBACK_LIST.push(() => rejectedFnWithCatch(resolve, reject)); })}}}Copy the code
2. If onFulfilled is not the function and PromisE1 is successfully executed, Promise2 must be successfully executed and return the same value.
const fulFilledFnWithCatch = (resolve, reject) => {
try {
fulFilledFn(this.value);
resolve(this.value);
} catch (e) {
reject(e)
}
}
Copy the code
If onRejected is not a function and Promise1 rejects it, promise2 must reject it and return the same reason.
If promise1 onRejected is successfully executed, promise2 should be resolved
const rejectedFnWithCatch = (resolve, reject) => { try { rejectedFn(this.reason); if (this.isFunction(onRejected)) { resolve(); } } catch (e) { reject(e); }}Copy the code
If onFulfilled or onRejected returns a value x, run the resolvePromise method
then(onFulfilled, onRejected) {
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled
: (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected
: (reason) => {
throw reason;
};
const fulFilledFnWithCatch = (resolve, reject) => {
try {
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
} else {
const x = fulFilledFn(this.value);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e)
}
};
const rejectedFnWithCatch = (resolve, reject) => {
try {
if (!this.isFunction(onRejected)) {
reject(this.reason);
} else {
const x = rejectedFn(this.reason);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
}
switch (this.status) {
case FULFILLED: {
const newPromise = new HSPromise((resolve, reject) =>
fulFilledFnWithCatch(resolve, reject, newPromise))
return newPromise
}
case REJECTED: {
const newPromise = new HSPromise((resolve, reject) =>
rejectedFnWithCatch(resolve, reject, newPromise))
return newPromise
}
case PENDING: {
const newPromise = new HSPromise((resolve, reject) => {
this.FULFILLED_CALLBACK_LIST.push(() =>
fulFilledFnWithCatch(resolve, reject, newPromise));
this.REJECTED_CALLBACK_LIST.push(() =>
rejectedFnWithCatch(resolve, reject, newPromise));
});
return newPromise;
}
}
}
Copy the code
ResolvePromise method
ResolvePromise (newPromise, x, resolve, reject) {// if newPromise and x point to the same object, Reject (newPromise === x) {reject(new TypeError('The promise and The return value are the same')); } if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) { X. tet ((y) => {resolvePromise(newPromise, y, resolve, reject); }, reject); } else if (typeof x = = = 'object' | | this. IsFunction (x)) {/ / / / if x is an object or function of the pit is the time to run test found that, if x is null, Resolve (x === null) {return resolve(x); } let then = null; Try {// assign x.hen to then then = x.hen; } catch (error) {// Promise return reject(error), reject(error), reject(error), reject(error); } if (this.isfunction (then)) {let called = false; // The first parameter is resolvePromise, the second parameter is rejectPromise, and the second parameter is rejectPromise. Try {then. Call (x, // if the resolvePromise is called with the value y, Run resolvePromise (y) => {// If both resolvePromise and rejectPromise are called, // or the same argument is called multiple times, // This requires a variable called if (called) return; called = true; resolvePromise(promise, y, resolve, reject); }, // rejectPromise (r) => {if (called) return;}, // rejectPromise (r) => {if (called) return; called = true; reject(r); }); } catch (error) {// If the then method throws an exception e: // If either resolvePromise or rejectPromise has been called, ignore it if (called) return; // Reject (error); }} else {// If then is not a function, promise resolve(x); }} else {// Promise resolve(x) if x is not an object or function; }}Copy the code
This is very depressing and onRejected are micro tasks
Execute functions wrapped in queueMicrotask
const fulFilledFnWithCatch = (resolve, reject) => {
queueMicrotask(() => {
try {
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
} else {
const x = fulFilledFn(this.value);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e)
}
}) }
const rejectedFnWithCatch = (resolve, reject) => {
queueMicrotask(() => {
try {
if (!this.isFunction(onRejected)) {
reject(this.reason);
} else {
const x = rejectedFn(this.reason);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
})
}
Copy the code
Catch method
catch (onRejected) {
return this.then(null, onRejected);
}
Copy the code
Promise.resolve
This will be fulfilled fulfilled. If the parameter of promise. resolve is not an object with the then method (also called thenable), a new Promise object will be returned with the state fulfilled.
static resolve(param) { if (param instanceof HSPromise) { return param; } return new MyPromise(function (resolve) { resolve(param); }); }Copy the code
Promise.reject
1. Return a new Promise instance whose status is Rejected. The reason argument to the promise. reject method is passed to the instance callback function.
static reject(reason) {
return new MPromise((resolve, reject) => {
reject(reason);
});
}
Copy the code
Promise.race
const p = Promise.race([p1, p2, p3])
1. This method is to wrap multiple Promise instances into a new Promise instance. Whenever one instance of P1, P2, or P3 changes state first, the state of P changes accordingly. The return value of the Promise instance that changed first is passed to the p callback function.
static race(promiseList) { return new MPromise((resolve, reject) => { const length = promiseList.length; if (length === 0) { return resolve(); } else { for (let i = 0; i < length; i++) { HSPromise.resolve(promiseList[i]).then( (value) => { return resolve(value); }, (reason) => { return reject(reason); }); }}})}Copy the code