This is the third day of my participation in the August More Text Challenge

preface

This article writes a basic version of promise to understand its common approach. Methods involved include THEN, all, race, resolve, reject, finally, and catch. All, race, resolve, reject are static methods, that is, static keyword is added before method name (in this article, THEN and all are implemented first).

Create a promise

Use the class keyword to name the class. Set two properties promiseState and promiseResult, starting with pending and undefined, respectively. The constructor accepts a function type argument, which can also accept resolve and reject for successful and failed callbacks.

// Set the global status value for easy management
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECT = 'reject';

class MyPromise {
    PromiseState = PENDING;
    PromiseResult = undefined;

    constructor (exectutor) {
        try {
            exectutor(this.resolve.bind(this), this.reject.bind(this));
        } catch (err) {
            this.reject(err);
        }
    }

    resolve (val) {
        if (this.PromiseState ! == PENDING)return; // The current state must be pending when the state needs to be changed
        this.PromiseState = FULFILLED;
        this.PromiseResult = val;
    }

    reject (reason) {
        if (this.PromiseState ! == PENDING)return;
        this.PromiseState = REJECT;
        this.PromiseResult = reason; }}Copy the code

Then method

Define < / br >1, accepts two callback functions </br>2If the state becomes successful, execute the first callback </br>3If the state changes to failed, the second callback </br> is executed4If the state becomes undetermined, keeping the current two callbacks </br> then returns a new onePromise</br> If the return value is a PROMISE object and </br> returns a success, the new PROMISE is a success and </br> returns a failure, </br> If the return value is not a PROMISE object </br> The new promise is a success and its value is the return value </br> In particular, if the second callback is not a function, the new promise must be a failed state with an error message </br>Copy the code

First, the incoming callback functions are typed to determine whether they are functions. Here use Object. The prototype. ToString. Call can detect arrow function, if is the typeof is to detect the arrow function. For the first callback, if it is not a function, you can simply provide an arrow function that returns the input parameter. For the second callback, if it is not a function, to make the returned PROMISE fail, simply throw an exception that is the value passed in. Then because a Promise object is to be returned, define a new promise object for return, because in each condition the logic of the specific code is similar, the repetition rate is high, so propose a public method out; This public method receives different callbacks that are executed in the same state, with specific logic for the new Promise state.

For example, if the first callback is called in the successful state, you can determine the result of the callback: Define a variable that receives the return value of the callback and, if the return value is a Promise object, changes the new promise state by indirectly executing resolve or REJECT of the new promise through its then method. If the return is not a PROMISE object, the state of the new PROMISE is successful, so its (new Promise) resolve method is executed directly. Since the then method is a chain invocation, it should not appear that the promise before then is exactly the same as the promise after it, so a conditional judgment if (x === then promise) is added. In this conditional judgment, Since you want to use thenPromise itself, you need to ensure that thenPromise has a value at this point, implementing an asynchronous operation through the queueMicrotask method; Again, try catch is used for error handling, calling the new Promise reject.

Calling the second callback in error state is essentially the same logic. Set two array properties (ledCBS, rejectCbs) to store the two callbacks in the pending state and invoke the array element methods in order to execute resolve or reject when appropriate.

then (onFulfilled, onRejected) {
    // Determine the parameters
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val= > val;
    onRejected = typeof onRejected === 'function' ? onRejected : reason= > { throw reason };
    const thenPromise = new MyPromise((resolve, reject) = > {
        const resolvePromise = cb= > {
            queueMicrotask(() = > { // Asynchronous method, let the PROMISE do the assignment first
                try {
                    let x = cb(this.PromiseResult);
                    if (x === thenPromise) {
                        throw new Error('Then lian error');
                    }
                    if (x instanceof MyPromise) {
                        x.then(resolve, reject);
                    } else{ resolve(x); }}catch (err) {
                    console.error(err); reject(err); }}); };if (this.PromisState === FULFILLED) {
            resolvePromise(onFulfilled);
        } else if (this.PromisState === REJECT) {
            resolvePromise(onRejected);
        } else {
            this.fulfilledCbs.push(resolvePromise.bind(this, onFulfilled));
            this.rejectCbs.push(resolvePromise.bind(this, onFulfilled)); }});return thenPromise;
}

// class MyPromise
fulfilledCbs = [];
rejectCbs = [];

/ / resolve method
while (this.fulfilledCbs.length) {
    this.fulfilledCbs.shift()(this.PromiseResult);
}

/ / reject method
while (this.rejectCbs.length) {
    this.rejectCbs.shift()(this.PromiseResult);
}
Copy the code

All methods

Is a static method that takes an array as an argument and returns onePromiseIn the </br> parameter array, if all promise objects are successful, then return a promise object in the success state if any promise object is failed. And aborts execution of subsequent Promise objects </br>Copy the code

Define an array of Results to collect successful promise results, and then the parameter array handles each item through foreach. First, determine whether the current item is a promise. If it is, then method is used to determine its state. If it is a successful callback, store the result into result; if it is a failed callback, call reject of the new promise directly to set the state. If the current item is not a promise, it is added directly to the Result array. If the result length is the same as the parameter array, call the resolve state of the new Promise.

static all (arr) {
    let result = [];
    const allPromise = new MyPromise((resolve, reject) = > {
        arr.forEach(item= > {
            if (item instanceof MyPromise) {
                item.then(val= >{
                    addData(val);
                }, reject);
            } else addData(item);
        });
        function addData (val) {
            result.push(val);
            if(result.length === arr.length) resolve(result); }});return allPromise;
}
Copy the code

reference

That’s the end of this article, and the rest will be covered in tomorrow’s post. The source code is here