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:
Promise
Once the state of an object is changed, it will never change again. So in the callback functionresolve
andreject
“Should add a line of code to determine the currentPromise
If the object’s state has changed, then it cannot change its state. As illustrated in the following example,Promise
State bypending
Into 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
- The constructor passes in one
executor
Function, which takes two arguments:resolve
andreject
, the function is executed when it is passed in. - If the
executor
Reject is also fired when an error is thrown in the reject function. 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:
Then ()
Method takes two callback functions as arguments, only inPromise
Both functions are triggered when the state changes.- In the implementation
Promise
May return one when synchronizing codePromise
Object to pass throughthen
The way to do it is to take thisPromise
The 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:
Promise
Only 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 onePromise
Instance 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 beginning
resolve
.resolve
Is a synchronous operation, so they are executed separatelyThen ()
Methods; - The first one
resolve
Prints 0 and returns oneresolve
The state of thePromise
And the secondresolve
Print 1; - We just said, return one
Promise
, a microtask is added, at which point the second one is executedresolve
The secondthen
Method, print 2; - Now let’s see
Promise.resolve(4)
Return one in the then methodPromise
Object, which will call this Promisethen
The method can be seen aboveThen ()
What does it say in the method,then
Method returns a callback after executionPromise
It calls its then method, passing the argument; Next, number twoPromise
Will also execute its next itthen
Method, print 3; - And then another one
resolve
, at this momentPromise. Resolve (4)
The return result has been passed as an argument to the next onethen
Method, print 4; - And finally, number two
Promise
Print 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