Goal:

Implement A custom Promise to the PROMISE A+ specification

Why do Promises exist and what do promise specifications mean

Promise is a solution to JS asynchronous programming that has become the syntax standard for ES6. Es6 provides native Promise objects.

Promise A+ is A constraint and specification for this asynchronous operation.

English: PROMISE A+ specification English translation version: PROMISE A+ specification translation version

Leafing through the above documents, I found that the following requirements should be implemented:

  1. A promise state must be one of three states: Pending, Fulfilled, or Rejected

    1.1 When the status is determined, it cannot be changed

    1.2 The execution state must have an immutable final value and the rejection state must have an immutable cause

  2. You can synchronize resolve, async resolve

    2.1 Async Resolve (Reject) can be executed multiple times instead of once

  3. The then function can be called chained

    3.1 You need to return a new Promise object each time, rather than making chained calls by calling this

  4. The value of the previous THEN, return is used as an argument to the next callback

    4.1 If the return is not of the promise type, this parameter is used as the next callback parameter. If the return is of the PROMISE type, this parameter is used as the data produced by promise Resolve

  5. The then method recognizes itself and then continues calling.THEN, which needs to throw an exception.

  6. Implement exception catching with the constructor and resolve/reject

  7. Make the THEN method optional, passable or not

7.1 Change the THEN method to also passable non-function types

The 7.2 Promise A+ specification states that if two callbacks in A THEN method are not functions, they must be ignored.

  1. Implement the catch function

  2. Implement finally function

  3. Implement the resolve static method. If a promise object is passed, return it directly, otherwise wrap it as a Promise and return resolve.

  4. Implement the Reject static method

  5. Implement all static methods

  6. Implement the race static method

MyPromise code implementation

Task a

Determine the basic model for the Promise class. Resolve succeeds with a successful end value, reject fails with a failed cause, and the state is determined and cannot be changed.

Task 2

When MyPromise is applied multiple times then, the synchronous case is true and the asynchronous case is overwritten because then is executed immediately, but resolve and reject are not necessarily executed immediately. So when the pending state of resolve/reject is encountered, the callbacks are stored in the array. When the async is complete, the callbacks in the array are executed in turn when the resolve/reject call is made.

Task three

The THEN method makes a chain call and returns a new promise object. The small detail is that the promise returned by the THEN method is pending, so the resolve/reject operation is performed.

Task 4

The callback is injected into the next then’s resolve/reject argument, and the push function is used to execute the callback in the function.

The test code

let promise = new MyPromise((resovle, reject) = > {

    resovle('success')

})

promise.then(data= > {

    console.log(data)

    return 't1'

})

    .then(data= > {

    console.log(data)

    return new MyPromise(resovle= > resovle('sss'))

})

    .then(data= > {

    console.log(data)

})

Copy the code
Task five

If the then method callback returns itself, then an exception needs to be thrown. You don’t need any dynamic logic, you just need to handle the resolvePromise method, and add a parameter that represents the current promise object, but when the resolvePromise method is executed, the current Promise object is not constructed yet, so using a little trick, Make the execution of this resolvePromise asynchronous. Then you can get the current object.

The test code

let p1 = new MyPromise((resolve, reject) = > {

    resolve('success')

})

let p2 = p1.then(data= > {

    console.log(data)

    return p2

})

p2.then(data= > {

    console.log(data)

})

Copy the code
Task 6

Doing exception catching

Simple exception catching

Task 7

Arguments passed by the THEN method are processed; non-functions are ignored

then (successCallback, errorCallback) {

        // Make the THEN method optional

        // The native THEN method automatically resolves to value=>value if it is not a function

        successCallback = typeof successCallback === 'function' ? successCallback : value= > value

        errorCallback = typeof errorCallback === 'function' ? errorCallback : err= > { throw err }

        / /...

}

Copy the code
Task eight

The catch method is used to catch exceptions throughout the promise chain

Syntactic sugar

catch (failCallback) {

    return this.then(undefined, failCallback)

}

Copy the code
The task of nine

In the finally method, the finall method will be applied regardless of the state, and the promise object will be returned so that the call can continue.

The finally method needs to save the value of the previous one and pass it to the next one

 finally (callback) {

     return this.then(value= > {

         return MyPromise.resolve(callback()).then((a)= > value)

     }, reason => {

         return MyPromise.resolve(callback()).then((a)= > { throw reason })

     })

 }

Copy the code

  • After the above nine steps, you are ready to use some of the basic features of Promsie. Now add some static methods
    • Resolve, reject, all, and race
Task ten
// Implement the resolve function

static resolve (value) {

    if (value instanceof MyPromise) return value

    return new MyPromise(resolve= > {

        resolve(value)

    })

}

Copy the code
The task.
/ / reject

static reject (value) {

    if (value instanceof MyPromise) return value

    return new MyPromise((resolve, reject) = > {

        reject(value)

    })

}

Copy the code
The task.
/ / all

static all (array) {

    // Define an array to hold the promise results returned

    return new MyPromise((resovle, reject) = > {

        let index = 0

        let result = []

        for (let i = 0; i < array.length; i++) {

            let r = array[i]

            if (r instanceof MyPromise) {

                // Put the result of its resolve into the array

                r.then(data= > addData(i, data), err => reject(err))

            } else {

                addData(i, r)

            }

        }

        // The index of the data passed in must correspond to the index of the result returned

        function addData (i, value{

            result[i] = value

            index++

            // Reolve (); // Reolve (); // Reolve ()

            // ps: let hijacks the block-level scope. Although the for loop completes immediately, the index stored in the scope is the same as the index at the time of execution

            if (index === array.length) {

                resovle(result)

            }

        }

    })

}

Copy the code
The task.
/ / implementation of race

static race (array) {

    let flag = true

    return new MyPromise((resovle, reject) = > {

        for (let i = 0; i < array.length && flag; i++) {

            let r = array[i]

            if (r instanceof MyPromise) {

                r.then(data= > addData(data), err => reject(err))

            } else {

                addData(r)

            }

        }

        function addData (value{

            resovle(value)

            flag = false

        }

    })

}

Copy the code
conclusion

Promise is an important es6 standard. Writing a promise by hand can help you understand the implementation of the promise and make it more flexible in use. Promise not only solves the problem of callback hell, but also sets the standard for js asynchronous programming.