preface

Promise has become a must-have skill for front-end development. It mainly solves the callback hell problem caused by a large number of nested callback functions in asynchronous programming. In this article, I will study it with you in the form of learning notes. The content mainly includes the basic usage and handwriting two parts, suitable for beginners and want to in-depth understanding of the principle of small partners.

Know the Promise

  • CommonJSThe community came up with it firstPromiseThe specification, theES2015Is standardized and becomes a language specification
  • PromiseIs an object that indicates whether an asynchronous task succeeds or fails after completion. The initial state of any Promise object isPendingWhen the task succeeds, the status changes toFulfilled, and then performs a callback for the successful taskonFufilled; When the task fails, the status changes toRejected, and then performs the callback for the failed taskonRejected
  • States can only be created fromPendingintoFulfilledOr fromPendingbecomeRejectedThere are only two kinds of changes, and after the changes willCan’t beThis will be a big pity, which is very depressing. If I am invited tonight, this will be a pity. If I am not invited tonight, this will be my Rejected. It can’t be changed.

Promise basic usage

Step 1: Create an instance

Promise is a new global object in ES2015. Create a Promise instance with new and pass in an Executor function that starts executing immediately. The main business process is in the Executor function

const promise = new Promise((resolve,reject) = >{
    if(/* Asynchronous operation succeeded */){
        resolve('Executed successfully')}else{
        reject(new Error('Execution failed'))}})Copy the code

The resolve and reject functions are passed as arguments to the executor function

  • callresolveDelta function, and put ourPromiseChange the status toFulfilledAnd pass the result of the successful asynchronous operation as a parameter
  • callrejectDelta function, and put ourPromiseChange the status toRejectedAnd pass the reason why the asynchronous operation failed as a parameter
  • You can only call one or the other, either success or failure
  • It’s important to note that,PromiseIs used to manage asynchrony, but it’s not asynchrony itself,executorThe function will execute immediately, and we tend to be inexecutorWrite asynchronous operations in

Step 2: Call the then method

After the Promise instance is created, use its then method to specify the onFulfilled or onRejected callback function. The first parameter is onFulfilled and the second parameter is onFulfilled. Where onRejected can be omitted.

promise.then( value= >{
    console.log('resolved',value)
}, error= >{ // the onRejected callback can be omitted
    console.log('rejected',error)
})
Copy the code

Execution sequence

Even if we don’t perform any asynchronous operations, the callback in promise.then is executed after the JS has completed its synchronous task:

const promise = new Promise((resolve,reject) = >{
  console.log(1)
  resolve(100)
  console.log(2)
})
promise.then( value= >{
    console.log('resolved',value)
}, error= >{
    console.log('rejected',error)
})

console.log('3')

/* Output result */
/ / 1
/ / 2
/ / 3
// resolved 100
Copy the code

Execute the executor function first, printing 1 and 2. Resolve is a microtask, and proceed with the synchronization task. Store both the success and failure callbacks (stored in the variables of the Promie instance, as described in the handwritten Promise), do not execute them, and then print 3. At this point, the synchronization task is complete, the microtask is executed, and the success callback of the then method is called. Print Out Resolved 100

Then let’s add the timer:

const promise = new Promise((resolve,reject) = >{
  console.log(1)
  resolve(100)
  console.log(2)})// Add timer here, what is the order of execution?
setTimeout(() = >{
    console.log('setTimeout')},0)

promise.then( value= >{
    console.log('resolved',value)
}, error= >{
    console.log('rejected',error)
})

console.log('3')

/* Output result */
/ / 1
/ / 2
/ / 3
// resolved 100
// setTimeout
Copy the code

If setTimeout is 0, the system immediately enters the callback queue and waits for the next round of execution. There is a myth here, because setTimeout executes before Promise, we would think that setTimeout would be queued first, so it would execute first, but that’s not the case.

Because Promise belongs to the microtask, setTimeout belongs to the macro task. After the current synchronization code is executed, if there is a microtask, the microtask will be executed, if there is a macro task, it will wait until the next queue to execute. For the concept and difference between macro task and microtask, please refer to microtask, macro task and Event-loop

Microtasks are designed to improve overall responsiveness. In JS, most asynchronous tasks are macro tasks, and only Promise, MutationObserver and Process. nextTick in Node are executed as microtasks.

Common Mistakes

