“This is the 31st day of my participation in the First Challenge 2022. For details: First Challenge 2022”

preface

I’ve always heard that you need to understand some source code to become an advanced front-end programmer, so start with Promise, which the authors tried to get you to understand in as little language as possible

To prepare

Promises/A+原文 : Promises/A+ translation

Install the Promise testing tool

npm i promises-aplus-tests -g
Copy the code

Run the test tool to verify that the Promise complies with the specification

Promises - Aplus -tests [promise name]Copy the code

Complete code is preceded by use cases

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeofexecutor ! = ='function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) = > {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        this.onFulfilledCallbacks.forEach((fn) = >fn()); }};const reject = (reason) = > {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) = >fn()); }};try {
      executor(resolve, reject);
    } catch (e) {
      this.reject(e); }}then(onFulfilled, onRejected) {
    if (typeofonFulfilled ! = ='function') {
      onFulfilled = (value) = > value;
    }
    if (typeofonRejected ! = ='function') {
      onRejected = (err) = > {
        throw err;
      };
    }
    let promise2 = new Promise((resolve, reject) = > {
      if (this.state === FULFILLED) {
        setTimeout(() = > {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch(e) { reject(e); }},0);
      }
      if (this.state === REJECTED) {
        setTimeout(() = > {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch(e) { reject(e); }},0);
      }
      if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(() = > {
          setTimeout(() = > {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch(e) { reject(e); }}); });this.onRejectedCallbacks.push(() = > {
          setTimeout(() = > {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch(e) { reject(e); }}); }); }});returnpromise2; }}const resolvePromise = (promise2, x, resolve, reject) = > {
  if (promise2 === x)
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>'));if ((typeof x === 'object'&& x ! = =null) | |typeof x === 'function') {
    let called;
    try {
      const then = x.then;
      if (typeofthen ! = ='function') resolve(x);
      else {
        then.call(
          x,
          (value) = > {
            if (called) return;
            called = true;

            resolvePromise(promise2, value, resolve, reject);
          },
          (reason) = > {
            if (called) return;
            called = true; reject(reason); }); }}catch (err) {
      if (called) return;
      called = true; reject(err); }}else{ resolve(x); }};Promise.defer = Promise.deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) = > {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};
module.exports = Promise;


Copy the code

The complete code is 127 lines, adding the Promise test code for a total of 136 lines.

How to test

In VS Code file new promise. Jspromise. Jspromise. Js file

/ / promise code
class Promise {
  constructor() {}
  then() {}
  catch() {}}// Test the code
Promise.defer = Promise.deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) = > {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};
module.exports = Promise;
Copy the code

In promise. Jspromise. Jspromise. Js file directory open a terminal, enter the following command to test promise is in accordance with the specification

promises-aplus-tests promise.js
Copy the code

For the rest of this tutorial, I'll stop explaining the test code and just talk about the Promise code

Keep up with the ideas, the core of this article begins

The statement Promise class

Common Promise methods include then and catch, which declare a Promise class using ES6 syntax

That’s easy to understand, right?

class Promise {
  constructor() {}
  then() {}
  catch() {}}Copy the code

constructor

A normal use of a Promise would look like this: New Promise(parameter is a function)

let p1 = new Promise((resolve) = > {
  setTimeout(() = > {
    resolve(1);
  }, 1000);
});
Copy the code

So is it understandable that the Constructor of the Promise class uses the executor parameter to receive this parameter?

class Promise {
  constructor(executor) {}
  then() {}
  catch() {}}Copy the code

Continue to:

Executor is a parameter entered by the user. We can’t trust the user to use a function as a new Promise, right?

So you need to determine whether executor is a function.

Makes sense, right?

class Promise {
  constructor(executor) {
    if (typeofexecutor ! = ='function') {
      return new TypeError(`Promise resolver ${executor} is not a function`); }}then() {}
  catch() {}}Copy the code

executor

The constructor section already knows that executor is a function. Executor functions take arguments.

The following Promise uses the code

let p1 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    Math.random() > 0.5 ? resolve('right') : reject('wrong');
  }, 1000);
});
p1.then((value) = > {
  console.log(value);
});
Copy the code

