My Promise

Rocky1發表於2019-04-01

Promise 簡單來說是非同步程式設計的一種解決方案

Promise物件有以下兩個特點:

(1)物件的狀態不受外界影響。Promise物件代表一個非同步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。

(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise物件的狀態改變,只有兩種可能:從pending變為fulfilled和從pending變為rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果。

(3)有了Promise物件,就可以將非同步操作以同步操作的流程表達出來,避免了層層巢狀的回撥函式。

promise的寫法

let mypromise=new Promise((resolve, reject)=>{
    setTimeout(()=>{
    resolve(100)  
    },1000);
});

mypromise.then((res)=>{
    console.log(res);
},()=>{
    console.log("no");
})
複製程式碼

用promise寫Ajax

let pro=new Promise((resolve,reject)=>{
    let xhr=new XMLHttpRequest();
    xhr.open("get","js/1.js",true);
    xhr.onreadystatechange=()=>{
    if(xhr.readyState===4 && xhr.status===200){
        val=xhr.responseText;
        resolve(val);
    }
    if(xhr.status!==200){
        reject();
    }
    };
    xhr.send();
});

pro.then((res)=>{
    console.log(res);
    獲取資料//資料繫結
},()=>{
    console.log("no不行");
})
複製程式碼

這樣一來管理回撥函式或者非同步事件就很清楚了。可以後面繼續追加.then();

then中兩個方法,成功走第一個,失敗走第二個,

比如實現某一種效果,就比如商品排序。

第一個then請求資料,繫結資料,渲染資料

第二個then從小到大排序

第三個then從大到小排序

let op=new Promise((resolve,reject)=>{
    //Ajax請求資料
})

op.then((res)=>{
    繫結資料//渲染資料
},()=>{
    
}).then(()=>{
    //商品排序
})
...以此內推
複製程式碼

一旦在第一個then中return了,那麼返回結果就給了第二個then,以此內推。

這種設計模式,功能很強大,也方便了許多,從上面可以看出 .then()可以寫很多個,那麼promise的實現原理是什麼呢?

接下來就小手擼程式碼,進入正題

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    class MyPromise{
        constructor(excutor){
        
            // 這裡相當於MyPromise的函式體;
            // 在promise中分三個狀態;pending  fulfilled rejected;
            // this --> promise的例項;給例項新增state屬性,其屬性值是"pending";
            
            this.state="pending";
            
            // 在例項上找了兩塊空間;一個是用來儲存成功的回撥,一個用來儲存失敗的回撥;
            
            this.fulfilledEvent = [];
            this.rejectedEvent = [];
            this.value =undefined;
            
            let resolve = (result)=>{
                 // resolve : 這個函式是用來管控所有成功態的函式執行;
                // 一旦呼叫resolve,那麼應該變成成功態;
                
                //if(this.state==="fulfilled"||this.state==="rejected")return;
                // 如果當前狀態已經凝固,是成功或者失敗中的一個,都不再執行;
                
                if(this.state!=="pending")return;
                this.state="fulfilled";
                this.value=result;
                clearTimeout(this.timer);
                 this.timer = setTimeout(()=>{
                    this.fulfilledEvent.forEach((item)=>{
                        if(typeof item==="function"){
                            item(this.value);
                        }
                    })
                 },0)
            };
            
            let reject=(result)=>{
                if(this.state!=="pending")return;
                this.state="rejected";
                clearTimeout(this.timer);
                this.value=result;
                this.timer = setTimeout(()=>{
                    this.rejectedEvent.forEach((item)=>{
                        if(typeof item==="function"){
                            item(this.value);
                        }
                    })
                },0)
            }
            try{
                excutor(resolve,reject)
            }catch(e){
                // 如果在函式中丟擲異常,那麼會呼叫下面then的reject的方法;
                reject(e);
            }

        }
        then(resolveFn,rejectedFn){
            if(resolveFn===undefined){
                //如果then沒有傳遞函式,那麼給當前預設賦值一個函式
                resolveFn=(result)=>{
                    return result
                }
            }
            if(rejectedFn===undefined){
                rejectedFn=()=>{
                    // 這個地方丟擲異常,為了能夠呼叫下個then的失敗的方法;
                    throw new Error;
                }
            }
            
            
            // 為了確保下一次的then方法中的回撥受上一次then方法中返回值的影響,
            //所以每次呼叫then,都返回一個不同的例項;
            
            return new MyPromise((resolve,reject)=>{
                // this --> then中this--> p1;
                this.fulfilledEvent.push(()=>{
                    // 需要驗證當前resolveFn函式的返回值是否是一個Promise的例項;
                   try{
                       let x = resolveFn();
                       x instanceof MyPromise?x.then(resolve,reject):resolve();
                   }catch(e){
                       reject(e)
                   }
                });
                this.rejectedEvent.push(()=>{
                    try{
                        let x = rejectedFn();
                        x instanceof MyPromise?x.then(resolve,reject):resolve();
                    }catch(e){
                        reject(e)
                    }
                });
            });
        }
    }
    let p1 = new MyPromise(function (resolve,reject) {
        resolve(200)
    })
    console.log(1);
    let p2=p1.then(function (res) {
        return new MyPromise(function (resolve,reject) {
            reject();
        })
    },function () {
        console.log(101);
    });
    p2.then(function () {
        console.log(11);
    },function () {
        console.log(22);
    })

</script>
</body>
</html>
複製程式碼

注意:

  1. 當new 一個promise時,promise中的函式會立馬執行
  2. 當promise的狀態一旦固定,就不再改變
  3. 無法取消Promise,一旦新建它就會立即執行,無法中途取消
  4. 如果不設定回撥函式,Promise內部丟擲的錯誤,不會反應到外部
  5. 當處於pending狀態時,無法得知目前進展到哪一個狀態

then方法

  1. then : 為promise的例項增加狀態發生改變時的回撥函式
  2. then: 把第一個then中的回撥的返回值會傳遞給第二個then回撥的函式的形參
  3. then : 方法中內建會返回一個新的promise的例項;但不是之前的那個promise的例項了
  4. 前面一個回撥函式中如果返回一個promise的物件,那麼第二個回撥函式會等待第一個返回的promise例項的狀態發生變化才執行

promise的catch

  1. catch : 捕獲當前非同步的錯誤資訊
  2. 如果在catch之前已經有then將錯誤資訊進行處理,那麼不再執行這個catch方法
  3. 如果第一個請求失敗,那麼不會再執行第二個請求
  4. catch : 只要之前的請求有一個失敗,都會觸發這個catch方法

promise的all

  1. all : 是將多個Promise的例項包裝成一個promise的例項
  2. all方法是Promise這個類的私有方法
  3. all方法傳遞一個陣列,陣列中存放著Promise的例項;all方法返回一個promise的例項
  4. p1的成功或者失敗的狀態由陣列中每一個promise的例項決定;當所有的例項的狀態都是成功態,那麼該p1的狀態才是成功態,只要有一個失敗,那麼這個就會執行失敗態
 let p1 = Promise.all([l1,l2,l3]).then(function () {},function () {})
複製程式碼

參考文件 es6.ruanyifeng.com/?search=pro…

My Promise