Reference data
- Front-end development core knowledge advanced – do you think I really want you to write Promise, in fact, are basically written after reading this article, if you want to better understand can see the big guy’s article;
The API to implement
- Constructor method
- Then method
- Catch method
- Resolve static method
- Reject static method
- All Static methods
- Race static method
- All the code
Promise to explain
- Promise Most of these methods will return a Promise object, because we’re going to do a chain call;
- There may be three states when calling then,catch, etc., namely, depressing, Rejected, and pending. The former two states are easy to understand. For pending, you need to use an array to save the callback method and empty the callback list in the array when you call resolve/ Reject.
- Each argument passed to the then/catch method is a callback method that returns data in the Result /error property of the returned Promise object.
Promise constructor
Example use of the Promise constructor
let p = new Promise((resolve,reject)=>{ resolve('result'); / / or reject (" error "); })Copy the code
So the Promise constructor must accept a method, and we can deduce its constructor based on its properties
Class Promise{// Reject ledarray and onRejectArray are used to handle asynchronous logic, assuming, for example, that a.then method is bound before a reject. Private onfunction ledarRay: Function[] = []; private onRejectedArray : Function[] = []; status : PROMISE_STATUS = PROMISE_STATUS.PENDING; result : any = null; error : any = null; constructor(apply: Function){ const onFulfill = (result)=>{ if(this.status === PROMISE_STATUS.PENDING){ this.status = PROMISE_STATUS.FULFIL; this.result = result; / / resolve the onFulfilledArray binding method to execute the enclosing onFulfilledArray. ForEach (fun = > {fun (result); }) } }, onReject = (error)=>{ if(this.status === PROMISE_STATUS.PENDING){ this.status = PROMISE_STATUS.REJECT; this.error = error; / / reject all the inside of the array method to perform the enclosing onRejectedArray. ForEach (fun = > {fun (error); }) } } apply(onFulfill,onReject); }}Copy the code
This part is the most simple, just need to have reverse thinking, basically can understand;
Implementation of then methods
The Primise. Then method receives two parameters, the resolve callback method and the reject callback method, and only one of them will be executed. The THEN method is the core part of the whole Promise, which is also the most difficult part to understand. The then method accepts two callbacks, resolve and reject, in three cases according to promise.status:
- If status === ‘Fulfiled’, call the resolve callback and return the result to generate a new Promise.
- If status === ‘reject’, reject (reject) returns a new Pomise;
- When status === ‘Pending’, we need to wait for the result of the Promise, but we need to return a Promise, so we have to push into onredarray, onRejectedArray;
// The resolvePromise method is explained later; resolvePromise(promise2 : Promise, result : any, resolve : Function, reject : Function){ } then(onFulfilled : Function, onFulfilled: Function) : Promise {// If there is no fulfilled, then add the default onFulfilled/ onFulfilled = onFulfilled? onFulfilled : data => data; onRejected = onRejected ? onRejected : error => error; let promise2 : Promise; If (this.status === promise_status.fulfil){// Return a new Promise object return promise2 = new Promise((resolve,reject)=>{ try{ let result = onFulfilled(this.result); / / here's a encapsulates the method of processing the result / / object can handle the result is a Promise, or other data this. ResolvePromise (promise2, result, resolve, reject); }catch(e){ reject(e); Promise_status. REJECT (this.status === promise_status. REJECT){return promise2 = new Promise((resolve,reject)=>{ try{ let result = onRejected(this.error); this.resolvePromise(promise2,result,resolve,reject); }catch(e){ reject(e); }})} / Promise state when/if the call is Pending, you need to put back into the onFulfilledArray/onRejectedArray array, If (this.status === promise_status.pending){return promise2 = new Promise((resolve,reject)=>{ this.onFulfilledArray.push(result=>{ try{ let _result = onFulfilled(result); this.resolvePromise(promise2, _result, resolve, reject); }catch(e){ reject(e) } }) this.onRejectedArray.push(result=>{ try{ let _result = onRejected(result); this.resolvePromise(promise2, _result, resolve, reject); }catch(e){ reject(e) } }) }) } return this; }Copy the code
ResolvePromise method
The resolvePromise method is the logic we encapsulate to handle the result or error associated with the newly generated Promise and the result returned by the callback. Result may have the following situations:
- Promise comes, in the result of promise. then processing;
- Direct treatment;
resolvePromise(promise2 : Promise, result : any, resolve : Function, reject : Function){
if(promise2 === result){
return reject('error');
}
if(result instanceof Promise){
if(result.status === PROMISE_STATUS.PENDING){
result.then(value=>{
this.resolvePromise(promise2,value,resolve,reject);
}, reject)
}else{
result.then(resolve,reject);
}
return;
}
resolve(result);
}
Copy the code
Promise.catch
catch(onReject: Function) : Promise { if(this.status === PROMISE_STATUS.FULFIL){ return this; } let promise2; return promise2 = new Promise((resolve,reject)=>{ if(this.status === PROMISE_STATUS.REJECT){ let result = onReject(this.error); this.resolvePromise(proimse2,result,resolve,reject); return; } this.then((result)=>{ this.resolvePromise(promise2,result,resolve,reject); },(error)=>{ this.resolvePromise(promise2,onReject(error),resolve,reject); })})}Copy the code
Promise.reject
static reject(error){
return new Promise((resolve,reject)=>{
reject(error);
});
}
Copy the code
Promise.resolve
static resolve(result){
return new Promise((resolve,reject)=>{
resolve(result);
});
}
Copy the code
Promise.all
static all(promises: Promise[]): Promise{ let resultArray = new Array(promises.length); return new Promise((resolve,reject)=>{ let n = 0, maxLength = resultArray.length; let setResult = function(item,idx){ if(idx + 1 > maxLength) reject('cao'); if(! resultArray[idx]){ n ++; resultArray[idx] = item; if(n == maxLength ){ resolve(resultArray); } } } for(let idx =0; idx < promises.length; idx ++ ){ let item = promises[idx]; try{ if(item instanceof Promise){ item.then((result)=>{ setResult(result,idx); }, (error)=>{ reject(error); }) }else{ setResult(promises[idx],idx); } }catch(e){ reject(e); }}})}Copy the code
Promise.race
static race(promises : Promise[]) : Promise{ return new Promise((resolve,reject)=>{ let flag = false; promises.forEach(p => { if(flag){ return; } if(p instanceof Promise){ return p.then(result=>{ if(flag){ return; } flag = true; resolve(result); },error=>{ if(flag){ return; } flag = true; reject(error); }) } flag = true; resolve(p); })})}Copy the code
Full code Promise
enum PROMISE_STATUS { PENDING, FULFIL, REJECT, } class Promise{ private onFulfilledArray : Function[] = []; private onRejectedArray : Function[] = []; status : PROMISE_STATUS = PROMISE_STATUS.PENDING; result : any = null; error : any = null; constructor(apply: Function){ const onFulfill = (result)=>{ if(this.status === PROMISE_STATUS.PENDING){ this.status = PROMISE_STATUS.FULFIL; this.result = result; this.onFulfilledArray.forEach(fun=>{ fun(result); }) } }, onReject = (error)=>{ if(this.status === PROMISE_STATUS.PENDING){ this.status = PROMISE_STATUS.REJECT; this.error = error; this.onRejectedArray.forEach(fun=>{ fun(error); }) } } apply(onFulfill,onReject); } resolvePromise(promise2 : Promise, result : any, resolve : Function, reject : Function){ if(promise2 === result){ return reject('error'); } if(result instanceof Promise){ if(result.status === PROMISE_STATUS.PENDING){ result.then(value=>{ this.resolvePromise(promise2,value,resolve,reject); }, reject) }else{ result.then(resolve,reject); } return; } resolve(result); } then(onFulfilled : Function, onRejected : Function) : Promise { onFulfilled = onFulfilled ? onFulfilled : data => data; onRejected = onRejected ? onRejected : error => error; let promise2 : Promise; if(this.status === PROMISE_STATUS.FULFIL){ return promise2 = new Promise((resolve,reject)=>{ try{ let result = onFulfilled(this.result); this.resolvePromise(promise2,result,resolve,reject); }catch(e){ reject(e); } }) } if(this.status === PROMISE_STATUS.REJECT){ return promise2 = new Promise((resolve,reject)=>{ try{ let result = onRejected(this.error); this.resolvePromise(promise2,result,resolve,reject); }catch(e){ reject(e); } }) } if(this.status === PROMISE_STATUS.PENDING){ return promise2 = new Promise((resolve,reject)=>{ this.onFulfilledArray.push(result=>{ try{ let _result = onFulfilled(result); this.resolvePromise(promise2, _result, resolve, reject); }catch(e){ reject(e) } }) this.onRejectedArray.push(result=>{ try{ let _result = onRejected(result); this.resolvePromise(promise2, _result, resolve, reject); }catch(e){ reject(e) } }) }) } return this; } catch(onReject: Function) : Promise { if(this.status === PROMISE_STATUS.FULFIL){ return this; } let promise2; return promise2 = new Promise((resolve,reject)=>{ if(this.status === PROMISE_STATUS.REJECT){ let result = onReject(this.error); this.resolvePromise(proimse2,result,resolve,reject); return; } this.then((result)=>{ this.resolvePromise(promise2,result,resolve,reject); },(error)=>{ this.resolvePromise(promise2,onReject(error),resolve,reject); }) }) } static reject(error){ return new Promise((resolve,reject)=>{ reject(error); }); } static resolve(result){ return new Promise((resolve,reject)=>{ resolve(result); }); } static all(promises: Promise[]): Promise{ let resultArray = new Array(promises.length); return new Promise((resolve,reject)=>{ let n = 0, maxLength = resultArray.length; let setResult = function(item,idx){ if(idx + 1 > maxLength) reject('cao'); if(! resultArray[idx]){ n ++; resultArray[idx] = item; if(n == maxLength ){ resolve(resultArray); } } } for(let idx =0; idx < promises.length; idx ++ ){ let item = promises[idx]; try{ if(item instanceof Promise){ item.then((result)=>{ setResult(result,idx); }, (error)=>{ reject(error); }) }else{ setResult(promises[idx],idx); } }catch(e){ reject(e); } } }) } static race(promises : Promise[]) : Promise{ return new Promise((resolve,reject)=>{ let flag = false; promises.forEach(p => { if(flag){ return; } if(p instanceof Promise){ return p.then(result=>{ if(flag){ return; } flag = true; resolve(result); },error=>{ if(flag){ return; } flag = true; reject(error); }) } flag = true; resolve(p); }}})})Copy the code