The essence of Promise is still callback. When the asynchronous task ends, callback is executed through then method. Some students will nest callback unnaturally, because they are not clear about the use of Promise and do not know the characteristics of chain invocation of Promise.

promiseA.then(function(value1){
    promiseB.then(function(value2){
        promiseC.then(function(value3){
            /* Callback hell */. })})})Copy the code

The chain call to Promise

The then method returns a new Promise object after execution, so you can use chained calls to avoid callback hell and make your code flat.

The chain invocation of a Promise differs from the traditional chain invocation:

  • Traditional chain calls return in a functionthis
  • PromiseThe chain call is inthenReturns a new one inPromiseobject
const promise1 = new Promise((resolve,reject) = >{
    resolve(100)})const promise2 = promise1.then((value) = >{
    console.log(value)
})
const promsie3 = promise2.then((value) = >{
    console.log(value)
})

console.log(promise1 === promise2) // false proves that a new Promise object is returned
console.log(promise2 === promise3) // false
Copy the code

Since then returns a new Promise, the current call to THEN adds a state-changed callback to the Promise returned by the previous THEN:

const promise = new Promise((resolve,reject) = >{
    resolve(100)})/* chain call */
promise
.then((value) = >{
    console.log('11111')
})
.then((value) = >{
    console.log('22222')
})
.then((value) = >{
    console.log('33333')})Copy the code

We can either manually return a new Promise in the THEN method, or we can return a plain value:

promise
.then((value) = >{
    // Manually return a new Promise
    return new Promise((resolve,reject) = >{
        resolve(800)
    })
})
.then((value) = >{
    console.log(value) / / 800
    // Manually return the normal value
    return 'hello promise'
})
.then((value) = >{
    console.log(value) // hello promise
})
.then((value) = >{
    console.log(value) // undefined returns no value for the last then
})
Copy the code

Exception handling

promise
.then(function(value){
    console.log(1)
})
.then(function(value){
    throw Error('error')
})
.then(function(value){
    console.log(2)
})
.catch(function(error){
    console.log('onRejected',error)
})
/ / output
/ / 1
// error
Copy the code
  • Used at the end of a chain callcatchCatch the exception and specify the failed callback
  • It catches all the exceptions in the whole chain call, sort of “bubbling”, passing them backwards until they are calledcatchcapture
  • This way, we don’t have to be in everythenIn the writingonRejectedCallbacks don’t have to be everythenWrite backcatch, which makes our code more elegant

A static method

Promise.resolve( )

If you receive a normal value, return a Promise with the normal value as a result

// Return the Fulfilled Promise object
Promise.resolve('hello world')
.then(value= >{
    console.log(value) // hello world
})
/ / equivalent to the
new Promise((resolve,reject) = >{
    resolve('hello world')})Copy the code

If another Promise object is received, it is returned as is

const promise = new Promise((resolve,reject) = >{})
const promise2 = Promise.resolve(promise)

console.log(promise === promise2) // true
Copy the code

Promise.reject( )

Return a failed Promise that will fail no matter what parameter is passed

cosnt promise = Promise.reject('hello world')
Copy the code

Promise.all( )

Combine multiple Promise instances into a new Promise instance that returns a different value for success than for failure, with success returning an array containing the execution results of each Promise, and failure returning the original REJECT value.

  • Promise.allWhen allPromiseA successful callback is executed if all objects succeed, and a failed callback is executed if any object fails
const promise = Promise.all([
    Promise.resolve({code:200.data: [1.2]}),
    Promise.resolve({code:200.data: [3.4]}),
    Promise.resolve({code:200.data: [5.6]}),
])

promise.then(function(values){
    console.log(values) // Values are an array containing the results of each promise asynchronous task
})
Copy the code

For example, if we want to request multiple interfaces at the same time and perform the next step when all data is returned, we can use the promise.all method

Note that the array of successful results obtained by promise. all is the same order as the instance passed in when calling Promise.all. In the above code, interface 1 is requested, interface 2 is requested, interface 3 is requested, even if interface 1 is the last to get the result, it is first.

Promise.allSettled( )

Sometimes we don’t care about the outcome of asynchronous operations, just whether they are finished, so we introduced the Promise.allSettled method in ES2020

