preface

Learning is a long process, step by step, in order to deeply understand a technology, you need to sink down and study slowly. To see the essence through the phenomenon, learning Promise will also use higher-order functions and publish and subscribe, only by mastering those general technologies can we learn more effectively and see the essence better. Over time, you’ll find that by studying a Promise in depth, you’ll get more than just a Promise.

What is Promise

Promises are a solution to asynchronous programming, and the Promise object is a constructor that generates a Promise instance.

Ii. Promise objects have the following two characteristics.

Only the result of the asynchronous operation can determine which state is currently pending. No other operation can change this state

Once the state changes, it will never change again. There are only two possibilities for the state change of the Promise object: from pending to depressing and from pending to Rejected. As long as those two things happen, the state is frozen, it’s not going to change, it’s going to stay the same

Iii. Realization of Promise (ES5)

1.

When new Promsie(executor) is used, executor is executed as synchronized code immediately.

This is a big pity. Status: Three states pending, fulfilled and Rejected of the Promise instance

3. Value: This is the parameter passed successfully. Success has a success value.

4. Reason: This parameter is passed when failure occurs. Failure has a reason for failure.

Resolve: A function that is called on success and passed to executor as an argument

Reject: A higher-order function that is called on failure and passed to executor as an argument

2. The most basic Promise:

The most basic promise source code only 34 lines, read the 34 lines of code, you will understand the most core part of the promise, is not very excited!!