Promises/A+ : Resolve is A set of actions that will succeed, reject is A set of actions that will fail, and cause success. We have to have all of these promises, all of them

Resolve and reject

class Promise {
  constructor(executor) {
    if (typeofexecutor ! = ='function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }

    // The value passed to the resolution callback when a promise is resolved
    this.value = null;

    // The value passed to the resolution callback when a promise is rejected
    this.reason = null;

    // Successful sequence of operations
    const resolve = () = > {};

    // Some operations failed
    const reject = () = > {};
    executor(resolve, reject);
  }
  then() {}
  catch() {}}Copy the code

state

Promises/A + translation

Promises/A+ : Promises have three states. Let’s add these three states to our code, and that makes sense

Constants are named in uppercase, which is understandable

PENDING, depressing and REJECTED

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeofexecutor ! = ='function') {
      return new TypeError(`Promise resolver ${executor} is not a function`); }}then() {}
  catch() {}}Copy the code

The Pending state can only be Fulfilled or Rejected and cannot be changed. This requires a variable to record the Promise state value, and the initial value of the state value is Pending

this.state

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeofexecutor ! = ='function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    const resolve = () = > {};
    const reject = () = > {};
    executor(resolve, reject);
  }
  then() {}
  catch() {}}Copy the code

Pending can only be Fulfilled Fulfilled or Rejected means resolve and reject can only be executed Pending.

So you need to add judgments to the resolve and reject functions

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeofexecutor ! = ='function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    const resolve = () = > {
      // The execution can be performed only when the execution is completed. The modification state is depressing
      if (this.state === PENDING) {
        this.state = FULFILLED; }};const reject = () = > {
      // The value can be executed only when the value is PENDING. The value can be modified to REJECTED after the execution
      if (this.state === PENDING) {
        this.state = REJECTED; }}; executor(resolve, reject); }then() {}
  catch() {}}Copy the code

Does the success/exception function need to have success/exception data? Does the value of the callback need to be stored in the class and returned in the then method?

add

The value and reason

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeofexecutor ! = ='function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    const resolve = (value) = > {
      if (this.state === PENDING) {
        this.state = FULFILLED;

        // The value passed to the resolution callback at resolution time
        this.value = value; }};const reject = (reason) = > {
      if (this.state === PENDING) {
        this.state = REJECTED;

        // The value passed to the resolution callback when rejected
        this.reason = reason; }}; executor(resolve, reject); }then() {}
  catch() {}}Copy the code

Has this been completed? No, one more step.

Executor is a function, as described above, but it is possible for the function to execute an error. Try/catch solution

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeofexecutor ! = ='function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    const resolve = (value) = > {
      if (this.state === PENDING) {
        this.state = FULFILLED;

        // The value passed to the resolution callback at resolution time
        this.value = value; }};const reject = (reason) = > {
      if (this.state === PENDING) {
        this.state = REJECTED;

        // The value passed to the resolution callback when rejected
        this.reason = reason; }};try {
      // If the function runs smoothly, execute the function
      executor(resolve, reject);
    } catch (error) {
      // The function throws an exception, which is returned by rejectreject(error); }}then() {}
  catch() {}}Copy the code

Then

Write the then function alone and ignore the constructor code for now. Too much code can be confusing. What do readers think?

then() {}
Copy the code

Promises/A + translation

According to the specification, then should have two parameters, and these two parameters should be functions, if not functions, then should be ignored

So the then code looks like this; It’s not hard to understand

then(onFulfilled, onRejected){
    if (typeofonFulfilled ! = ='function') {
      onFulfilled = (value) = > value;
    }
    if (typeofonRejected ! = ='function') {
      onRejected = (err) = > {
        throwerr; }; }}Copy the code

OnFulfilled and onRejected

Then look at the specification description

OnFulfilled and onRejected cannot be called more than once.

then(onFulfilled, onRejected) {
    if (typeofonFulfilled ! = ='function') {
      onFulfilled = (value) = > value;
    }
    if (typeofonRejected ! = ='function') {
      onRejected = (err) = > {
        throw err;
      };
    }

    // Execute only once
    if (this.state === Promise.FULFILLED) {
      onFulfilled(this.value);
    }

    if (this.state === Promise.REJECTED) {
      onRejected(this.reason); }}Copy the code

