沐鳴註冊平台官網_手寫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