Code read: In Promise, define the status, success value, and reason for failure when you pass infunction(resolve,reject){resolve('It worked'/ / Resolve will be triggered as a callback function, and the previously defined state pending will become a pitythenThe method passes in two callbacks, which are compared internallyifThis is onFulfilled or onRejected.function Promise(executor){
   const self = this;
   self.status = 'pending'; // Promise state self.value = undefined; Self. reason = undefined; // There are reasons for failurefunction resolve(value){
       if(self.status === 'pending'){// Only pending states can be changed self.status ='fulfilled'; self.value = value; }}function reject(reson){
       if(self.status === 'pending'){// Only pending states can be changed self.status ='rejected'; self.reason = reson; } } try{ executor(resolve,reject); }catch(err){reject(err);}catch(err){reject(err); } } Promise.prototype.then =function(onFulfilled,onRejected){
       const self = this;
       if(self.status === 'fulfilled'){
           onFulfilled(self.value);
       }
       if(self.status === 'rejected'){ onRejected(self.reason); }}Copy the code

The above code can normally run the following code:

const p = new Promise((resolve,reject)=>{
    resolve('success') 
    // throw 1213
    // reject('failure')}); p.then(function(data){console.log(data) // success},function(err){console.log(err) // failed or 1213})Copy the code

At this point, the basic Promise has been wrapped, isn’t it?

3, how to solve the asynchronous call?

The code encapsulated above has no result if it encounters the code below.

  • synchronousThe code is executed in the following order:executor ---> resolve ---> then
  • asynchronousThe code is executed in the following order:executor ---> then ---> resolve

So when you call then, remember to look at the implementation of the THEN method. Its internal status is pending. Remember that the implementation of the then method has a success or failure state. This is a big pity, which is a big pity. This is a big pity, which is a big pity. This is a big pity, which is a big pity. OnRejectedCallbacks install the then callback onRejected (resolve)

const p = new Promise((resolve,reject)=>{
   setTimeout(()=>{
       resolve('I am asynchronous success')})});Copy the code

To solve the asynchronous update code is as follows:

function Promise(executor){ const self = this; self.status = 'pending'; // Promise state self.value = undefined; Self. reason = undefined; // There are reasons for failure+ self.onResolvedCallbacks = [];
+ self.onRejectedCallbacks = [];
 
    function resolve(value){
        if(self.status === 'pending'){// Only pending states can be changed
            self.status = 'fulfilled';
            self.value = value;
+ self.onResolvedCallbacks.forEach(item => item(value));
        }
    }
    function reject(reson){
        if(self.status === 'pending'){// Only pending states can be changed
            self.status = 'rejected';
            self.reason = reson;
+ self.onRejectedCallbacks.forEach(item => item(value));} } try{ executor(resolve,reject); }catch(err){reject(err);}catch(err){reject(err); } } Promise.prototype.then = function(onFulfilled,onRejected){ const self = this; if(self.status=== 'fulfilled'){
            onFulfilled(self.value);
        }
        if(self.status === 'rejected'){
            onRejected(self.reason);
        }
+ if (self.status == 'pending') {
+ self.onResolvedCallbacks.push(function (value) {
+ try {
+ onFulfilled(value);
+ } catch (e) {
+ reject(e);
+}
+});
+ self.onRejectedCallbacks.push(function (value) {
+ try {
+ onRejected(value);
+ } catch (e) {
+ reject(e);
+}
+});
+}
+}
Copy the code

4, Promise/A+ complete implementation

The resolvePromisefang method resolves those things:

What is a resolvePromise? : This is actually an official Promise/A+ requirement. Because your then can return any job, including a Promise, of course, and if it’s a Promise, we need to unpack it until it’s not a Promise and take its value.

function Promise(executor) {
 let self = this;
 self.status = "pending";
 self.value = undefined;
 self.onResolvedCallbacks = [];
 self.onRejectedCallbacks = [];
 function resolve(value) {
+ if (value instanceof Promise) {
+ return value.then(resolve, reject)
+}
+ setTimeout(function () {// Execute all callbacks asynchronouslyif (self.status == 'pending') { self.value = value; self.status = 'resolved'; self.onResolvedCallbacks.forEach(item => item(value)); }});+}

 function reject(value) {
+ setTimeout(function () {if (self.status == 'pending') { self.value = value; self.status = 'rejected'; self.onRejectedCallbacks.forEach(item => item(value)); }});+}try { executor(resolve, reject); } catch (e) { reject(e); }}+ function resolvePromise(promise2, x, resolve, reject) {
+ if (promise2 === x) {
+ return Reject (new TypeError(' circular reference '));
+}
+ let then, called;

+  if (x != null && ((typeof x == 'object' || typeof x == 'function'))) {
+ try {
+ then = x.then;
+ if (typeof then == 'function') {
+ then.call(x, function (y) {
+ if (called)return;
+ called = true;
+ resolvePromise(promise2, y, resolve, reject);
+ }, function (r) {
+ if (called)return;
+ called = true;
+ reject(r);
+});
+ } else {
+ resolve(x);
+}
+ } catch (e) {
+ if (called)return;
+ called = true;
+ reject(e);
+}
+ } else {
+ resolve(x);
+}
+}
Promise.prototype.then = function (onFulfilled, onRejected) {
 let self = this;
+ onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : function (value) {
+ return value
+};
+ onRejected = typeof onRejected == 'function' ? onRejected : function (value) {
+ throw value
+};
+ let promise2;
 if (self.status == 'resolved') {
+ promise2 = new Promise(function (resolve, reject) {
+ setTimeout(function () {
+ try {
+ let x = onFulfilled(self.value);
+ resolvePromise(promise2, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+}
+});
+});
 }
 if (self.status == 'rejected') {
+ promise2 = new Promise(function (resolve, reject) {
+ setTimeout(function () {
+ try {
+ let x = onRejected(self.value);
+ resolvePromise(promise2, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+}
+});
+});
 }
 if (self.status == 'pending') {
+ promise2 = new Promise(function (resolve, reject) {
+ self.onResolvedCallbacks.push(function (value) {
+ try {
+ let x = onFulfilled(value);
+ resolvePromise(promise2, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+}
+});
+ self.onRejectedCallbacks.push(function (value) {
+ try {
+ let x = onRejected(value);
+ resolvePromise(promise2, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+}
+});
+});
+}
+ return promise2;
}
Copy the code

Iv. Implementation of other methods of Promise

all:

The promise.all () method takes an array of arguments. P1, p2, and p3 are all Promise instances. If they are not, the Promise. In addition, the promise.all () method can take arguments that are not arrays, but must have an Iterator interface and return each member as a Promise instance

Promise.all=function(promises){
    return new Promise((resolve,reject)=>{
        promises=Array.from(promises);
        const length=promises.length, results=[],_index=0;
        if(length==0){
            resolve(results)
            return 
        }
        promises.forEach((promise,index)=>{
            Promise.resolve(promise).then(result=>{
                results[index]=result;
                if(length==++_index){
                   resolve(results)
                }
            }).catch(err=>{
                reject(err)
            })
        })
    })
}
Copy the code

race

const p = Promise.race([p1, p2, p3]);

In the above code, the state of P changes as long as one of the first instances of P1, P2, and P3 changes state. The return value of the first changed Promise instance is passed to p’s callback.

Promise.race=function(promises){
    return new Promise((resolve,reject)=>{
        promises=Array.from(promises);
        if(promises.length==0){
            resolve()
            return 
        }
        promises.forEach((promise,index)=>{
            Promise.resolve(promise).then(result=>{
                resolve(result)
            }).catch(err=>{
                reject(err)
            })
        })
    })
}
Copy the code

finally

The finally method is used to specify actions that will be performed regardless of the final state of the Promise object. This method was introduced as a standard in ES2018.

Promise. Then (result = > {...}). The catch (error = > {...}), finally (() = > {...});Copy the code

In the code above, regardless of the last state of the promise, the callback specified by the finally method is executed after the callback specified by then or catch.

Promise.prototype.finally=function(onFinally){
    var isFunction = typeof onFinally == "function";
    returnthis.then(isFunction? (result)=>{ onFinally();returnresult }:onFinally,isFunction? (err)=>{ onFinally();return Promise.reject(err)
    }:onFinally);
}
Copy the code

resolve/reject

Resolve: Sometimes you need to turn an existing object into a Promise object, which the promise.resolve () method does

Reject: promise. reject(Reason) also returns a new Promise instance with a state of Rejected.

// the resolve method promise.resolve =function(val){
  returnNew Promise((resolve,reject)=>{resolve(val)})} //reject promise.reject =function(val){
  return new Promise((resolve,reject)=>{
    reject(val)
  })
}
Copy the code