1.Promise

Promise is a popular asynchronous solution, essentially a constructor.

1.1 state

Promise has three states, the initial state is PEDding, including:

  • Pedding => Resolve
  • If pedding fails, go to Reject
  • Waiting status Pedding

Let’s start with a simple example

let promise = new Promise(function(resolve,reject){
    //throw new Error('Wrong')
    //resolve()
    reject()
});
promise.then(()=>{
    console.log('success')
},()=>{
    console.log('error');
});
Copy the code

Each promise instance has a THEN method, which contains two parameters: successful callback and failed callback, and multiple THEN, successful callback and failure of all successful methods. In essence, THEN is asynchronous, also known as microtask. Other methods include:

  • Promise.all() All Promise objects trigger a success state if they succeed, or a failure state if they fail
  • Promise.race() any sub-pormise state will be called immediately by the parent Promise after it is triggered, and one can be completed

2. Make a Promise yourself

All promises follow the promiseA+ specification

Simple version 2.1

function Promise(executor){ 
    letself = this; self.value = undefined; // Define success value self.reason = undefined; // Define failed reson self.status ='pending'; // The initialization state is PEDdingfunction resolve(value){
        if(self.status === 'pending'Self. value = value; self.value = value; self.status ='resolved'; }}function reject(reason){
        if(self.status === 'pending'Self. reason = reason; self.status ='rejected'; }} try{executor(resolve,reject); }catch(e){reject(e); } } Promise.prototype.then =function(onFulfilled,onRejected){
    letself = this; // Determine the current status // success statusif(self.status === 'resolved'// This is a big pity (self.value); // This is a big pity. // The example abovethenSuccess callback (console.log('success'} // In the failed stateif(self.status === 'rejected'){// If rejected (self.reason); // If rejected (self.reason); // The example abovethenFailure callback (console.log('error'Module. Exports = exports;Copy the code

2.2 Slightly improved

However, if an asynchronous method is added to a New Promise and the execution of resolve is delayed for 3 seconds, then will not execute the successful or failed method because the successful or failed methods need to be stored in an array

let promise = new Promise(function(resolve,reject){
    setTimeout(()=>{
        resolve()
    },3000)
});
Copy the code

To perfect the example

function Promise(executor){
    let self = this;
    self.value = undefined;
    self.reason = undefined;
    self.status = 'pending'; self.onResolvedCallbacks = []; / / storethenSelf.onrejectedcallbacks = []; / / storethenFailed callback infunction resolve(value){
        if(self.status === 'pending'){
            self.value = value;
            self.status = 'resolved'; self.onResolvedCallbacks.forEach(fn=>fn()); // Loop executed successfully}}function reject(reason){
        if(self.status === 'pending'){
            self.reason = reason;
            self.status = 'rejected'; self.onRejectedCallbacks.forEach(fn=>fn()); // loop execution failed}} try{executor(resolve,reject); }catch(e){ reject(e); // this is a big Promise, onFulfilled // this is a big Promise, onFulfilled // This is a big Promise, onFulfilled // This is a big Promise, onFulfilled // This is a big Promise, onFulfilled // This is a big Promisefunction(onFulfilled,onRejected){
    let self = this;
    if(self.status === 'resolved'){
        onFulfilled(self.value);
    }
    if(self.status === 'rejected'){
        onRejected(self.reason);
    }
    if(self.status === 'pending') {/ / when a wait state, save the callback function self. OnResolvedCallbacks. Push (() = > {onFulfilled (self. Value); }); self.onRejectedCallbacks.push(()=>{ onRejected(self.reason) }); } } module.exports = Promise;Copy the code

2.3 Chain call

We know that promises can go on and on to implement chain calls, but the example above clearly doesn’t work for example

let p = new Promise((resolve,reject) =>{
    resolve(123)
})
let p1 = new Promise((resolve,reject) =>{
    resolve(111)
})
p.then((data)=>{
    console.log(data)
    returnP1 // returns p1 as a new promise. Continue with success, passing 111 to the next newData. Failure is the samethen}). Then ((newData)=>{console.log()'p1',data)
})

Copy the code

Improve the code

function Promise(executor) {
    let self = this;
    self.value = undefined; 
    self.reason = undefined; 
    self.status = 'pending'; 
    self.onResolvedCallbacks = [];  
    self.onRejectedCallbacks = [];
    function resolve(value) { 
        if (self.status === 'pending') {
            self.value = value;
            self.status = 'resolved'; self.onResolvedCallbacks.forEach(fn => fn()); }}function reject(reason) { 
        if (self.status === 'pending') {
            self.reason = reason;
            self.status = 'rejected';
            self.onRejectedCallbacks.forEach(fn => fn());
        }
    }
    try {
        executor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}
/**
 * 
 * @param {*} promise2  thenReturn value (the new promise returned) * @param {*} xthen* @param {*} resolve resolve of promise2 * @param {*} reject Reject */functionResolvePromise (promise2, x, resolve, reject) {/ / promise2 and function performs the returned result is the same object, after waiting for himself, can't <! - for instance,letp1 = p.then((data)=>{--> <! --returnP1 // Return a promise that will neither succeed nor fail, waiting for yourself --> <! -}) -- -- >if(promise2 === x){
        return reject(new TypeError('Chaining cycle'));
    }
    letcalled; // x can be either a promise or a normal valueif(x! ==null && (typeof x==='object' || typeof x === 'function')){
        try{
            let then= x.then; // This promise may have been written by someone else, so try catch // x may still be a promiseif(typeof then= = ='function'){then.call(x,y=>{// returns a successful result after a promise // recurses until a normal value is resolvedif(called) return; // Prevent multiple calls to called =true; / / recursive may after the success of the result is a promise that is about to cycle to parse resolvePromise (promise2, y, resolve, reject); },err=>{// The result of a promise failureif(called) return;
                    called = true;
                    reject(err);
                });
            }else{
                resolve(x);
            }
        }catch(e){
            if(called) return;
            called = true; reject(e); }}else{// If x is a constant resolve(x); } } Promise.prototype.then =function (onFulfilled, onRejected) {
    let self = this;
    letpromise2; // Each call is requiredthenPromise2 = new promise ((resolve, reject) =>thenA promise was returnedif (self.status === 'resolved') {
            setTimeout(()=>{try {// An exception may occur when a successful callback is executed, so use this exception as the result of a promise2 errorletx = onFulfilled(self.value); // The new promise, i.ethenReturns the result / / return the result after execution of the current success callback may be promise resolvePromise (promise2, x, resolve, reject); } catch (e) { reject(e); }},0)} //setTimeout
        if (self.status === 'rejected') {
            setTimeout(()=>{
                try {
                    letx = onRejected(self.reason); resolvePromise(promise2,x,resolve,reject); } catch (e) { reject(e); }}}, 0)if (self.status === 'pending') {/ / wait to also want to pack a promise2 self. OnResolvedCallbacks. Push (() = > {setTimeout(()=>{
                    try {
                        letx = onFulfilled(self.value); resolvePromise(promise2,x,resolve,reject); } catch (e) { reject(e); }}}, 0)); self.onRejectedCallbacks.push(() => {setTimeout(()=>{
                    try {
                        letx = onRejected(self.reason); resolvePromise(promise2,x,resolve,reject); } catch (e) { reject(e); }}}, 0)); }});return promise2
}
module.exports = Promise;

Copy the code