Promise code implementation points

1. Promise is a class that needs to pass in an executable function during execution. This function is executed immediately and the state of the Promise changes from pending to Fufilled or Rejected after execution.

The first steps are roughly as follows:

const PENDING = 'pending'; // this is a big pity; // const REJECTED = 'REJECTED '; Constructor (executor) {// Use a try catch to handle possible errors in the constructor. this.reject) } catch (e) { this.reject(e); }} status = PENDING // Value returned after the execution succeeds value = undefined // Value returned after the execution fails Reason = undefined resolve = (value) => {// If the state is not a wait state, you cannot execute if(this.status! == PENDING) return this.status = FULFILLED this.value = value this.successCallback && this.successCallback(this.value) }  reject = (error) => { if(this.status ! == PENDING) return this.status = REJECTED this.reason = error this.failCallback && this.failCallback(this.reason) } then  (successcallback,failcallback) { if(this.status === FULFILLED){ successcallback(this.value) } else if(this.status === REJECTED) { failcallback(this.reason) } } } module.exports = MyPromise;Copy the code

Call this class in another file:

const MyPromise = require('./myPromise') function p1() { return new MyPromise((resolve,reject) => { resolve('success') }  let promise1 = p1()Copy the code

If you want to use the then method to call a success callback or a failure callback based on the state, add this method to the class:

then (successcallback,failcallback) {
        if(this.status === FULFILLED){
            successcallback(this.value)
        }
        else if(this.status === REJECTED) {
            failcallback(this.reason)
        }
    }

promise1.then((data)=>{
    console.log(data);
},error => {
    console.log(error);
})
Copy the code

At this point, a similar step operation code preliminary implementation

Add asynchronous operations to functions

function p1() {
    return new MyPromise((resolve,reject) => {
        setTimeout(() => {
            resolve('success')
        }, 2000);
     
}
let promise1 = p1()
promise1.then(data => {
    
})
Copy the code

Then modify the then, resolve, reject methods:

// Callback successCallback = undefined; // failCallback = undefined; Resolve = (value) => {// If (this.status! == PENDING) return this.status = FULFILLED this.value = value this.successCallback && this.successCallback(this.value) }  reject = (error) => { if(this.status ! == PENDING) return this.status = REJECTED this.reason = error this.failCallback && this.failCallback(this.reason) } then  (successcallback,failcallback) { if(this.status === FULFILLED){ successcallback(this.value) } else if(this.status === Failed) {failCallback (this.reason)} else {this.SuccessCallback = successCallback when pendding else {this.successCallback = FailCallback this.failCallback = failcallback } }Copy the code

This is the beginning of asynchronous operations, but only if the THEN method is called once. If the THEN method is called multiple times:

1. Define successCallback and failCallback as arrays so they can receive multiple callbacks in pendding state.

2. Call the resolve and reject callbacks in each array

// Callback successCallback = []; // failCallback = []; Resolve = (value) => {// If (this.status! == PENDING) return this.status = FULFILLED this.value = value while (this.successCallback.length) { this.successCallback.shift()(value) } } reject = (error) => { if (this.status ! == PENDING) return this.status = REJECTED this.reason = error while (this.failCallback.length) { this.failCallback.shift()(error) } } then(successcallback, failcallback) { if (this.status === FULFILLED) { successcallback(this.value) } else if (this.status === REJECTED) { Failcallback (enclosing a tiny)} / / state is pendding else {this. SuccessCallback. Push (successCallback) this.failCallback.push(failcallback) } }Copy the code

Chain uses the then method

When we chain the THEN method in a promise, the result of the current THEN execution can be passed to the next THEN method, and the result of that execution must be a Promise object

promise1.then(data => { return 1000; }).then(data => {console.log(data) // this will print the result returned by the previous callback function})Copy the code

Modifications in the then method:

then(successcallback, failcallback) { let promise2 = new MyPromise((resolve, reject) => { if (this.status === FULFILLED) { let res1 = successcallback(this.value); resolve(res1); } else if (this.status === REJECTED) { let err1 = failcallback(this.reason)reject(err1); } / / state is pendding else {this. SuccessCallback. Push (successCallback) enclosing failCallback. Push (failCallback)}}) return promise2; }Copy the code

However, there is no judgment on the type of RES1, which can have either a normal value or a Promise object,

1. If the value is normal, call resolve directly

2. If it is a Promise, look at the result returned by the Promise and decide whether to call resolve or reject

Both of the preceding steps must be performed once the status succeeds or fails

ResolvePromise (res, resolve, Reject) {if (res instanceof MyPromise) {// Promise object res.then(value => resolve(value), reason => reject(reason)); } else {resolve(res); } } then(successcallback, failcallback) { let promise2 = new MyPromise((resolve, reject) => { if (this.status === FULFILLED) { let res1 = successcallback(this.value); resolvePromise(res1, resolve, reject) } else if (this.status === REJECTED) { let err1 = failcallback(this.reason) resolvePromise(err1, resolve, Reject)} / / state is pendding else {this. SuccessCallback. Push (successCallback) enclosing failCallback. Push (failCallback)}}) return promise2; }Copy the code

Test code:

function p1() { return new MyPromise((resolve, reject) => { resolve('success') }) } function p2() { return new MyPromise(function (resolve, reject) { resolve('p2') }) } let promise1 = p1(); promise1.then((data) => { console.log(data); //success return p2(); }).then(value => { console.log(value); //p2 })Copy the code

The callback currently executed in a Promise cannot return the object itself, so we need to add a check to the then method to determine if the result of the execution is the object itself

then(successcallback, failcallback) { let promise2 = new MyPromise((resolve, (this. Status === = depressing) {// This is asynchronous because the promise2 will be transferred to another function, so setTimeout(() => {let res1 = successcallback(this.value); resolvePromise(promise2, res1, resolve, reject) }, 0); } else if (this.status === REJECTED) { let err1 = failcallback(this.reason)resolvePromise(err1, resolve, Reject)} / / state is pendding else {this. SuccessCallback. Push (successCallback) enclosing failCallback. Push (failCallback)}}) return promise2; } function resolvePromise(promise2, res, resolve, reject) { if (promise2 === res) { return reject(new TypeError('Chaining cycle detected for promise #<Promise>')) } if (res instanceof MyPromise) {// The promise object res.then(value => resolve(value), reason => reject(reason)); } else {resolve(res); }}Copy the code

At this point, the core part of then method is basically completed, but the error state has not been captured and processed

then(successcallback, failcallback) { let promise2 = new MyPromise((resolve, (this. Status === = depressing) {// This is a big pity. SetTimeout (() => {try { let res1 = successcallback(this.value); ResolvePromise (promise2, res1, resolve, reject)} catch (e) {// Pass the error to the next promise, reject(e)}, 0); } else if (this.status === REJECTED) { setTimeout(() => { try { let err1 = failcallback(this.reason) resolvePromise(promise2, err1, resolve, reject) } catch (e) { reject(e) } }, 0); } / / state is pendding else {/ / here will result in implementation of the callback function to process this. SuccessCallback. Push (() = > {try {let res = successcallback(this.value) resolvePromise(promise2, res, resolve, reject) } catch (e) { reject(e) } }) this.failCallback.push(() => { try { let err = failcallback(this.reason) resolvePromise(promise2, err, resolve, reject) } catch (e) { reject(e) } }) } }) return promise2; }Copy the code

The callback function in the then method is optional

In addition, when a promise object chain-calls the THEN method several times, no parameter is passed in the preceding THEN method, and the parameter in the last THEN method is the return value of the previous callback function (THEN), that is, the parameter of the THEN method is optional. The then method evaluates the two callback functions passed in, and does something else if the function passed is null:

Successcallback = SuccessCallback? successcallback : value => value; failcallback = failcallback ? failcallback : error => { throw error }Copy the code

Test code:

let promise1 = new MyPromise((resolve, reject) => {
    resolve('success')
    // reject("fail")});
    promise1.then().then().then(data => {
        console.log(25);
        console.log(data);
    }, err => {
        console.log(err);
    })
Copy the code

The realization of the Promise. All

The all method receives an array, which can contain common values and Promise instance objects. During implementation, all the Promise objects in the array will be fulfilled, and then an array of results will be returned. However, if the state of one of the Promise objects fails during execution, the Reject callback is directly triggered to return the failure value

Static all(array) {// result = [] let count = array.length; return new MyPromise((resolve, reject) => { if (! Array.isArray(array)) { return reject(new Error("The args must be array type")) } function normalData(key, value) { result[key] = value count--; If (count == 0) {resolve(result)}} if (count == 0) {resolve(result)}} i < array.length; i++) { const current = array[i]; if (current instanceof MyPromise) { current.then(value => normalData(i, value), Error => reject(error))} else {// normalData(I, array[I])}}})}Copy the code

Test code:

function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('success')
        }, 2000);
    })
}
function p2() {
    return new MyPromise((resolve, reject) => {
        reject('p2')
    })
}
MyPromise.all([1, 2, p1(), p2(), 44]).then(res => {
    console.log(res);
}, err => {
    console.log("22" + err);
})
Copy the code

The realization of the Promise. Resolve

The resolve method is a simple one. If it is a promise object, it will be returned. Otherwise, a Promise object will be instantiated inside the method, and an executor will be passed in the newly instantiated object to call the Resolve method and return the promise object.

static resolve(value) {
    if (value instanceof MyPromise)
        return value else {
            return new MyPromise(resolve => resolve(value))
        }
}
Copy the code

Test code:

function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {

            resolve('success')
        }, 2000);
    })
}

MyPromise.resolve(1000).then(res => {
    console.log(res);
})
MyPromise.resolve(p1()).then(res => {
    console.log(res);
})
Copy the code

The realization of the Promise. Finally

Finally method is characterized by the execution of the current promise object regardless of whether the result of the final execution is successful or failed, and can chain call then method to get the current promise object execution result;

finally(callback) { return this.then((value) => { callback() return value; },(error) => { callback() throw error; })}Copy the code

Test code:

function p2() { return new MyPromise(function (resolve, Reject) {resolve (p2 'success')})} p2 (.) finally (() = > {the console. The log (" callback "); }).then(res => { console.log(res); })Copy the code

There is a problem with this code. If we return a promise object in the finally callback, the finally method waits for the promise to complete, so we need to do:

1. Determine whether the callback returns a normal value or a Promise object

2. Either a normal value (converted to a Promise object) or a promise object waits for it to complete and returns the resulting value

finally (callback) {
            return this.then((value) => {
                return MyPromise.resolve(callback()).then(value => value)

            }, (error) => {
                return MyPromise.resolve(callback()).then(error => {
                    throw error
                })

            })
        }
Copy the code

Test code:

function p1() { return new MyPromise((resolve, reject) => { setTimeout(() => { // resolve('success') reject("fail p1") }, 2000); }) } function p2() { return new MyPromise(function (resolve, Reject) {/ / resolve (' p2 success) reject (p2 "fail")})} p2 (.) finally (() = > {the console. The log (" callback "); return p1() }).then(res => { console.log(res); }, err => { console.log(err); })Copy the code

Catch method

This method is used to handle cases where the current promise object ends up in a failed state, i.e. failed callbacks are not passed in then, and then failed callbacks are caught by a catch

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

Test code:

function p2() {
    return new MyPromise((resolve, reject) => {
        resolve('p2 success')
        // reject("p2 fail")
    })
}
p2().catch(err => {
    console.log(err);
}).then(res => {
    console.log(res);
})
Copy the code

Complete code:

const PENDING = 'pending'; // this is a big pity; // const REJECTED = 'REJECTED '; Constructor (executor) {// Use a try catch to handle possible errors in the constructor. this.reject) } catch (e) { this.reject(e); }} status = PENDING // Value returned after the execution succeeds value = undefined // Value returned after the execution fails Reason = undefined // Callback successCallback = []; // failCallback = []; Resolve = (value) => {// If (this.status! == PENDING) return this.status = FULFILLED this.value = value while (this.successCallback.length) { this.successCallback.shift()() } } reject = (error) => { if (this.status ! == PENDING) return this.status = REJECTED this.reason = error while (this.failCallback.length) { this.failCallback.shift()(error) } } then(successcallback, failcallback) { successcallback = successcallback ? successcallback : value => value; failcallback = failcallback ? failcallback : error => { throw error } let promise2 = new MyPromise((resolve, (this. Status === = depressing) {// This is a big pity. SetTimeout (() => {try { let res1 = successcallback(this.value); ResolvePromise (promise2, res1, resolve, reject)} catch (e) {// Pass the error to the next promise, reject(e)}, 0); } else if (this.status === REJECTED) { setTimeout(() => { try { let err1 = failcallback(this.reason) resolvePromise(promise2, err1, resolve, reject) } catch (e) { reject(e) } }, 0); } / / state is pendding else {/ / here will result in implementation of the callback function to process this. SuccessCallback. Push (() = > {try {let res = successcallback(this.value) resolvePromise(promise2, res, resolve, reject) } catch (e) { reject(e) } }) this.failCallback.push(() => { try { let err = failcallback(this.reason) resolvePromise(promise2, err, resolve, reject) } catch (e) { reject(e) } }) } }) return promise2; } static all(array) {let result = [] let count = array.length; return new MyPromise((resolve, reject) => { if (! Array.isArray(array)) { return reject(new Error("The args must be array type")) } function normalData(key, value) { result[key] = value count--; if (count == 0) { console.log("108" + " " + result); Resolve (result)}} for (let I = 0; i < array.length; i++) { const current = array[i]; if (current instanceof MyPromise) { current.then(value => normalData(i, value), Error => reject(error))} else {// normalData(I, array[i]) } } }) } static resolve(value) { if (value instanceof MyPromise) return value else { return new MyPromise(resolve => resolve(value)) } } finally (callback) { return this.then((value) => { return MyPromise.resolve(callback()).then(value => value) }, (error) => { return MyPromise.resolve(callback()).then(error => { throw error }) }) } catch (failCallback) { return this.then(undefined, failCallback) } } function resolvePromise(promise2, res, resolve, reject) { if (promise2 === res) { return reject(new TypeError('Chaining cycle detected for promise #<Promise>')) } if (res instanceof MyPromise) {// The promise object res.then(value => resolve(value), reason => reject(reason)); // res.then(resolve, reject); } else {resolve(res); } } module.exports = MyPromise;Copy the code