沐鳴註冊平台官網_手寫Promise
Promise的用法 :
let p = new Promise(function(resolve, reject){
console.log(111)
setTimeout(function(){
resolve(2)
}, 1000)
})
p.then(function(res){
console.log('suc',res)
},function(err){
console.log('err',err)
})
可以看到new了一個Promise,裏面有一個回調函數,回調函數里有2個參數,分別又是另外2個函數。其實裏面很多也都是回調函數的封裝調用。
const [PENDING,RESOLVED,REJECTED]=["PENDING","RESOLVED","REJECTED"];` class Promise1 { constructor(executor){ state = PENDING; value = undefined; reason = undefined; resolve = (value) => { if(this.state === PENDING){ this.state = RESOLVED; this.value = value; } } reject = (reason) => { if(this.state === PENDING){ this.state = REJECTED; this.value = reason; } } try{ executor(this.resolve,this.reject) }catch(e){ reject(e) } } }
測試一下執行情況:
let p1 = new Promise1((resolve,reject)=>{//function:executor
console.log(111)
setTimeout(()=>{
resolve(111)//this.resolve,直接傳參調用
}, 1000)
})
下面就是then了
class Promise1 {
constructor(executor){
...
onResolvedCallbacks=[]; //then,pending里先存起來
onRejectedCallbacks=[];
...
resolve = (value) => {
if(this.state === PENDING){
...
//executor里如果是異步會把then里存起來,然後executor走完了resolved的話,會再調then里回調函數
this.onResolvedCallbacks.forEach(fn => fn(value))
}
}
reject = (reason) => {
if(this.state === PENDING){
...
this.onRejectedCallbacks.forEach(fn => fn(reason))
}
}
}
then(onResolved,onRejected){
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
};
switch(this.state){
case RESOLVED : //狀態變了,就直接把結果給出去
onResolved(this.value);
case REJECTED :
onRejected(this.reason);
case PENDING :
//如果是pending的話,說明executor還沒走完,先存起來,走完再調用
this.onResolvedCallbacks.push(onResolved);
this.onRejectedCallbacks.push(onRejected)
}
}
}
測試一下 :
let p2 = new Promise1((resolve, reject) => {
setTimeout(()=>{
resolve(222)
}, 1000)
})
p2.then(res => console.log(res, 'res')) //222
鏈式調用:
class Promise1 {
...
then(onResolved,onRejected){
...
//返回一個promise1
let newPromise=new Promise1((resolve,reject)=>{
switch(this.state){
case RESOLVED : //狀態變了,就直接把結果給出去
setTimeout(()=>{//then,放後面處理
try{
let reValue=onResolved(this.value);
rePromise(newPromise,reValue,resolve,reject)
}catch(e){reject(e)}
},0)
case REJECTED :
setTimeout(()=>{
try{
let reValue=onRejected(this.reason);
rePromise(newPromise,reValue,resolve,reject)
}catch(e){reject(e)}
},0)
case PENDING :
//如果是pending的話,說明executor還沒走完,先存起來,走完再調用
this.onResolvedCallbacks.push(()=>{
setTimeout(()=>{
try{
let reValue=onResolved(this.value);
rePromise(newPromise,reValue,resolve,reject)
}catch(e){reject(e)}
},0)
});
this.onRejectedCallbacks.push(()=>{
setTimeout(()=>{
try{
let reValue=onRejected(this.reason);
rePromise(newPromise,reValue,resolve,reject)
}catch(e){reject(e)}
},0)
})
}
})
return newPromise;
}
}
//newPromise:新的promise1對象,reValue:上一個then的返回值,newPromise.resolve,newPromise.reject
function rePromise(newPromise,reValue,resolve,reject){
//相當於把自己return出去了,let p2 = p.then(res => p2);
if(newPromise === reValue){
reject(new TypeError('循環了'))
}
if(reValue !== null && (typeof reValue === 'object' || typeof reValue === 'function')){
try{
//判斷一下reValue是不是promise1,是個對象,還帶有then函數
//如果有then並是個函數,就調then;
let then = reValue.then;
if(typeof then === 'function'){
then.call(reValue, res=>{
resolve(res)
},err=>{
reject(err)
})
}else{//then不是函數,直接用resolve返回值
resolve(reValue)
}
}catch(e){
reject(e)
}
}else{//只是個普通值
resolve(reValue)
}
}
測試一下:
p3.then(res => {
console.log(res)
return new Promise1((resolve, reject) => {
resolve('p3')
})
}).then(res => console.log(res, 'pp3'))//p3
但還有個問題
...
function rePromise(newPromise,reValue,resolve,reject){
...
let called;//是否調用過,防止多次調用
if(reValue !== null && (typeof reValue === 'object' || typeof reValue === 'function')){
try{
let then = reValue.then;
if(typeof then === 'function'){
then.call(reValue, res=>{
if(called) return;
called = true;
//promise1就繼續下一個,直到then走完,變成普通的值
rePromise(newPromise,res,resolve,reject)
},err=>{
if(called) return;
called = true;
reject(err)
})
}else{//then不是函數,直接用resolve返回值
resolve(reValue)
}
}catch(e){
if(called) return;
called = true;
reject(e)
}
}else{//只是個普通值
resolve(reValue)
}
}
測試一下
let p1=new Promise1((resolve,reject)=>{
resolve(111)
})
let p2=p1.then(res=>{console.log(res,'p1')},err=>console.log(err,'p1'));
p2.then(res=>console.log(res,'p2'))
.then(res=>console.log(res,'p3))
還有其它屬性:
class Promise1 {
...
catch(onReject){
return this.then(null,onReject)
}
defer(){
let defer={};
defer.promise=new Promise1((resolve,reject)=>{
defer.resolve=resolve;
defer.reject=reject;
})
return defer;
}
deffered(){
return this.defer;
}
all(promises){
return new Promise1((resolve,reject)=>{
let done=gen(promises.length,resolve);
for(let i=0;i<promises.length,i++){
promises[i].then(res=>{
done(i,res)
},reject)
}
})
}
race(promises){
return new Promise1((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject)
}
})
}
resolve(value){
return new Promise1((resolve,reject)=>{
resolve(value)
})
}
reject(reason){
return new Promise1((resolve,reject)=>{
reject(reason)
})
}
}
function gen(times,cb){
const result=[];
let count=0;
return (i,data)=>{
result[i]=data;
count+=1;
if(count===times){
cb(result)
}
}
}
站長推薦
1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲
鏈接: http://www.fly63.com/article/detial/10159