Resolve Supports asynchrony

Is that all? No, no, no.

If resolve is implemented in an asynchronous function in the Promise, console is not currently implemented in the Promise code I’m writing.

let p2 = new Promise((resolve) = > {
  setTimeout(() = > {
    resolve(2);
  }, 1000);
});
p2.then((value) = > {
  console.log(value);
});
Copy the code

The reason is that when the. Then function is executed, the Promise state is Pending. Currently, I only write the state as FULFILLED and REJECTED in the Promise

The.then function also handles PENDING state bits. The incoming arguments to the.THEN function are placed in an array before the asynchronous execution of resolve

Any other questions?

some

Then the asynchronous

console.log(1);
let p2 = new Promise((resolve) = > {
  resolve(4);
  console.log(2);
});
p2.then((value) = > {
  console.log(value);
});
console.log(3);
// 1,2,3,4
Copy the code

Normally returns 1, 2, 3, 4. Now I’m writing a promise that returns 1, 2, 4, 3

What’s the reason? The solution is to add setTimeout to the.then function to simulate asynchrony

  then(onFulfilled, onRejected) {
    if (typeofonFulfilled ! = ='function') {
      onFulfilled = (value) = > value;
    }
    if (typeofonRejected ! = ='function') {
      onRejected = (err) = > {
        throw err;
      };
    }

    if (this.state === FULFILLED) {
      setTimeout(() = > {
        onFulfilled(this.value);
      });
    }

    if (this.state === REJECTED) {
      setTimeout(() = > {
        onRejected(this.reason);
      });
    }
    if (this.state === PENDING) {
      this.onFulfilledCallbacks.push(() = > {
        setTimeout(() = > {
          onFulfilled(this.value);
        });
      });
      this.onRejectedCallbacks.push(() = > {
        setTimeout(() = > {
          onRejected(this.reason);
        });
      });
    }
    let promise2 = new Promise(() = > {});
    returnpromise2; }}Copy the code

The array of promises needs to be declared in constructor and executed in resolve, so the code Promise up to this point looks like this:

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeofexecutor ! = ='function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) = > {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        this.onFulfilledCallbacks.forEach((fn) = >fn()); }};const reject = (reason) = > {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) = >fn()); }};try {
      executor(resolve, reject);
    } catch (e) {
      this.reject(e); }}then(onFulfilled, onRejected) {
    if (typeofonFulfilled ! = ='function') {
      onFulfilled = (value) = > value;
    }
    if (typeofonRejected ! = ='function') {
      onRejected = (err) = > {
        throw err;
      };
    }

    if (this.state === FULFILLED) {
      setTimeout(() = > {
        onFulfilled(this.value);
      });
    }

    if (this.state === REJECTED) {
      setTimeout(() = > {
        onRejected(this.reason);
      });
    }
    if (this.state === PENDING) {
      this.onFulfilledCallbacks.push(() = > {
        setTimeout(() = > {
          onFulfilled(this.value);
        });
      });
      this.onRejectedCallbacks.push(() = > {
        setTimeout(() = > {
          onRejected(this.reason); }); }); }}}Copy the code

So I’m going to write this, and I’m going to test it and it says 806 exceptions; That’s 66 test cases passed. Continue to work hard

How does then return a new Promise

Then look at the specification description:

The then method must return a Promise object

  then(onFulfilled, onRejected) {
    if (typeofonFulfilled ! = ='function') {
      onFulfilled = (value) = > value;
    }
    if (typeofonRejected ! = ='function') {
      onRejected = (err) = > {
        throw err;
      };
    }


    if (this.state === FULFILLED) {
      setTimeout(() = > {
        onFulfilled(this.value);
      });
    }

    if (this.state === REJECTED) {
      setTimeout(() = > {
        onRejected(this.reason);
      });
    }
    if (this.state === PENDING) {
      this.onFulfilledCallbacks.push(() = > {
        setTimeout(() = > {
          onFulfilled(this.value);
        });
      });
      this.onRejectedCallbacks.push(() = > {
        setTimeout(() = > {
          onRejected(this.reason);
        });
      });
    }
    // Return a new Promise object
    let promise2 = new Promise(() = > {});
    return promise2;
  }
