首頁 > web前端 > js教程 > 主體

前端 Promise 常見的一些應用場景

hzc
發布: 2020-06-15 10:08:31
轉載
4392 人瀏覽過

這篇將結合自身使用ES6 Promise的情況,總結下Promise在我們專案開發中的常見的應用場景,當然,Promise 也許不是唯一選項,但是我們作為一個合格的前端開發人員,我們有必要了解它。

Promise.all


#語法:Promise.all(iterable)

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

傳回值:

  • 如果傳遞的iterable為空,則是已經解決的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將被非同步解析/拒絕(堆疊為空白時)

     1. 當給定可迭代物件中的所有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]
})
登入後複製

           2..當給予可迭代物件中的任何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
})
登入後複製

推荐教程:《JS教程

以上是前端 Promise 常見的一些應用場景的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:juejin.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板