Promise.allSettled([
    Promise.resolve({code:200.data: [1.2]}),
    Promise.reject({code:500.errMsg:'Server exception'}),
    Promise.resolve({code:200.data: [3.4]})
])
.then(function(values){
    console.log(values)
})
Copy the code

Promise.allsettled is very similar to promise.all, except that Promise.AllSettled will get the state of every Promise, whether it succeeds or fails.

Promie.race( )

Multiple Promise calls are also supported, but unlike promise.all, race stands for a race, and promise.race ([P1,p2,p3]) returns whichever result executes fastest, whether it succeeds or fails

  • Promise.allThe newly returned Promise will not be completed until all tasks have been completed
  • Promise.raceAs long as one task succeeds, the newly returned Promise succeeds, and as long as one Promise fails, the returned Promise fails

Promise.finally( )

In ES9, the finally method will execute the callback function specified by the finally function, no matter the result is pity or Rejected. This avoids the situation where we write operations in then and catch respectively

// Make the page go around while requesting the interface
this.loading = true

axios.get('http://juejin.cn/api')
    .then(res= > {
        // this.loading = false
    })
    .catch(err= > {
        // this.loading = false
    })
    .finally(() = > {
        this.loading = false
    })
Copy the code

Write a Promise

We couldn’t just lay out the full Promise code because it wouldn’t make sense. We had to start from scratch and work our way through it. So I write comments at key points in each step and learn by comparing the code before and after. It seems like a lot of code, but the emphasis is on incremental code.

A basic Promise

To write promises by hand, summarize how they’ll be used and their features:

  • PromisethroughnewCome out, it must be a constructor or a class, and we’ll implement it as a class
  • Receives an executor functionexecutorAnd can be executed immediately
  • The executor function receivesresolverejectThey are used for changePromiseThe state of the
  • PromiseThere are three states:Pendding,Fulfilled,RejectedAnd once it is determined, it cannot be changed
  • throughthenMethod determines the status and executes if it succeedsonFulfilledIf the command fails, the command is executedonRejected
// Define three state constants
const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class MyPromise {
    // Receive an executor function
    constructor(executor) {
        Execute executor immediately, passing resolve and reject
        executor(this.resolve, this.reject)
    }
    // Each Promise instance has its own state, starting with PENDDING
    status = PENDDING
    
    // Cache success results and failure causes
    value = undefined
    reason = undefined

    resolve = value= > {
        /** * 1. After the asynchronous function of the business code succeeds, call resolve and pass in the success value value * 2. We call resolve directly from executor. If this were a normal function, this would point to the window. We need this to point to the Promise instance * 4. If the state is not PENDDING, changes are not allowed */
        if (this.status ! == PENDDING)return

        this.status = FULFILLED

        // Save the successful value for future use in successful callbacks to the THEN method
        this.value = value
    }

    reject = reason= > {
        // Similar to resolve, reject is used to handle asynchronous task failures
        if (this.status ! == PENDDING)return

        this.status = REJECTED

        // Save the cause of the failure for future use in the failure callback of the then method
        this.reason = reason
    }

    /** * 1. Each Promise instance has then methods, so define THEN in the class * 2. The THEN method takes two arguments, a success callback and a failure callback * 3. Determine which callback to call based on the state and pass in the corresponding value */
    then(onFulfilled, onRejected) {
        if (this.status === FULFILLED) {
            onFulfilled(this.value)
        } else if (this.status === REJECTED) {
            onRejected(this.reason)
        }
    }

}
// Don't forget to export
module.exports = MyPromise
Copy the code

Test if it’s available

const MyPromise = require('./promise.js')

let promise = new MyPromise((resolve, reject) = > {
    resolve('success')
})

promise.then(value= > {
    console.log(value)
}, reason= > {
    console.log(reason)
})
Copy the code

Handling asynchronous cases

Next, in the asynchronous case of the business, we add a timer to the business code

const MyPromise = require('./promise.js')

let promise = new MyPromise((resolve, reject) = > {
    // Async
    setTimeout(() = >{
        resolve('success');
    },2000)})// The main thread does not wait for setTimeout, but executes here first
promise.then(value= > {
    console.log(value)
}, reason= > {
    console.log(reason)
})
Copy the code

The main thread does not wait for setTimeout to execute down to then, but resolve or reject has not yet been executed, which means that the Promise state is still PENDDING, so add a judgment to then: If the state is PENDDING, store the onFulfilled and onRejected callback functions first, and then invoke the callback function when the resolve or Reject callback is performed after the asynchronous task is completed