Copy the code

Understandable? Each time.then returns a new promise object, the.then method can be called forever

Why can’t we just return this? JQuery just returns this for chain calls.

Because a promise has three states and the states are irreversible, a new Promise object must be returned

Then returns the Promise resolution process

Then look at the specification description:

  • ifonFulfilledoronRejectedReturn a valuex, run the followingPromise resolution process:[[Resolve]](promise2, x)
  • ifonFulfilledoronRejectedThrow an exceptione,promise2Execution must be rejected and a rejection must be returnede
  • ifonFulfilledIs not a function andpromise1Successful execution,promise2Must execute successfully and return the same value
  • ifonRejectedIs not a function andpromise1Refuse to enforce,promise2Execution must be rejected and the same data returned

The first sentence

Make sure that onFulfilled or onRejected returns a value x to perform Promise2

Modify the then code as follows:


  then(onFulfilled, onRejected) {
    if (typeofonFulfilled ! = ='function') {
      onFulfilled = (value) = > value;
    }
    if (typeofonRejected ! = ='function') {
      onRejected = (err) = > {
        throw err;
      };
    }

    let promise2 = new Promise((resolve, reject) = > {
      if (this.state === FULFILLED) {
        setTimeout(() = > {
         const x = onFulfilled(this.value);
        });
      }

      if (this.state === REJECTED) {
        setTimeout(() = > {
          const x = onRejected(this.reason);
        });
      }
      if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(() = > {
          setTimeout(() = > {
           const x =  onFulfilled(this.value);
          });
        });
        this.onRejectedCallbacks.push(() = > {
          setTimeout(() = > {
           const x =  onRejected(this.reason); }); }); }});returnpromise2; }}Copy the code

The second sentence

If ondepressing or onRejected throws an exception E, promise2 must reject the implementation and return the rejection cause E

Catch the exception that ondepressing or onRejected throws with try/catch

then(onFulfilled, onRejected) {
    if (typeofonFulfilled ! = ='function') {
      onFulfilled = (value) = > value;
    }
    if (typeofonRejected ! = ='function') {
      onRejected = (err) = > {
        throw err;
      };
    }

    let promise2 = new Promise((resolve, reject) = > {
      if (this.state === FULFILLED) {
        setTimeout(() = > {
          try {
            const x = onFulfilled(this.value);
          } catch(error) { reject(error); }}); }if (this.state === REJECTED) {
        setTimeout(() = > {
          try {
            const x = onRejected(this.reason);
          } catch(error) { reject(error); }}); }if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(() = > {
          setTimeout(() = > {
            try {
              const x = onFulfilled(this.value);
            } catch(error) { reject(error); }}); });this.onRejectedCallbacks.push(() = > {
          setTimeout(() = > {
            try {
              const x = onRejected(this.reason);
            } catch(error) { reject(error); }}); }); }});return promise2;
  }
Copy the code

The third sentence

If ondepressing is not a function and promise1 executes successfully, promise2 must execute successfully and return the same value

Resolve (x) : resolve(x)

then(onFulfilled, onRejected) {
  if (typeofonFulfilled ! = ='function') {
    onFulfilled = (value) = > value;
  }
  if (typeofonRejected ! = ='function') {
    onRejected = (err) = > {
      throw err;
    };
  }

  let promise2 = new Promise((resolve, reject) = > {
    if (this.state === FULFILLED) {
      setTimeout(() = > {
        try {
          const x = onFulfilled(this.value);
          resolve(x);
        } catch(error) { reject(error); }}); }if (this.state === REJECTED) {
      setTimeout(() = > {
        try {
          const x = onRejected(this.reason);
          // 这里直接 resolve 并并且返回 x
          resolve(x);
        } catch(error) { reject(error); }}); }if (this.state === PENDING) {
      this.onFulfilledCallbacks.push(() = > {
        setTimeout(() = > {
          try {
            const x = onFulfilled(this.value);
            resolve(x);
          } catch(error) { reject(error); }}); });this.onRejectedCallbacks.push(() = > {
        setTimeout(() = > {
          try {
            const x = onRejected(this.reason);
            resolve(x);
          } catch(error) { reject(error); }}); }); }});return promise2;
}
Copy the code

