What is a Promise

A way to turn asynchronous callback nested code into chained invocation.

Theoretical analysis:

A Promise must be in one of the following states:

  • Pending: Pending // initial value
  • Resolved: already solved
  • Rejected: has failed

In the pending state, it can be resolved/Rejected. It can be determined once and will not change after that.

The Promise accepts an executor function, calls it synchronously and hands it two resolved methods (resolved, Rejected) that must explicitly call one of them internally. After the resolution, clear the task list of the corresponding states added by THEN (resolved, Rejected state). This is an important step in making the asynchronous callback “connected” by Promise.

Each THEN call returns a default Promise instance (this supports the chained call then().then()). The Promise’s resolution value is selected and evaluated from the onResolved/onRejected call that the THEN accepts. Which one to choose is determined by the decision status of the upper Promise. OnResolved will be called someday and onRejected will be called when the Promise is fulfilled. At this point, the return value of the resolve callback cannot be directly resolved; if the return value is still a Promise, the evaluation will continue recursively until the value is non-PROMISE.

Since the implementation Promise

Read this article carefully: The most detailed handwritten Promise tutorial ever

Here’s my implementation: Not all the details in the PromiseA+ specification, but enough to understand the principle.

/** * Promise State: Pending, resolved, Rejected * *  * new Promise((resolve, reject) => { // resolve/reject }) * .then(() => {}, () => {}) * .catch(e => { ... }) * * /

class MyPromise {
    constructor(excuter) {
        this.state = "pending";
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedList = [];
        this.onRejectedList = [];

        const resolve = (value) = > {
            if (this.state === "pending") {
                this.state = "resolved";
                this.value = value;
                this.onResolvedList.forEach(cb= > {
                    cb(this.value); }); }};const reject = (reason) = > {
            if (this.state === "pending") {
                this.state = "rejected";
                this.reason = reason;
                this.onRejectedList.forEach(cb= > {
                    cb(this.reason); }); }};try {
            excuter(resolve, reject);
        } catch(error) { reject(error); }}then(onResolved, onRejected) {
        return new MyPromise((resolve, reject) = > {
            onResolved = typeof onResolved ===  "function" ? onResolved : value= > value;
            onRejected = typeof onRejected === "function" ? onRejected : (reason) = > {
                throw reason;
            };
            const _onResolved = () = > {
                setTimeout(() = > {
                    try {
                        let x = onResolved(this.value);
                        this.handlePromise(x, resolve, reject);
                    } catch(error) { reject(error); }}); };const _onRejected = () = > {
                setTimeout(() = > {
                    try {
                        let x = onRejected(this.reason);
                        this.handlePromise(x, resolve, reject);
                    } catch(error) { reject(error); }}); };if (this.state === "pending") {
                this.onResolvedList.push(() = > _onResolved());
                this.onRejectedList.push(() = > _onRejected());
            }
            if (this.state === "resolved") _onResolved();
            if (this.state === "rejected") _onRejected();
        });
    }

    catch(onRejected) {
        return this.then(null, onRejected);
    }

    /** * if x is Promise * x.then getValue * * if x not Proimse * return x */
    handlePromise(x, resolve, reject) {
        let called = false;
        try {
            if(x ! = =undefined&& x ! = =null && typeof x.then === "function") {
                if (called) return;
                called = true;
                x.then(v= > {
                    // maybe v also promise
                    setTimeout(() = > {
                        this.handlePromise(v, resolve, reject);
                    });
                }, (e) = > {
                    if (called) return;
                    called = true;
                    reject(e);
                });
            } else {
                if (called) return;
                called = true; resolve(x); }}catch (error) {
            if (called) return;
            called = true; reject(error); }}}// test
let p1 = new MyPromise((resolve, reject) = > {
    setTimeout(() = > {
        resolve("delay 100ms p1");
    }, 100);
}).then(v= > {
    console.log("then recvie value: ", v);
    return new MyPromise((resolve, reject) = > {
        setTimeout(() = > {
            resolve("delay 1000ms p1.then");
        }, 1000);
    });
}).then((v) = > {
    console.log("then recvie value: ", v);
    throw new Error("custom error");
}).catch(e= > {
    console.log("cactch error: ", e);
});
Copy the code

Other implementations

Promise. Reject

class MyPromise {
    / / to omit...
    reject(reason) {
        return new MyPromise((resolve, reject) = >{ rejected(reason); }); }}Copy the code

Promise. Resolve to achieve

class MyPromise {
    / / to omit...
    resolve(value) {
        return new MyPromise((resolve, reject) = >{ resolve(value); }); }}Copy the code

Promise. Catch

class MyPromise {
    / / to omit...
    catch(onRejected) {
        this.then(null, onRejected); }}Copy the code