const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    
    status = PENDDING
    
    value = undefined
    reason = undefined
    
    // Cache successful callback and failed callback
    onFulfilled = undefined
    onRejected = undefined

    resolve = value= > {
        if (this.status ! == PENDDING)return

        this.status = FULFILLED

        this.value = value

        /** * For asynchrony, check whether the successful callback exists and call */ if so
        this.onFulfilled && this.onFulfilled(this.value)
    }

    reject = reason= > {
        if (this.status ! == PENDDING)return

        this.status = REJECTED

        this.reason = reason

        /** * For asynchrony, check whether the failed callback exists and call */ if it does
        this.onRejected && this.onRejected(this.reason)
    }

    then(onFulfilled, onRejected) {
        if (this.status === FULFILLED) {
            onFulfilled(this.value)
        } else if (this.status === REJECTED) {
            onRejected(this.reason)
        } else {
            /** * If it is PENDDING, it is asynchronous ** But we do not know whether it will succeed or fail in the future, so store them for now ** /
            this.onFulfilled = onFulfilled
            this.onRejected = onRejected
        }
    }
}

module.exports = MyPromise
Copy the code

Handle multiple callback cases

The then method is called multiple times, passing in either a successful or a failed callback that is to be executed, so modify it by storing these functions in an array and calling resolve and reject in turn

const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }

    status = PENDDING

    value = undefined
    reason = undefined


    // Use an array to store these callbacks instead
    // onFulfilled = undefined
    // onRejected = undefined
    onFulfilled = []
    onRejected = []

    resolve = value= > {
        if (this.status ! == PENDDING)return

        this.status = FULFILLED

        this.value = value

        // Call all callbacks instead of just once
        // this.onFulfilled && this.onFulfilled(this.value)
        while (this.onFulfilled.length) {
            this.onFulfilled.shift()(this.value)
        }

    }

    reject = reason= > {
        if (this.status ! == PENDDING)return

        this.status = REJECTED

        this.reason = reason

        // Call all callbacks instead of just once
        // this.onRejected && this.onRejected(this.reason)
        while (this.onRejected.length) {
            this.onRejected.shift()(this.reason)
        }
    }

    then(onFulfilled, onRejected) {
        if (this.status === FULFILLED) {
            onFulfilled(this.value)
        } else if (this.status === REJECTED) {
            onRejected(this.reason)
        } else {
            // There can be multiple callbacks, all stored
            // this.onFulfilled = onFulfilled
            // this.onRejected = onRejected
            this.onFulfilled.push(onFulfilled)
            this.onRejected.push(onRejected)
        }
    }
}

module.exports = MyPromise
Copy the code

Chain calls to the then method

  • thenMethods can be called chained, and each time they returnPromiseobject
  • On athenIs passed to the currentthenThe callback function of
const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }

    status = PENDDING

    value = undefined
    reason = undefined

    onFulfilled = []
    onRejected = []

    resolve = value= > {
        if (this.status ! == PENDDING)return

        this.status = FULFILLED

        this.value = value

        while (this.onFulfilled.length) {
            this.onFulfilled.shift()(this.value)
        }

    }

    reject = reason= > {
        if (this.status ! == PENDDING)return

        this.status = REJECTED

        this.reason = reason

        while (this.onRejected.length) {
            this.onRejected.shift()(this.reason)
        }
    }

    then(onFulfilled, onRejected) {
        The /** * then method needs to return a new Promise instance that implements the chain call */
        const newPromise = new MyPromise((resolve, reject) = > {
            if (this.status === FULFILLED) {
                // Get the success callback value of the current then
                let current = onFulfilled(this.value)

                /** * current may be a promise or a normal value, which is different for different cases. * if it is a normal value, call resolve. Call resolve or reject * we encapsulate the process into a function, which can be used in the same way as onRejected * we also need to compare newPromise and current to prevent them from being the same promise. That is, the problem with circular calls * */
                resolvePromise(newPromise, current, resolve, reject)
            } else if (this.status === REJECTED) {
                let current = onRejected(this.reason)
                resolvePromise(current, resolve, reject)
            } else {
                this.onFulfilled.push(onFulfilled)
                this.onRejected.push(onRejected)
            }
        })

        return newPromise
    }
}

