Recently looked at ruan Yifeng ES6 entry Promise part of the content, Promise has been learning and the focus of the interview, here the main record of the original writing of Promise, as well as the use of Promise some notes, The basics of Promise can be found in the Little Red Book and on Mr. Nguyen’s blog.

The constructor

function MyPromise(executor) { this.PromiseState = "pending"; this.PromiseResult = undefined; this.callbackList = []; let resolve = (value) => { if (this.PromiseState ! == "pending") return this.PromiseState = "fulfilled"; this.PromiseResult = value; for (let callback of this.callbackList) { callback.onResolved(value); }}; let reject = (reason) => { if (this.PromiseState ! == "pending") return this.PromiseState = "rejected"; this.PromiseResult = reason; for (let callback of this.callbackList) { callback.onRejected(reason); }}; try { executor(resolve, reject); } catch (err) { reject(err); }}Copy the code

Note:

  1. PromiseOnce the state of an object is changed, it will never change again. So in the callback functionresolveandreject“Should add a line of code to determine the currentPromiseIf the object’s state has changed, then it cannot change its state. As illustrated in the following example,PromiseState bypendingInto afulfilled, and then execute toReject (222).You can’t change the state anymore.
let p = new Promise((resolve, reject) => {
    resolve(111);
    reject(222)
})
// [[PromiseState]]: "fulfilled"
// [[PromiseResult]]: 111
console.log(p);
Copy the code
  1. The constructor passes in oneexecutorFunction, which takes two arguments:resolveandreject, the function is executed when it is passed in.
  2. If theexecutorReject is also fired when an error is thrown in the reject function.
  3. Finally, in executor functions, if the state of a Promise changes depending on an asynchronous operation, such as setTimeout, resolve or Reject will be called only after setTimeout has expired to change the state of the Promise. Therefore, the two callbacks should be saved so that they can be fired at a later time. In this case, you can set up an array to receive these callbacks directly.
let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(111)
    }, 1000)
})

console.log(p);
Copy the code

Then method