If x is a primitive datatype, let’s think about it, what if x is a reference datatype, a function, or even a Promise?

So we need to determine the data type of x

Now that it’s self-contained, let’s just add a method that executes these x values

The method name is: resolvePromise

 then(onFulfilled, onRejected) {
    if (typeofonFulfilled ! = ='function') {
      onFulfilled = (value) = > value;
    }
    if (typeofonRejected ! = ='function') {
      onRejected = (err) = > {
        throw err;
      };
    }

    let promise2 = new Promise((resolve, reject) = > {
      if (this.state === FULFILLED) {
        setTimeout(() = > {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch(error) { reject(error); }}); }if (this.state === REJECTED) {
        setTimeout(() = > {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch(error) { reject(error); }}); }if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(() = > {
          setTimeout(() = > {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch(error) { reject(error); }}); });this.onRejectedCallbacks.push(() = > {
          setTimeout(() = > {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch(error) { reject(error); }}); }); }});return promise2;
  }

  function resolvePromise(promise2, x, resolve, reject){}Copy the code

resolvePromise

Let’s start writing the resolvePromise function

X is not promise itself

Promise can’t be called in a loop,

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')); }}Copy the code

Determine if x is a reference data type

If it is not a reference data type, simply execute resolve(x)

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')); }if ((typeof x === 'object'&& x ! = =null) | |typeof x === 'function') {}else{ resolve(x); }}Copy the code

If it is a reference data type, determine if there is then in the data. If there is then that is not a function, execute resolve(x).

Here’s an explanation: if then is a function, x may be a Promise object, requiring special treatment, or if it is not a function, it may be treated as a general object

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')); }if ((typeof x === 'object'&& x ! = =null) | |typeof x === 'function') {
    const then = x.then;
    if (typeofthen ! = ='function') {
      resolve(x);
    } else{}}else{ resolve(x); }}Copy the code

Of course, exceptions can occur in any code, so try/catch is needed to catch some possible exceptions

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')); }if ((typeof x === 'object'&& x ! = =null) | |typeof x === 'function') {
    try {
      const then = x.then;
      if (typeofthen ! = ='function') {
        resolve(x);
      } else{}}catch(err) { reject(err); }}else{ resolve(x); }}Copy the code

If then is a function

Then is a function that executes then. Because the then is fetched from x, we call the call method to redirect the this of the then function to x

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')); }if ((typeof x === 'object'&& x ! = =null) | |typeof x === 'function') {
    try {
      const then = x.then;
      if (typeofthen ! = ='function') {
        resolve(x);
      } else {
        then.call(
          x,
          (value) = > {
            resolvePromise(promise2, value, resolve, reject);
          },
          (reason) = >{ reject(reason); }); }}catch(err) { reject(err); }}else{ resolve(x); }}Copy the code

The above code does most of what promises do, but there is one more thing that the specification says: If both resolvePromise and rejectPromise are called, or if they are called more than once by the same parameter, the first call is preferred and the remaining calls are ignored

Calledcalledcalled, called true returns,

const resolvePromise = (promise2, x, resolve, reject) = > {
  if (promise2 === x)
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>'));if ((typeof x === 'object'&& x ! = =null) | |typeof x === 'function') {
    let called;
    try {
      const then = x.then;
      if (typeofthen ! = ='function') resolve(x);
      else {
        then.call(
          x,
          (value) = > {
            if (called) return;
            called = true;

            resolvePromise(promise2, value, resolve, reject);
          },
          (reason) = > {
            if (called) return;
            called = true; reject(reason); }); }}catch (err) {
      if (called) return;
      called = true; reject(err); }}else{ resolve(x); }};Copy the code

conclusion

Although I want to describe or explain this Promise in as few words as possible. But it still ended up using nearly 4,000 words to describe what it was. The author’s current level is limited, so he has to make the Promise as clear as possible. If you have any comments and suggestions, please leave a comment in the comment section.