function resolvePromise(newPromise, current, resolve, reject) {
    if (current === newPromise) {
        return reject(new TypeError('Cannot loop'))}if (current instanceof MyPromise) {
        current.then(value= > {
            resolve(value)
        }, reason= > {
            reject(reason)
        })
    } else {
        resolve(current)
    }
}
module.exports = MyPromise
Copy the code

If you are careful, you will notice that newPromise is returned after the execution of newPromise is completed. The newPromise passed in when we call resolvePromise is not available yet, so we use setTimeout to convert it into asynchronous code

then(onFulfilled, onRejected) {

    const newPromise = new MyPromise((resolve, reject) = > {
        if (this.status === FULFILLED) {
            // Switch to asynchronous code to get newPromise
            setTimeout(() = > {
                let current = onFulfilled(this.value)
                resolvePromise(newPromise, current, resolve, reject)
            }, 0);
        } else if (this.status === REJECTED) {
            setTimeout(() = > {
                let current = onRejected(this.reason)
                resolvePromise(current, resolve, reject)
            }, 0);
        } else {
            this.onFulfilled.push(onFulfilled)
            this.onRejected.push(onRejected)
        }
    })

    return newPromise
}
Copy the code

Error handling mechanism

  • If the executor function fails, it should be inconstructorIs captured and thrown
  • ifonFulfilledoronRejectedErrors should also be caught and thrown
const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class MyPromise {
    constructor(executor) {
        // Catch an error in the executor function
        try {
            executor(this.resolve, this.reject)
        } catch (err) {
            this.reject(err)
        }
    }

    status = PENDDING

    value = undefined
    reason = undefined

    onFulfilled = []
    onRejected = []

    resolve = value= > {
        if (this.status ! == PENDDING)return

        this.status = FULFILLED

        this.value = value

        while (this.onFulfilled.length) {
            // No need to pass the value
            // this.onFulfilled.shift()(this.value)
            this.onFulfilled.shift()()
        }

    }

    reject = reason= > {
        if (this.status ! == PENDDING)return

        this.status = REJECTED

        this.reason = reason

        while (this.onRejected.length) {
            // No need to pass the value
            // this.onRejected.shift()(this.reason)
            this.onRejected.shift()()
        }
    }

    then(onFulfilled, onRejected) {

        const newPromise = new MyPromise((resolve, reject) = > {
            if (this.status === FULFILLED) {
                setTimeout(() = > {
                    // Catch ondepressing's mistake
                    try {
                        let current = onFulfilled(this.value)
                        resolvePromise(newPromise, current, resolve, reject)
                    } catch (err) {
                        reject(err)
                    }
                }, 0);
            } else if (this.status === REJECTED) {
                setTimeout(() = > {
                    // Catch an error from onRejected
                    try {
                        let current = onRejected(this.reason)
                        resolvePromise(current, resolve, reject)
                    } catch (err) {
                        reject(err)
                    }
                }, 0);
            } else {
                // Catch the error onFulfilled and onRejected
                // this.onFulfilled.push(onFulfilled)
                // this.onRejected.push(onRejected)
                this.onFulfilled.push(() = > {
                    setTimeout(() = > {
                        // Catch ondepressing's mistake
                        try {
                            let current = onFulfilled(this.value)
                            resolvePromise(newPromise, current, resolve, reject)
                        } catch (err) {
                            reject(err)
                        }
                    }, 0);
                })
                this.onRejected.push(() = > {
                    setTimeout(() = > {
                        // Catch an error from onRejected
                        try {
                            let current = onRejected(this.reason)
                            resolvePromise(current, resolve, reject)
                        } catch (err) {
                            reject(err)
                        }
                    }, 0); })}})return newPromise
    }
}

function resolvePromise(newPromise, current, resolve, reject) {
    if (current === newPromise) {
        return reject(new TypeError('Cannot loop'))}if (current instanceof MyPromise) {
        current.then(value= > {
            resolve(value)
        }, reason= > {
            reject(reason)
        })
    } else {
        resolve(current)
    }
}
module.exports = MyPromise
Copy the code

Realize the Promise. All ()

  • Promise.allIt’s a static methodstaticThe statement
  • Receives an array, one for each entryPromiseInstance or ordinary value, iterates through the array when allPromiseAfter the execution, the result is returned
