Basic concepts of Promise

Promise means

Promise is a solution to asynchronous programming. Simply put, it is a container that holds the result of an event that will end in the future. Syntactically, a Promise is an object from which to get messages for asynchronous operations.

The principle of Promise

Promise provides a container for processing asynchronous operations. The container outputs the results of the processor through three different states: Pending, depressing and Rejected. It receives the results of the asynchronous processing operation through then or catch methods and processes the results accordingly. Chained calls to the THEN method avoid traditional nested function callbacks and improve code readability.

The characteristics of the Promise

  1. The state of the Promise object is unaffected. This is a big pity. Promise has three states: Pending, fulfilled and Rejected. Only the result of an asynchronous operation can determine the current state, and no other operation can change that state
  2. Once the state changes, it never changes again, and you can get this result at any time. There are only two possibilities for the state of a Promise object to change: from pending to depressing and from pending to Rejected. As long as these two things happen, the state will not change. This is called resolved

The shortcoming of Promise

  1. It cannot be cancelled, as soon as it is created it will execute immediately and cannot be cancelled halfway
  2. If the callback function is not set, errors thrown inside a Promise cannot be reflected externally
  3. When in the pending state, it is impossible to know which stage is currently in progress

A simple implementation of Promise

  • Define MyPromise class. Define self properties and bindings in MyPromise

    class MyPromise {
        constructor (fn) {
            const that = this
            that._value = 0}}Copy the code
  • When MyPromise is instantiated, a function is passed as an argument, and resolve and reject are required as arguments. The implementation method is as follows:

    function tryCallTwo (fn, a, b) {
        try {
            fn (a, b)
        } catch (e) {
            return e
        }
    }
    Copy the code

    Call this method inside the MyPromise class to complete the binding of the passed FN function.

    class MyPromise {
        constructor (fn) {
            const that = this
            that._value = 0
            tryCallTwo (fn, function (value) {
                console.log(value) / / 2
            }, function (err) {
                console.log(err)
            })
        }
    }
    
    new MyPromise(function (resolve, reject) {
        resolve(2)})Copy the code

    The resolve or reject of the function passed in on instantiation is converted to a handler using tryCallTwo. From the print above, you can see that the second argument to the tryCallTwo method is the resolve handler passed in on instantiation. Inside the second argument in the tryCallTwo method of the MyPromise class, the resolve method is called as a handler. The MyPromise class is modified as follows:

    class MyPromise {
        constructor (fn) {
            const that = this
            that._value = 0
            tryCallTwo (fn, function (value) {
                console.log(value) / / 2
                resolve(that, value)
            }, function (err) {
                console.log(err)
            })
        }
    }
    Copy the code
  • Define the resolve method, which takes the current instance as the first argument and the value of resolve(2) as the second argument when instantiated. The resolve method is equivalent to changing the value of _value in the MyPromise class

    function resolve (self, newValue) {
        self._value = newValue
    }
    Copy the code
  • Now that the output of MyPromise has been resolved, you define the receive processing method then. Because THEN is an instance method, it is defined inside the MyPromise class

    class MyPromise {
        constructor (fn) {... } then (onFulfilled) {// Check if the argument passed to then is function
            let cb = typeof onFulfilled === 'function' ? onFulfilled : null
            // Add processing for cb if cb exists
            cb && tryCallOne(cb, that._value)
        }
    }
    Copy the code
  • Define the tryCallOne method

    tryCallOne (fn, a) {
        try {
            return fn (a)
        } catch (e) {
            return e
        }
    }
    Copy the code
  • Call the THEN method through the instance

    new MyPromise(function (resolve, reject) {
        resolve(3)
    }).then(res= > {
        console.log(res) / / 3
    })
    Copy the code

The complete code

// Implement the binding of two function arguments to the MyPromise constructor
function tryCallTow (fn, a, b) {
    try {
        fn(a, b)
    } catch (ex) {
        return ex
    }
}
// implement the function argument passing in the then method
function tryCallOne (fn, a) {
    try {
        return fn(a)
    } catch (ex) {
        return ex
    }
}
/ / resolve method
function resolve (self, newValue) {
    self._value = newValue
}
// noop method: passed as an argument to resolve when a simple datatype value is passed
class MyPromise {
    constructor(fn) {
        const that = this
        this._value = 0
        tryCallTow(fn, function (value) {
            resolve(that, value)
        }, function (err) {
            console.log(err)
        })
    }
    then (onFulfilled) {
        let cb = typeof onFulfilled === 'function' ? onFulfilled : null
        cb && tryCallOne(cb, this._value)
    }
}
Copy the code

Complete operation process

reference

  • Getting started with ECMAScript 6
  • Reference source: github.com/then/promis…