usage
new Promise((resolve, reject) = > {
// Asynchrony succeeds in executing resolve, otherwise executing reject
}).then((res) = > {
// Resolve triggers the first callback to execute
}, (err) => {
// Reject triggers the second callback to be executed
}).then(res= > {
// Ensure that the then method still returns a promise
// This is the way to make chained calls
}).catch(reason= >{});// Wait for all promises to execute successfully
// If there is a failure, catch will be executed
Promise.all([promise1, ...] ).then();Copy the code
First, try the knife
Initial realization Promise:
1. Achieve three states: ‘pending ‘, ‘fulfilled’, ‘rejected’
2. Can realize the then method of two callback function processing
//promise.js
class Promise{
// Pass an asynchronous function in
constructor(excutorCallBack){
this.status = 'pending';
this.value = undefined;
this.fulfillAry = [];
this.rejectedAry = [];
/ / = > Excutor execution
let resolveFn = result= > {
if(this.status ! = ='pending') return;
let timer = setTimeout((a)= > {
this.status = 'fulfilled';
this.value = result;
this.fulfillAry.forEach(item= > item(this.value));
}, 0);
};
let rejectFn = reason= > {
if(this.status ! = ='pending')return;
let timer = setTimeout((a)= > {
this.status = 'rejected';
this.value = reason;
this.rejectedAry.forEach(item= > item(this.value))
})
};
try{
// Execute this asynchronous function
excutorCallBack(resolveFn, rejectFn);
} catch(err) {
//=> Exception information is processed according to the rejected state
rejectFn(err);
}
}
then(fulfilledCallBack, rejectedCallBack) {
// The resolve and reject functions are actually microtasks
// So they are not executed immediately, but after the then call completes
this.fulfillAry.push(fulfilledCallBack);
this.rejectedAry.push(rejectedCallBack);
// After a push, they are executed}}module.exports = Promise;
Copy the code
The test is as follows:
let Promise = require('./promise');
let p1 = new Promise((resolve, reject) = > {
setTimeout((a)= > {
Math.random()<0.5? resolve(100):reject(- 100.);
}, 1000)
}).then(res= > {
console.log(res);
}, err => {
console.log(err);
})
Copy the code
Two, complete the chain effect
The biggest hurdle is the implementation of chained calls, specifically the then method.
//then pass in two functions
then(fulfilledCallBack, rejectedCallBack) {
// Make sure both are functions
typeoffulfilledCallBack ! = ='function' ? fulfilledCallBack = result= > result:null;
typeofrejectedCallBack ! = ='function' ? rejectedCallBack = reason= > {
throw new Error(reason instanceof Error? reason.message:reason);
} : null
// Return a new Promise object called "New Promise"
return new Promise((resolve, reject) = > {
// Note that this refers to the current Promise object, not the new Promise
// It is important to repeat:
// The resolve and reject functions of the current Promise(not the new Promise return here) are actually a microtask
// So they are not executed immediately, but after the then call completes
this.fulfillAry.push((a)= > {
try {
// Execute the methods in the then
// The purpose of execution has been achieved
let x = fulfilledCallBack(this.value);
// The next step after execution is to record the execution status and determine how the new Promise will behave
// If the return value x is a Promise object, then the operation is performed
// If it is not a Promise, call the new Promise's resolve function directly,
// The new promises are now empty after the new promises' THEN operations. The resolve implementation of the new Promise
x instanceof Promise ? x.then(resolve, reject):resolve(x);
}catch(err){
reject(err)
}
});
// The same is true
this.rejectedAry.push((a)= > {
try {
let x = this.rejectedCallBack(this.value);
x instanceof Promise ? x.then(resolve, reject):resolve(x);
}catch(err){
reject(err)
}
})
}) ;
}
Copy the code
Test cases:
let p1 = new Promise((resolve, reject) = > {
setTimeout((a)= > {
Math.random()<0.5? resolve(100):reject(- 100.);
}, 1000)})let p2 = p1.then(result= > {
// Then returns a new Promise
return result + 100;
})
let p3 = p2.then(result= > {
console.log(result);
}, reason => {
console.log(reason)
})
Copy the code
A simple diagram to simulate the internal flow of chained calls:
catch(rejectedCallBack) {
return this.then(null, rejectedCallBack);
}
Copy the code
Third, the Promise. All ()
Next, implement promise.all ()
// For static methods of the class, not on the prototype
static all(promiseAry = []) {
let index = 0,
result = [];
return new Promise((resolve, reject) = > {
for(let i = 0; i < promiseAry.length; i++){
promiseAry[i].then(val= > {
index++;
result[i] = val;
if( index === promiseAry.length){ resolve(result) } }, reject); }})}Copy the code
Four, Promise. Race ()
Next comes the RACE method
static race(promises) {
return new Promise((resolve, reject) = > {
if (promises.length === 0) {
return;
} else {
for(let i = 0; i < promises.length; i++){
promises[i].then(val= > {
resolve(result);
return; } }, reject); }}}); }Copy the code
Five, the Promise. The resolve ()
static resolve (value) {
if (value instanceof Promise) return value
return new Promise(resolve= > resolve(value))
}
Copy the code
Six, Promise. Reject ()
static reject (value) {
return new Promise((resolve, reject) = > reject(value))
}
Copy the code
The complete code
Now write a simple but fully functional Promise and you’re done.
class Promise{
constructor(excutorCallBack){
this.status = 'pending';
this.value = undefined;
this.fulfillAry = [];
this.rejectedAry = [];
/ / = > Excutor execution
let resolveFn = result= > {
if(this.status ! = ='pending') return;
let timer = setTimeout((a)= > {
this.status = 'fulfilled';
this.value = result;
this.fulfillAry.forEach(item= > item(this.value));
}, 0);
};
let rejectFn = reason= > {
if(this.status ! = ='pending')return;
let timer = setTimeout((a)= > {
this.status = 'rejected';
this.value = reason;
this.rejectedAry.forEach(item= > item(this.value))
})
};
try{
excutorCallBack(resolveFn, rejectFn);
} catch(err) {
//=> Exception information is processed according to the rejected state
rejectFn(err);
}
}
then(fulfilledCallBack, rejectedCallBack) {
typeoffulfilledCallBack ! = ='function' ? fulfilledCallBack = result= > result:null;
typeofrejectedCallBack ! = ='function' ? rejectedCallBack = reason= > {
throw new Error(reason instanceof Error? reason.message:reason);
} : null
return new Promise((resolve, reject) = > {
this.fulfillAry.push((a)= > {
try {
let x = fulfilledCallBack(this.value);
x instanceof Promise ? x.then(resolve, reject ):resolve(x);
}catch(err){
reject(err)
}
});
this.rejectedAry.push((a)= > {
try {
let x = this.rejectedCallBack(this.value);
x instanceof Promise ? x.then(resolve, reject):resolve(x);
}catch(err){
reject(err)
}
})
}) ;
}
catch(rejectedCallBack) {
return this.then(null, rejectedCallBack);
}
static all(promiseAry = []) {
let index = 0,
result = [];
return new Promise((resolve, reject) = > {
for(let i = 0; i < promiseAry.length; i++){
promiseAry[i].then(val= > {
index++;
result[i] = val;
if( index === promiseAry.length){ resolve(result) } }, reject); }})}static race(promiseAry) {
return new Promise((resolve, reject) = > {
if (promiseAry.length === 0) {
return;
}
for (let i = 0; i < promiseAry.length; i++) {
promiseAry[i].then(val= > {
resolve(val);
return; }, reject); }})}static resolve (value) {
if (value instanceof Promise) return value
return new Promise(resolve= > resolve(value))
}
static reject (value) {
return new Promise((resolve, reject) = > reject(value))
}
}
module.exports = Promise;
Copy the code