// promise. all is a static method declared static
static all(array) {
    let result = [];
    / / counter
    let index = 0;
    return new MyPromise((resolve, reject) = > {
        function addData(key, value) {
            result[key] = value;
            index++;
            /** * If the for loop is complete and the asynchronous function has not returned a result, resolve will fail * so we wait for the loop to complete before we execute resolve ** /
            if(index === array.length) { resolve(result); }}for (let i = 0; i < array.length; i++) {
            let data = array[i];
            if (data instanceof MyPromise) {
                // Data is the case for the Promise object
                data.then(value= > addData(i, value), reason= > reject(reason))
            } else {
                // data is a normal value
                addData(i, data)
            }
        }
    })
}
Copy the code

Implement promise.resolve () and promise.reject ()

These two are relatively simple, direct masturbation!

static resolve(value) {
    return new MyPromise((resolve, reject) = > {
        resolve(value)
    })
}

static reject(value) {
    return new MyPromise((resolve, reject) = >{ reject(err); })}Copy the code

If finally’s callback returns an asynchronous Promise object

To realize the catch

If we call the THEN method without passing a failure callback, the error will eventually be caught by a catch

catch (onRejected) {
    return this.then(undefined, onRejected)
}
Copy the code

Complete code

const PENDDING = 'PENDDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject)
        } catch (err) {
            this.reject(err)
        }
    }

    status = PENDDING

    value = undefined
    reason = undefined

    onFulfilled = []
    onRejected = []

    resolve = value= > {
        if (this.status ! == PENDDING)return

        this.status = FULFILLED

        this.value = value

        while (this.onFulfilled.length) {
            this.onFulfilled.shift()()
        }

    }

    reject = reason= > {
        if (this.status ! == PENDDING)return

        this.status = REJECTED

        this.reason = reason

        while (this.onRejected.length) {
            this.onRejected.shift()()
        }
    }

    then(onFulfilled, onRejected) {

        const newPromise = new MyPromise((resolve, reject) = > {
            if (this.status === FULFILLED) {
                setTimeout(() = > {
                    try {
                        let current = onFulfilled(this.value)
                        resolvePromise(newPromise, current, resolve, reject)
                    } catch (err) {
                        reject(err)
                    }
                }, 0);
            } else if (this.status === REJECTED) {
                setTimeout(() = > {
                    try {
                        let current = onRejected(this.reason)
                        resolvePromise(current, resolve, reject)
                    } catch (err) {
                        reject(err)
                    }
                }, 0);
            } else {
                this.onFulfilled.push(() = > {
                    setTimeout(() = > {
                        try {
                            let current = onFulfilled(this.value)
                            resolvePromise(newPromise, current, resolve, reject)
                        } catch (err) {
                            reject(err)
                        }
                    }, 0);
                })
                this.onRejected.push(() = > {
                    setTimeout(() = > {
                        try {
                            let current = onRejected(this.reason)
                            resolvePromise(current, resolve, reject)
                        } catch (err) {
                            reject(err)
                        }
                    }, 0); })}})return newPromise
    }

    static all(array) {
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) = > {
            function addData(key, value) {
                result[key] = value;
                index++;
                if(index === array.length) { resolve(result); }}for (let i = 0; i < array.length; i++) {
                let data = array[i];
                if (data instanceof MyPromise) {
                    data.then(value= > addData(i, value), reason= > reject(reason))
                } else {
                    addData(i, data)
                }
            }
        })
    }

    static resolve(value) {
        return new MyPromise((resolve, reject) = > {
            resolve(value)
        })
    }

    static reject(value) {
        return new MyPromise((resolve, reject) = >{ reject(err); })}catch (onRejected) {
        return this.then(undefined, onRejected)
    }
}

function resolvePromise(newPromise, current, resolve, reject) {
    if (current === newPromise) {
        return reject(new TypeError('Cannot loop'))}if (current instanceof MyPromise) {
        current.then(value= > {
            resolve(value)
        }, reason= > {
            reject(reason)
        })
    } else {
        resolve(current)
    }
}

module.exports = MyPromise
Copy the code

Write in the last

Write here basically almost, although there are points that can be optimized in the code, but through the arrangement of this article, we have deepened the impression of Promise again, learning is a process of forgetting, we need to continue to consolidate and deepen memory, come on, friends!

The resources

  • Do you really know Promise
  • Promise from entry to the handwritten | [Promise a series]