MyPromise.prototype.then = function (onResolved, onRejected) { return new MyPromise((resolve, reject) => { let handleCallback = (callback) => { let res = undefined; // Then method callback is a function or a null value. // If the callback is a function, then res is the result of the callback, and no result is returned. The PromiseResult of the returned Promise instance is undefined. If (typeof callback === "function") {res =. If (typeof callback === "function") {res = callback(this.PromiseResult); } else { res = this.PromiseResult; } try { if (res instanceof Promise) { res.then((value) => { resolve(value) }, (err) => { reject(err); })} else {// In the finally function, the callback function finally throws an error or returns a Promise whose state is rejected. In other cases, finally returns a Promise object whose state // depends on the current Promise state. Therefore, in addition to determining what type the current Promise object returns //, This is a big Promise. If (this.PromiseState === "depressing ") {resolve(res); } if (this.PromiseState === "rejected") { reject(res); } } } catch (err) { reject(res); } } if (this.PromiseState === "fulfilled") { console.log("fulfilled") handleCallback(onResolved); } if (this.PromiseState === "rejected") { console.log("rejected") handleCallback(onRejected); } if (this.PromiseState === "pending") { this.callbackList.push({ onResolved: () => { handleCallback(onResolved); }, onRejected: () => { handleCallback(onRejected); }})}})}Copy the code

Test cases:

let p = new MyPromise((resolve, reject) => {
    resolve(122344)
}).then().then(console.log).then((val) => {
    // undefined
    console.log(val)
    return 89
})
// PromiseResult: 89
// PromiseState: "fulfilled"
console.log(p);

let p1 = new MyPromise((resolve, reject) => {
    resolve(122344)
}).then().then().then((val) => {
    // 122344
    console.log(val)
})
// PromiseResult: undefined
// PromiseState: "fulfilled"
console.log(p1);
Copy the code

Note:

  1. Then ()Method takes two callback functions as arguments, only inPromiseBoth functions are triggered when the state changes.
  2. In the implementationPromiseMay return one when synchronizing codePromiseObject to pass throughthenThe way to do it is to take thisPromiseThe state and return value of the instance are determined.

Catch method

/ / catch () method can directly use then () method to implement MyPromise. Prototype. Catch = function (onRejected) {return this. Then (null, onRejected); }Copy the code

Promise.resolve()

MyPromise.resolve = function (val) { return new MyPromise((resolve, Reject) => {// Promise cannot be recursively called if (this === val) reject("Chaining cycle detected for Promise #<Promise>"); if (val instanceof MyPromise) { val.then((value) => { resolve(value) }, (err) => { reject(err) }) } else { resolve(val); }})}Copy the code

Promise.reject()

Reject = function (val) {return new MyPromise((resolve, resolve)); reject) => { reject(val); })}Copy the code

Promise.finally()

// Finally returns the state of the Promise except the rejected state. // The state of the Promise returned is the same as the state of the current Promise. To give priority to the current state of the Promise MyPromise. Prototype. Finally = function (the callback) {return this. Then ((value) = > {the console. The log (value);  // The finally method may return a Promise object // So determine the state and return value of the Promise instance. // The then method will fire reject whenever a problem occurs. // The then method returns an exception. Mypromise.resolve (callback()). Then (null, (err) => {return err}) // Returns the same PromiseResult return value} as the current Promise object, (err) => {console.log(err); MyPromise.reject(callback()).then(null, (err) => { return err }) return err } ) }Copy the code

Promise.all()

MyPromise.all = function (promiseList) { let res = []; return new MyPromise((resolve, reject) => { for (let i = 0; i < promiseList.length; i++) { promiseList[i].then((value) => { res[i] = value; if (res.length === promiseList.length) { resolve(res); } }, (err) => { reject(err); })}})}Copy the code

Promise.race()

MyPromise.race = function (promiseList) { return new MyPromise((resolve, reject) => { for (let i = 0; i < promiseList.length; i++) { promiseList[i].then((value) => { resolve(value) }, (err) => { reject(err); })}})}Copy the code

Promise.allSettled()

MyPromise.allSettled = function (promiseList) { let res = []; return new MyPromise((resolve, reject) => { for (let i = 0; i < promiseList.length; i++) { promiseList[i].then((value) => { res[i] = value; resolve(value) }, (err) => { res[i] = err; reject(err); }) } if (res.length === promiseList.length) { resolve(res); }})}Copy the code

Promise.any()

MyPromise.any = function (promiseList) { let res = []; return new MyPromise((resolve, reject) => { for (let i = 0; i < promiseList.length; i++) { promiseList[i].then((value) => { resolve(value) }, (err) => { res[i] = err; if (res.length === promiseList.length) { reject(res); }})}})}Copy the code

Are you sure you’ve figured out Promise now? Let’s do an example

Promise.resolve().then(() => {
    console.log(0);
    return Promise.resolve(4);
}).then((res) => {
    console.log(res)
})

Promise.resolve().then(() => {
    console.log(1);
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
}).then(() => {
    console.log(5);
}).then(() => {
    console.log(6);
})
Copy the code

Here’s what we need to know before we look at this problem:

  • PromiseOnly callbacks that need to be executed after a state change are microtasks, such asthen,catch,finally. In the use ofPromise.resolve()This is not a microtask, it just defines onePromiseInstance and change its state.

Here’s the answer ~~~

Result: 0123456

This question was in an article I read when I wrote the Promise, and the article explained it.

Let’s start with an example:

let p = new Promise((resolve, reject) => {
    return p
})

// Uncaught (in promise) ReferenceError: Cannot access 'p' before initialization
Copy the code

As you can see from this, you must wait for the Promise initialization to complete before proceeding to the next step, so you need to create an asynchronous task to wait for the initialization of P to complete. When we initialize a Promise instance, we definitely want it to initialize and complete

Here’s how to print this problem:

  • There were two at the beginningresolve.resolveIs a synchronous operation, so they are executed separatelyThen ()Methods;
  • The first oneresolvePrints 0 and returns oneresolveThe state of thePromiseAnd the secondresolvePrint 1;
  • We just said, return onePromise, a microtask is added, at which point the second one is executedresolveThe secondthenMethod, print 2;
  • Now let’s seePromise.resolve(4)Return one in the then methodPromiseObject, which will call this PromisethenThe method can be seen aboveThen ()What does it say in the method,thenMethod returns a callback after executionPromiseIt calls its then method, passing the argument; Next, number twoPromiseWill also execute its next itthenMethod, print 3;
  • And then another oneresolve, at this momentPromise. Resolve (4)The return result has been passed as an argument to the next onethenMethod, print 4;
  • And finally, number twoPromisePrint out 5 and 6, respectively.

The understanding here of returning promise.resolve () in the THEN method can be reduced to a straightforward rule: Whenever a Promise is returned with a state, it delays two THEN executions.

Let’s do two more examples to help you understand Promise

Patients with a

Promise.resolve()
  .then(() => {
    console.log("then1");
    Promise.resolve().then(() => {
      console.log("then1-1");
    });
  })
  .then(() => {
    console.log("then2");
  });
Copy the code

Then1 → THEN1-1 → THEN2

In a chained call, the callback of the next THEN method cannot be added to the microtask queue until the callback of the previous THEN method completes.

Example 2

let p = Promise.resolve();

p.then(() => {
  console.log("then1");
  Promise.resolve().then(() => {
    console.log("then1-1");
  });
}).then(() => {
  console.log("then1-2");
});

p.then(() => {
  console.log("then2");
}); 
Copy the code

Then1 → THEN2 → THEN1-1 → THEN1-2

The beginning of each chain call of the same Promise is, in turn, first entered into the microtask queue.

Rewrite the above example:

let p = Promise.resolve().then(() => {
  console.log("then1");
  Promise.resolve().then(() => {
    console.log("then1-1");
  });
}).then(() => {
  console.log("then2");
});

p.then(() => {
  console.log("then3");
});
Copy the code

Then1 → THEN1-1 → THEN2 → THEN1-3

The p here is no longer the one originally defined, but the one generated by calling the last THEN.

The last

This article is mainly summed up after learning Promise, the examples in the article are mainly borrowed from other authors, and the sources of the article must be posted below

Juejin. Cn/post / 694531…

Juejin. Cn/post / 686957…

The following is my summary of Promise, write on Processon, stick down www.processon.com/outline/603…

The mountain is high and the road is long. The article will be updated from time to time. There is no end to learning