What is promise?

  • A promise is an object or function with then methods that behave according to this specification;
  • Thenable is an object or function with a then method;
  • Value is the value of the successful promise state, that is, the resolve parameter, including various data types, including undefined/thenable or promise.
  • Reason is a reject value when the promise state fails.
  • Exception is an exception thrown with a throw.

Ii. A+ specification

1. Three states of promise
  • pending

    1.1 The initial state can be changed;

    1.2 A promise is in this state before resolve or reject;

    1.3 Can be fulfilled through the resolve-> depressing state;

    1.4 Reject -> Reject;

  • fulfilled

    1.1 Final state, immutable;

    1.2 A promise becomes this state after it is resolved;

    1.3 Must have a value

  • rejected

1.1 Final state, immutable;

1.2 A promise is rejected in this state;

1.3 Must have a Reason

2. State flow of promise
  • pending->resolve(value)->fulfilled
  • pending->reject(reason)->rejected

Three, then

Promise has a then method that accesses the final result, either value or Reason.

promise.then(onFunfilled,onRejected)
Copy the code
1. Two parameters:

1.1 Ondepressing must be a function type. If it is not a function, it should be ignored;

  • Ondepressing should be called with the parameter value when the promise becomes a big pity.
  • Promises should not be invoked until they become a big pity.
  • Can only be called once (so you need a variable at implementation time to limit the number of times it can be executed)

1.2 onRejected must be a function type. If it is not a function, it should be ignored.

  • When a promise becomes Rejected, you should call onRejected with reason;
  • Promise should not be called until it becomes Rejected.
  • Can only be called once (so you need a variable at implementation time to limit the number of times it can be executed)
This is a big pity and onRejected

Use queueMicrotask to implement the invocation of microtasks.

3. The then method can be called multiple times

3.1 After the promise state becomes a big pity, all ondepressing callbacks need to be executed according to the order of THEN, that is, according to the order of registration (so an array is needed to store multiple ondepressing callbacks when realizing the promise);

3.2 After the promise status changes to Rejected, all the onRejected callbacks need to be executed in the order of THEN, that is, in the order of registration (so an array is required to store multiple onRejected callbacks).

4. Return value of the then method

4.1 Then returns a brand new promise

promise2 - promise1.then(onFulfilled, onRejected);
Copy the code

4.2 Set the result of onFulfilled or onRejected to X, and call resolvePromise(explained later);

4.3 If exception E is thrown when onFulfilled or onRejected is implemented,promise2 needs to be rejected.

4.4 If ondepressing is not a function, promise2 will trigger the depressing with the value of promise1.

4.5 If onRejected is not a function, promise2 triggers Rejected with the reason of promise1.

5. Focus on resolvePromise
ResolvePromise (promise2, x, resolve, reject)Copy the code

Reject TypeError if promise2 is equal to X;

5.2 If x is a Promise, make newPromise accept the state of X; Keep executing x, and if you get a Y, keep parsing y;

5.3 If x is an object or a function,

let then = x.then; Call (x, resolvePromiseFn, rejectPromise); // Call (x, resolvePromiseFn, rejectPromise); ResolvePromiseFn (y, y,resolve, reject); If not a function, resolve(x)Copy the code

Four, code implementation

Const PENDING = 'PENDING '; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; \ class MPromise {// a detail point // using an array to store callback functions is not applicable to chained calls. Then, because each.then returns a new promise, // When the same promise instance is called, Led_callback_list = []; REJECTED_CALLBACK_LIST = []; Getter \ set_status = PENDING; Constructor (fn) {constructor(fn) {// This. Status = pending; // This. Value = null; // This. Reason = null; try { fn(this.resolve.bind(this), this.reject.bind(this)); } catch (e) { this.reject(e); }} \ // Get status() {return this._status; } set status(newStatus) {this._status = newStatus; switch (newStatus) { case FULFILLED: { this.FULFILLED_CALLBACK_LIST.forEach(callback => { callback(this.value); }); break; } case REFUSED: { this.REJECTED_CALLBACK_LIST.forEach(callback => { callback(this.reason) }); break; If (this.status === pending) {this.value = value; if (this.status === pending) {this.value = value; this.status = FULFILLED; } } \ reject(reason) { if (this.status === PENDING) { this.reason = reason; this.status = REJECTED; This is a big pity; // Then (onFulfilled, onFulfilled) {const realOnFulfilled = this.isfunction (onFulfilled)? onFulfilled : (value) => { return value } const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {throw reason} // then returns a new promise2 // Ondepressing and onRejected is a microtask const, which uses queueMicrotask promise2 = new MPromise((resolve, Reject) => {// Success const stringledMicroTask = () => {queueMicrotask(() => {try {const x = realOnFulfilled(this.value); This. ResolvePromise (promise2, x, resolve, reject)} catch (e) {reject(e); }})}; // Fail const rejectedMocrotask = () => {queueMicrotask(() => {try {const x = realontask (this. Reason); ResolvePromise (promise2, x, resolve, This is a big pity. This is a big pity. This is a big pity. { fulfilledMicrotask() break; } case REJECTED: { rejectedMocrotask() break; } case PENDING: { this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask); this.REJECTED_CALLBACK_LIST.push(rejectedMocrotask); } } }) return promise2; } \ catch(onRejected) { return this.then(null, IsFunction (param) {return typeof parame === 'function'; return typeof parame === 'function'; ResolvePromise (promise2, x, resolve, reject) {// If newPromise and x refer to the same object, Reject newPromise with typeError to prevent an infinite loop if (promise2 === x) {return Reject (new TypeError(' The promise and the return If (x instanceof MPromise) {// if (x instanceof MPromise) {// If (x instanceof MPromise) { Y queueMicrotask(() => {x. Chen ((y) => {this.resolvePromise(promise2, y, resolve, reject)} Reject)})} else if (typeof x = = = 'object' | | this. IsFunction (x)) {/ / / / null if x is an object or function will be judged as object if (x = = = null) { return resolve(x); } \ let then = null; try { then = x.then; } catch (error) { return reject(error); } \ // If (this.isfunction (then)) {let called = false; // Call this with x as function scope // pass two callback functions as arguments, The first argument is resolvePromise, and the second argument is called rejectPromise try {then.call(x, // if resolvePromise is called with the value y, ResolvePromise (y) => {// A variable called is required to ensure that if (called) return is called only once; called = true; This. ResolvePromise (promise2, y, resolve, reject)} Promise (r) => {if (called) return; called = true; reject(r); } ) } catch (e) { if (called) return; Reject (e)}} else {resolve(x)}} else {// If x is not an object or a function, Resolve static resolve(value) {if (value instanceof MPromise) {return value; } \ return new MPromise((resolve) => { resolve(value); })} \ // static reject static reject(reason) {return new MPromise((resolve, reject) => {reject(reason); })} // Static method race, Static race(promiseList) {return new MPromise((resolve, reject) => {const length = promiseList. if (length === 0) { return resolve(); } else { for (let i = 0; i < length; i++) { MPromise.resolve(promiseList).then( (value) => { return resolve(value); }, (reason) => { return reject(reason); Static all(promiseList) {let index = 0; static all(promiseList) {let index = 0; let result = []; return new MPromise((resolve, reject) => { promiseList.forEach((p, Resolve (p).resolve(p).then(value => {index++; result[i] = value; if (index === promiseList.length) { resolve(result) } }, Reason => {reject(reason)})})})}} \ // Write a simple test case const test = new MPromise((resolve, resolve) reject) => { setTimeout(() => { reject(111); }, 1000); }).then((value) => { console.log('then'); }).catch((reason) => { console.log('catch'); The \})Copy the code