preface

Here I quote ruan’s definition of Primose objects from ES6 introduction

Promise is a solution to asynchronous programming that makes more sense and is more powerful than traditional solutions — callback functions and events. It was first proposed and implemented by the community, and ES6 has written it into the language standard, unifying usage, and providing Promise objects natively.

It has two characteristics:

  1. The status of an object is not affected
  2. Once the state changes, it never changes again, and you can get this result at any time

Realize the Promise

Based on the concept, write a Promise by hand

class PromiseA {
  constructor(exectuor) {
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;
    const resolve = (value) = > {
      if (this.status === 'pending') {
        this.value = value;
        this.status = 'fulfilled'; }}const reject = (reason) = > {
      if (this.status === 'pending') {
        this.reason = reason;
        this.status === 'rejected';
      }
    }
    exectuor(resolve, reject);
  }

  then(onResolved, onRejected) {
    const resolved = typeof onResolved === 'function' ? onResolved : v= > v;
    const rejected = typeof onRejected === 'function' ? onRejected : r= > r;
    if (this.status === 'fulfilled') {
      resolved(this.value);
    }
    if (this.status === 'rejected') {
      rejected(this.reason); }}}Copy the code

The code is simple, with the focus on changing the state of the current Promise in resolve, Reject. Let’s test it out. Everything’s fine

const promise = new PromiseA((resolve) = > {
  resolve('promise success');
}).then((data) = > {
  console.log(data); // promise success
})
Copy the code

If asynchronous processing in the Promise of the callback function resolve, eventually did not get the desired results, then the reason is that the call, the status is still in a pending state, don’t perform then method of resolved or rejected.

new PromiseA((resolve, reject) = > {
  setTimeout(() = > {
    resolve('promise success')}); }).then((data) = > {
	// Note: this is not executed at all
  console.log(data);
})
Copy the code

Resolved or Rejected methods are added to the array. When resolve() is executed, the resolved/ Rejected method is iterated through the array. This is the observer mode.

class PromiseA {
  constructor(exectuor){...// omit part
    
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) = > {
      if (this.status === 'pending') {
        this.value = value;
        this.status = 'fulfilled';
        Resolved ()
        this.onResolvedCallbacks.forEach(fn= >fn()); }}const reject = (reason) = > {
      if (this.status === 'pending') {
        this.reason = reason;
        this.status === 'rejected';
        this.onRejectedCallbacks.forEach(fn= > fn());
      }
    }
    exectuor(resolve, reject);
  }

  then(onResolved, onRejected){...// omit part

	  // Add a new section
    if(this.status === 'pending') {
      this.onResolvedCallbacks.push(() = > {
        resolved(this.value);
      });
      this.onRejectedCallbacks.push(() = > {
        rejected(this.reason); })}}}Copy the code

Let’s test it out. Everything’s fine.

const promise = new PromiseA((resolve) = > {
  setTimeout(() = > {
    resolve('promise success');
  });
}).then((data) = > {
  console.log(data); // promise success
})
Copy the code

Chain calls to THEN

Using chained THEN, you can specify a set of callback functions that are called in order. In this case, the previous callback may still return a Promise object (with asynchronous operations), and the latter callback will wait for the state of the Promise object to change before it is invoked. To implement a chained call to THEN, you must process the return value of the THEN method by adding a method that handles the return value of the THEN method.

// Handle chain calls to THEN
function resolveThen(promisable, promise, resolve, reject) {
  if (promisable === promise) {
    throw ('Promise cannot be the same reference object');
  }
  try {
    // Determine if the promise is an object, and if so, further processing
    // If not, promise is a base value and resolve is used directly
    if (promise && typeof promise === 'object') {
      const then = promise.then;
      // Determine if a promise has a then method, and if so, further processing
      // If not, promise is a normal object and resolve is handled directly
      if (then && typeof then === 'function') {
        // Recursive processing is the case for Promise
        then.call(promise, y= > {
          resolveThen(promise2, y, resolve, reject);
        }, r= >{ reject(r); })}else{ resolve(promise); }}else {
      resolve(promise)
    }
  } catch(error) { reject(error); }}Copy the code

The then method returns a Promise object

export class PromiseA {.../ / to omit

  then(onResolved, onRejected) {
    const resolved = typeof onResolved === 'function' ? onResolved : v= > v;
    const rejected = typeof onRejected === 'function' ? onRejected : r= > r;

    const promise = new PromiseA((resolve, reject) = > {
      if (this.status === 'fulfilled') {
        const value = resolved(this.value);
        resolveThen(promise, value, resolve, reject);
      }
      if (this.status === 'rejected') {
        const reason = rejected(this.reason);
        resolveThen(promise, reason, resolve, reject);
      }
      if (this.status === 'pending') {
        this.onResolvedCallbacks.push(() = > {
          const value = resolved(this.value);
          resolveThen(promise, value, resolve, reject);
        });
        this.onRejectedCallbacks.push(() = > {
          const reason = rejected(this.reason); resolveThen(promise, reason, resolve, reject); }}}));returnpromise; }}Copy the code

So that’s the chain call to THEN. Let’s test it out. Everything works

const promise = new PromiseA((resolve) = > {
  setTimeout(() = > {
    resolve('promise success');
  });
}).then((data) = > {
  console.log(data); // promise success
  return 'promise then success';
}).then((data) = > {
  console.log(data); // promise then success
})
Copy the code

The implementation of static methods like promise.resolve, promise.all will be updated later.