1.Promise resolves callback hell: (1) Callback function deferred binding: callback functions are not declared directly, but passed in via the later THEN method, that is, deferred. (2) Return value penetration: Asynchronous methods do not immediately return the final value, but return a promise, which can be followed by chain calls. (3) Error bubbling: The error generated before will be passed backward until it is received by catch.
A simple version of the implementation
// Three states
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function myPromise(executor){
let self = this; // Cache the current Promise instance
self.status = PENDING; // Current status
self.value = undefined; // The value returned successfully
self.reason = undefined; // Cause of failure
self.onFulfilled = undefined; // Successful callback
self.onRejected = undefined; // Failed callback
let resolve = (value) = >{
if (self.status === PENDING){
setTimeout(() = >{
self.status = FULFILLED;
self.value = value;
self.onFulfilled(self.value);// Execute a successful callback in resolve.
},0)}}let reject = (reason) = >{
if (self.status === PENDING){
setTimeout(() = >{
self.status = REJECTED;
self.reason = reason;
self.onRejected(self.reason);
},0)}}// If exector executes an error, reject is executed
try{
executor(resolve,reject);
}catch(err){
reject(err);
}
}
myPromise.prototype.then = function(onFulfilled,onRejected){
if (this.status === PENDING){
this.onFulfilled = onFulfilled;
this.onRejected = onRejected;
}
if (this.status === FULFILLED){
// If the state is fulfilled, the successful callback will be implemented directly and the successful value will be passed in
onFulfilled(this.value);
}
if (this.status === REJECTED){
// In the rejected state, the failed callback is executed directly and the failure cause is passed in
onRejected(this.reason); }}Copy the code
Set to callback array
Set the callback to an array:
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
Copy the code
The then function adds the callback function to the array when the state is PENDING
if (this.status === PENDING) {
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
Copy the code
Partially modify the execution of the callback function in resolve and Reject:
/ / resolve
self.onFulfilledCallbacks.forEach((callback) = > callback(self.value));
/ / reject
self.onRejectedCallbacks.forEach((callback) = > callback(self.error));
Copy the code
The full code is as follows:
// Three states
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function myPromise(executor){
let self = this; // Cache the current Promise instance
self.status = PENDING; // Current status
self.value = undefined; // The value returned successfully
self.reason = undefined; // Cause of failure
self.onFulfilledCallbacks = []; // Successful callback
self.onRejectedCallbacks = []; // Failed callback
let resolve = (value) = >{
if (self.status === PENDING){
setTimeout(() = >{
self.status = FULFILLED;
self.value = value;
self.onFulfilledCallbacks.forEach((callback) = >{callback(this.value)});// Execute successful callbacks in order to resolve.
},0)}}let reject = (reason) = >{
if (self.status === PENDING){
setTimeout(() = >{
self.status = REJECTED;
self.reason = reason;
self.onRejectedCallbacks((callback) = >{callback(self.reason)});
},0)}}// If exector executes an error, reject is executed
try{
executor(resolve,reject);
}catch(err){
reject(err);
}
}
myPromise.prototype.then = function(onFulfilled,onRejected){
if (this.status === PENDING){
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
if (this.status === FULFILLED){
// If the state is fulfilled, the successful callback will be implemented directly and the successful value will be passed in
onFulfilled(this.value);
}
if (this.status === REJECTED){
// In the rejected state, the failed callback is executed directly and the failure cause is passed in
onRejected(this.reason);
}
return this;
}
Copy the code
Solve the chain call
1. By default, we return a promise in the first THEN. • If a promise is returned, it is passed to the next THEN. • If a normal value is returned, the normal value is passed to the next THEN. 2. If we return a parameter in the first then. This new promise that comes out of return is onFulfilled() or onRejected()
The secret states the value of onFulfilled() or onRejected(), which is the value returned by the first THEN. This is called X, and the function to judge X is called resolvePromise
// Three states
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function myPromise(executor) {
let self = this; // Cache the current myPromise instance
self.status = PENDING; // Current status
self.value = undefined; // The value returned successfully
self.reason = undefined; // Cause of failure
self.onFulfilledCallbacks = []; // Successful callback
self.onRejectedCallbacks = []; // Failed callback
let resolve = (value) = > {
if (self.status === PENDING) {
setTimeout(() = > {
self.status = FULFILLED;
self.value = value;
self.onFulfilledCallbacks.forEach((callback) = > { callback(this.value) });// Execute successful callbacks in order to resolve.
}, 0)}}let reject = (reason) = > {
if (self.status === PENDING) {
setTimeout(() = > {
self.status = REJECTED;
self.reason = reason;
self.onRejectedCallbacks.forEach((callback) = > { callback(self.reason) });
}, 0)}}// If exector executes an error, reject is executed
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
// ondepressing, onRejected are both optional parameters. If they are not functions, they must be ignored
// this is a big pity. This is a big pity. This is a big pity
This is a big pity. // • onRejected returns a common value. If value => value, then this will run into the next onpity
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
onRejected = typeof onRejected === 'function' ? onRejected : reason= > { throw reason };
let bridgemyPromise;
let self = this;
if (self.status === PENDING) {
return bridgemyPromise = new myPromise((resolve, reject) = > {
self.onFulfilledCallbacks.push((value) = > {
setTimeout(() = > {
try {
let x = onFulfilled(value);
resolvemyPromise(bridgemyPromise, x, resolve, reject);
} catch(reason) { reject(reason); }},0)}); self.onRejectedCallbacks.push((reason) = > {
setTimeout(() = > {
try {
let x = onRejected(reason);
resolvemyPromise(bridgemyPromise, x, resolve, reject);
} catch(e) { reject(e); }},0)})})}if (this.status === FULFILLED) {
// If the state is fulfilled, the successful callback will be implemented directly and the successful value will be passed in
return bridgemyPromise = new myPromise((resolve, reject) = > {
setTimeout(() = > {
try {
let x = onFulfilled(self.value);
resolvemyPromise(bridgemyPromise, x, resolve, reject);
}
catch(reason) { reject(reason); }},0)})}if (this.status === REJECTED) {
// In the rejected state, the failed callback is executed directly and the failure cause is passed in
return bridgemyPromise = new myPromise((resolve, reject) = > {
setTimeout(() = > {
try {
let x = onRejected(self.reason);
resolvemyPromise(bridgemyPromise, x, resolve, reject);
}
catch(reason) { reject(reason); }})})}return bridgemyPromise;
}
Copy the code
One of the important functions implemented is:
// Compatible with multiple myPromise implementations
function resolvemyPromise(bridgemyPromise, x, resolve, reject) {
// Prevent circular reference problems
if (bridgemyPromise === x) {
return reject(new TypeError('Error'));
}
// called variable, used to determine whether the function has been called
let called;
// Determine whether x is an object or a function, and if neither is, pass x to resolve
if(x ! = =null && (typeof x === 'object' || typeof x === 'function')) {
try {
If x is an object or a function, assign x. Chen to then, and then determine the type. If x is not a function, pass x to resolve
let then = x.then;
// If then is a function, it defaults to myPromise
if (typeof then === 'function') {
// Execute then with this as the first argument, followed by a successful callback and a failed callback
then.call(x, y= > {
if (called) return;
called = true;
resolvemyPromise(bridgemyPromise, x, resolve, reject);
}, reason= > {
if (called) return;
called = true; reject(reason); })}else{ resolve(x); }}catch (reason) {
if (called) return;
called = true; reject(reason); }}else{ resolve(x); }}Copy the code
4. Address error capture and bubbling mechanisms
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
Copy the code
5. Catch and resolve, Reject, race, and All
(1) developer.mozilla.org/zh-CN/docs/… (2) www.cnblogs.com/sugar-tomat… (3) juejin. Cn/post / 684490…