PromiseA + specification
Common terminology
1) Promise: an object or function with a then method that behaves in accordance with the promiseA+ specification 4) Reason: a reject value. 5) exception: a throw exceptionCopy the code
Promise Status Indicates the status flow
Promise has three states: you can implement a flow between states. 1) Pending state The initial state can be changed into the fulfilled state through the pity state, which can be changed into the rejected state through the reject state 3) Reject When the execution fails, there must be a reason value when the reject state is changed to rejected stateCopy the code
Then Promises should provide a THEN method that accesses the final result
promise.then(onFulfilled, onRejected)
Copy the code
1. OnFulfilled and onRejected must be a function. If it is not a function, OnFulfilled and onRejected must be a big pity. 3. Both onFulfilled and onRejected can only be called once, when the promise state becomes a big pity. OnFulfilled should be called. When the promise state becomes Rejected, onFulfilled should be called. 4. The THEN method can be called multiple times. After the promise state becomes "depressing", all ondepressing callbacks need to be executed in the order of "THEN", that is, in the order of registration. When the Promise state changes to Rejected, all onRejected callbacks need to be executed in the order of then, in the order of registration. 5. The then method returns a new promiseCopy the code
resolvePromise(promise2, x, resolve, reject)
Copy the code
6.1 An exception is thrown if x and prommise2 are equal, If x is an object or function let then = x. teng if x. teng fails, then x is a promise. Call (x, resolvePromiseFn, rejectPromise) if then is not a function then resolveCopy the code
Implement a simple version of the promise based on the promiseA+ specification
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MPromise {
FULFILLED_CALLBACK_LIST = []
REJECTED_CALLBACK_LIST =[]
_status = PENDING
constructor (fn) {
this.status = PENDING;
this.value = null;
this.reason = null;
try {
fn(this.resolve.bind(this), this.reject.bind(this));
} catch (err) {
this.reject(err);
}
}
get status () {
return this._status;
}
set status (newStatus) {
this._status = newStatus;
switch (this._status) {
case FULFILLED:
this.FULFILLED_CALLBACK_LIST.forEach(callback= > {
callback(this.value);
});
break;
case REJECTED:
this.REJECTED_CALLBACK_LIST.forEach(callback= > {
callback(this.reason);
});
break;
}
}
resolve (value) {
if (this.status ! == PENDING) {return;
}
this.value = value;
this.status = FULFILLED;
}
reject (reason) {
if (this.status ! == PENDING) {return;
}
this.reason = reason;
this.status = REJECTED;
}
then (onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value= > value;
const realOnRejected = this.isFunction(onRejected) ? onRejected : reason= > { throw reason; };
const promise2 = new MPromise((resolve, reject) = > {
const fulfilledMicroTask = () = > {
queueMicrotask(() = > {
try {
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch(err) { reject(err); }}); };const rejectedMicroTask = () = > {
queueMicrotask(() = > {
try {
const x = realOnRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch(err) { reject(err); }}); };switch (this.status) {
case FULFILLED:
fulfilledMicroTask();
break;
case REJECTED:
rejectedMicroTask();
break;
case PENDING:
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicroTask);
this.REJECTED_CALLBACK_LIST.push(rejectedMicroTask);
break; }});return promise2;
}
// core resolves a promise
resolvePromise (promise2, x, resolve, reject) {
// if x is equal to promise2, throw an error to avoid an infinite loop
if (x === promise2) {
return reject(TypeError('the x and promise are the same'));
}
// x is an MPromise instance
if (x instanceof MPromise) {
x.then(y= > {
this.resolvePromise(promise2, y, resolve, reject);
}, reject);
}
// is a function or an object
if (this.isFunction(x) || typeof x === 'object') {
if (x === null) {
return resolve(x);
}
let then = null;
try {
then = x.then;
} catch (err) {
return reject(err);
}
if (this.isFunction(then)) {
let called = false;
then.call(x,
y= > {
if (called) {
return;
}
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
r= > {
if (called) {
return;
}
called = true; reject(r); }); }else{ resolve(x); }}else{ resolve(x); }}// catch
catch (onRejected) {
return this.then(null, onRejected)
}
Static methods can be called directly
static resolve (value) {
if (value instanceof MPromise) {
return value;
}
return new MPromise((resolve, reject) = > {
resolve(value);
});
}
// reject
static reject (reason) {
return new MPromise((resolve, reject) = > {
reject(reason);
});
}
// race: The race method has a Promise that subsequent code will not execute after successful execution
static race (promiseList = []) {
return new MPromise((resolve, reject) = > {
const len = promiseList.length;
if(! len) {return resolve();
}
for (let i = 0; i < len; i++) {
MPromise.resolve(promiseList[i]).then(
value= > resolve(value),
reason= >reject(reason) ); }}); }// all: Promise. All can wrap multiple Promise instances into a new Promise instance. Promise.all array of success resultsSame order as the array passed instatic all (promiseList = []) {
return new MPromise((resolve, reject) = > {
const len = promiseList.length;
let resolvedNum = 0;
const resolvedValueList = new Array(len);
for (let i = 0; i < len; i++) {
MPromise.resolve(promiseList[i]).then(value= > {
resolvedNum++;
resolvedValueList[i] = value;
if(resolvedNum === len) { resolve(resolvedValueList); }},reason= >reject(reason)); }}); }// the utility function checks if it is function
isFunction (value) {
return typeof value === 'function'; }}Copy the code