前端 Promise 常見的應用場景

本篇將結合自身使用 ES6 Promise的狀況,總結下Promise在咱們項目開發中的常見的應用場景,固然,Promise 也許不是惟一選項,可是咱們做爲一個合格的前端開發人員,咱們有必要了解它。前端

Promise.all

語法:Promise.all(iterable)小程序

參數:一個可迭代對象,如Array。後端

返回值:微信小程序

  • 若是傳遞的iterable爲空,則是已經解決的Promise。promise

    Promise.all([]).then(res=>{
        console.log(res)//[]
    })
    複製代碼
  • 異步解析的Promise(若是傳遞的Iterable不包含Promise)。 請注意,在這種狀況下,Google Chrome 58返回已解決的承諾。安全

    Promise.all([1,2,3]).then(res=>{
        console.log(res)//[1,2,3]
    })
    複製代碼
  • 當給定可迭代對象中的全部promise已解決,或者任何promise均被拒絕時,此返回的promise將被異步解析/拒絕(堆棧爲空時)微信

    • 當給定可迭代對象中的全部promise 已解決
      let promise1 = new Promise((resolve,reject)=>{
          resolve(1)
      })
      let promise2 = new Promise((resolve,reject)=>{
          resolve(2)
      })
      
      Promise.all([promise1,promise2,3]).then(res=>{
          console.log(res)//[1,2,3]
      })
      複製代碼
    • 當給定可迭代對象中的任何promise被拒絕時
      let promise1 = new Promise((resolve,reject)=>{
          resolve(1)
      })
      let promise2 = new Promise((resolve,reject)=>{
          reject(2)
      })
      
      Promise.all([promise1,promise2,3]).then(res=>{
          console.log(res)
      }).catch(err=>{
          console.log(err)//2
      })
      複製代碼

    描述:網絡

    此方法對於彙總多個promise的結果頗有用, 在ES6中能夠將多個Promise.all異步請求並行操做:併發

    1.當全部結果成功返回時按照請求順序返回成功;異步

    2.當其中有一個失敗方法時,則進入失敗方法;

    應用場景1:多個請求結果合併在一塊兒

    具體描述:一個頁面,有多個請求,咱們需求全部的請求都返回數據後再一塊兒處理渲染

    思考:若是併發請求的話,每一個請求的loading狀態要單獨設置,多個的話可能多個loading 重合,頁面顯示的內容 根據請求返回數據的快慢 有所差別,具體表如今渲染的過程,爲提高用戶體驗,咱們能夠採用 全部請求返回數據後,再一塊兒渲染,此時咱們關閉請求的單獨loading設置,經過Promise.all 彙總請求結果,從開始到結束,咱們只設置一個 loading 便可。

    //1.獲取輪播數據列表
    function getBannerList(){
        return new Promise((resolve,reject)=>{
            setTimeout(function(){
                resolve('輪播數據')
            },300)
        })
    }
    
    //2.獲取店鋪列表
    function getStoreList(){
       return new Promise((resolve,reject)=>{
            setTimeout(function(){
                resolve('店鋪數據')
            },500)
        })
    }
    
    //3.獲取分類列表
    function getCategoryList(){
       return new Promise((resolve,reject)=>{
            setTimeout(function(){
                resolve('分類數據')
            },700)
        })
    }
    
    function initLoad(){
        // loading.show() //加載loading
        Promise.all([getBannerList(),getStoreList(),getCategoryList()]).then(res=>{
            console.log(res)
            // loading.hide() //關閉loading
        }).catch(err=>{
            console.log(err)
            // loading.hide()//關閉loading
        })
    }
    //數據初始化 
    initLoad()
    複製代碼

    應用場景2:合併請求結果並處理錯誤

    描述:咱們需求單獨處理一個請求的數據渲染和錯誤處理邏輯,有多個請求,咱們就須要在多個地方寫

    思考:咱們可否把多個請求合併在一塊兒,哪怕有的請求失敗了,也返回給咱們,咱們只須要在一個地方處理這些數據和錯誤的邏輯便可。

    //1.獲取輪播圖數據列表
    function getBannerList(){
        return new Promise((resolve,reject)=>{
            setTimeout(function(){
                // resolve('輪播圖數據')
                reject('獲取輪播圖數據失敗啦')
            },300)
        })
    }
    
    //2.獲取店鋪列表
    function getStoreList(){
       return new Promise((resolve,reject)=>{
            setTimeout(function(){
                resolve('店鋪數據')
            },500)
        })
    }
    
    //3.獲取分類列表
    function getCategoryList(){
        return new Promise((resolve,reject)=>{
            setTimeout(function(){
                resolve('分類數據')
            },700)
        })
    }
    
    function initLoad(){
        // loading.show()
        Promise.all([
            getBannerList().catch(err=>err),
            getStoreList().catch(err=>err),
            getCategoryList().catch(err=>err)
        ]).then(res=>{
            console.log(res) // ["獲取輪播圖數據失敗啦", "店鋪數據", "分類數據"]
            
            if(res[0] == '輪播圖數據'){
                //渲染
            }else{
                //獲取 輪播圖數據 失敗的邏輯
            }
            if(res[1] == '店鋪數據'){
                //渲染
            }else{
                //獲取 店鋪列表數據 失敗的邏輯
            }
            if(res[2] == '分類數據'){
                //渲染
            }else{
                 //獲取 分類列表數據 失敗的邏輯
            }
            
            // loading.hide()
        })
    }
    
    initLoad()
    複製代碼

    有時候頁面掛掉了,可能由於接口異常致使,或許只是一個可有可無的接口掛掉了。那麼一個接口掛掉了爲何會致使整個頁面無數據呢?Promise.all告訴咱們,若是參數中 promise 有一個失敗(rejected),此實例回調失敗(reject),就再也不執行then方法回調,以上用例 正好能夠解決此種問題

    應用場景3:驗證多個請求結果是否都是知足條件

    描述:在一個微信小程序項目中,作一個表單的輸入內容安全驗證,調用的是雲函數寫的方法,表單有多7個字段須要驗證,都是調用的一個 內容安全校驗接口,所有驗證經過則 能夠 進行正常的提交

    function verify1(content){
        return new Promise((resolve,reject)=>{
            setTimeout(function(){
                resolve(true)
            },200)
        })
    }
    
    function verify2(content){
        return new Promise((resolve,reject)=>{
            setTimeout(function(){
                resolve(true)
            },700)
        })
    }
    
    function verify3(content){
        return new Promise((resolve,reject)=>{
            setTimeout(function(){
                resolve(true)
            },300)
        })
    }
    
    
    
    Promise.all([verify1('校驗字段1的內容'),verify2('校驗字段2的內容'),verify3('校驗字段3的內容')]).then(result=>{
        console.log(result)//[true, true, true]
    
        let verifyResult = result.every(item=>item)
        //驗證結果
        console.log(verifyResult?'經過驗證':'未經過驗證')// 經過驗證
    }).catch(err=>{
        console.log(err)
    })
    複製代碼

    Promise.race

    語法:Promise.race(iterable)

    參數: iterable 可迭代的對象,例如Array。可迭代的。

    返回值: Promise.race(iterable) 方法返回一個 promise,一旦迭代器中的某個promise解決或拒絕,返回的 promise就會解決或拒絕

    描述 race 函數返回一個 Promise,它將與第一個傳遞的 promise 相同的完成方式被完成。它能夠是完成( resolves),也能夠是失敗(rejects),這要取決於第一個完成的方式是兩個中的哪一個。

    若是傳的迭代是空的,則返回的 promise 將永遠等待。

    若是迭代包含一個或多個非承諾值和/或已解決/拒絕的承諾,則 Promise.race 將解析爲迭代中找到的第一個值。

    應用場景1:圖片請求超時

    //請求某個圖片資源
    function requestImg(){
        var p = new Promise(function(resolve, reject){
            var img = new Image();
            img.onload = function(){
               resolve(img);
            }
            //img.src = "https://b-gold-cdn.xitu.io/v3/static/img/logo.a7995ad.svg"; 正確的
            img.src = "https://b-gold-cdn.xitu.io/v3/static/img/logo.a7995ad.svg1";
        });
        return p;
    }
    
    //延時函數,用於給請求計時
    function timeout(){
        var p = new Promise(function(resolve, reject){
            setTimeout(function(){
                reject('圖片請求超時');
            }, 5000);
        });
        return p;
    }
    
    Promise
    .race([requestImg(), timeout()])
    .then(function(results){
        console.log(results);
    })
    .catch(function(reason){
        console.log(reason);
    });
    複製代碼

    應用場景2:請求超時提示

    描述:有些時候,咱們前一秒刷着新聞,下一秒進入電梯後,手機頁面上就會提示你 「網絡不佳」

    //請求
    function request(){
        return new Promise(function(resolve, reject){
           setTimeout(()=>{
                resolve('請求成功')
           },4000)
        })
    }
    
    //請求超時提醒
    function timeout(){
        var p = new Promise(function(resolve, reject){
            setTimeout(function(){
                reject('網絡不佳');
            }, 3000);
        });
        return p;
    }
    
    
    
    Promise.race([
        request(),
        timeout()
    ])
    .then(res=>{
        console.log(res)
    }).catch(err=>{
        console.log(err)//網絡不佳
    })
    複製代碼

    Promise..prototype.then

    應用場景1:下個請求依賴上個請求的結果

    描述:相似微信小程序的登陸,首先須要 執行微信小程序的 登陸 wx.login 返回了code,而後調用後端寫的登陸接口,傳入 code ,而後返回 token ,而後每次的請求都必須攜帶 token,即下一次的請求依賴上一次請求返回的數據

    function A(){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('B依賴的數據')
            },300)
        })
    }
    function B(prams){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve(prams + 'C依賴的數據')
            },500)
        })
    }
    function C(prams){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve(prams)
            },1000)
        })
    }
    
    //咱們指望的是走 try ,因爲A B C模擬的請求中都是沒有reject,用 try catch 捕獲錯誤
    try{
        A().then( res=>B(res) ).then( res=>C(res) ).then( res=>{
            console.log(res)//B依賴的數據C依賴的數據
        })   
    } catch(e){
        
    }
    複製代碼

    應用場景2:中間件功能使用

    描述:接口返回的數據量比較大,在一個then 裏面處理 顯得臃腫,多個渲染數據分別給個then,讓其各司其職

    //模擬後端返回的數據
    
    let result = {
        bannerList:[
            {img:'輪播圖地址'}
        //...
        ],
        storeList:[
            {name:'店鋪列表'}
        //...
        ],
        categoryList:[
            {name:'分類列表'}
        //...
        ],
        //...
    }
    
    function getInfo(){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve(result)
            },500)
        })
    }
    
    getInfo().then(res=>{
    
        let { bannerList } = res
        //渲染輪播圖
        console.log(bannerList)
        return res
    }).then(res=>{
        
        let { storeList } = res
        //渲染店鋪列表
        console.log(storeList)
        return res
    }).then(res=>{
        let { categoryList } = res
        console.log(categoryList)
        //渲染分類列表
        
        return res
    })
    複製代碼

    參考資料:

    中文 Promise - JavaScript | MDN

    英文 Promise - JavaScript | MDN

    結語

    若是你有更好的點子,歡迎留言

    文中如有不許確或錯誤的地方,歡迎指出

    往期文章 :

    前端代碼優化實用篇

    前端開發中實用的工具方法

相關文章
相關標籤/搜索