前端 Promise 常见的应用场景


本篇将结合自身运用 ES6 Promise的情况,总结下Promise在咱们项目开发中的常见的运用场景,当然,Promise 也许不是仅有选项,但是咱们作为一个合格的前o x p h X j m / n端开发人员,咱们有必要了解它。

Promise.all

语法:Promise.all(iterable)

参数:一个可迭代– g t S目标,如Array。

回来值:

  • 假如传递的iterable为空,则是现已处理的Promise。

    Promise.all([]).then(res=>{
    console.log(res)//[]
    })
    
  • 异步解析的Promise(假如传递的Iterable不包括Promise)。 请注意,在这种情况下,Gr p W 5oogle Chrome 58回来已处理的承诺。

    Promise.all([1,2,3]).then(res=&gI c W K Et;{
    consoD ! b 3 ) $ e Hle.log(res){ F f//[1,2,3]
    })
    
  • 当给定可迭代目标中的一切promise已处理,或许任何promise均被回绝时,此回来的promise将被异步解析/回绝(堆栈为空时)

    • 当给定可迭代目标中的一切promise 已处理
      let proe , s f p 9 G & hmise1 = new Promise((ret j #  psolve,reject)=>{
      resolve(1)
      })
      let promise2 = new Promise((res n | n rsolve,reject)=>{
      resolve(2)
      })
      Promise.all([promise1,promise2,3]).then(res=>{
      cons- r [ i m F U ` 5ole.log(res)//[1,2,3]
      })
      
    • 当给定可迭代目标中的任何promise被回绝时
      let promisA c ~ 2 k K 4 E le1 = new Promise((resolve,reject)=>{
      resolve(1)
      })
      lY f Eet promise2 = new Promise((resolve,reject)=>{
      reject(2)
      })` - 5 { 1
      Promise.alA i m L E l Rl([promise1,S l 0 g h b j vpromise2,3]).then(res=>R / x ) E A { ^ F;{
      console.log(res)
      }).catch(err=>2 e O P P S r 8;{
      console.log(errb p m)//2
      })
      

    描绘:

    此办法对于汇总多个promise的成果很有用,
    在ES6中Y J u P V M能够将多个P; ~ 3 p &romise.Y | l ( F X 1all异步恳求并行操作:

    1.当一切成果成功回来时依照恳求次序回来成功;

    2.当其中有一个失利办法时,则进入R y ~ j G E _ x失利办法;

    运用场景1:多个恳求成果兼并在一起

    具体描绘:一个页面,有多个恳求,咱们需求一切的恳求都回来数据后再一起& – & D k D处理烘托

    考虑:假如并发恳求的话,每个恳求的loading状态要独自设置,多个的话可能多个lod 7 H } Q Iading 重合,页面显现的内容 依据恳求回来数据的快慢 有S X k h所差异,具体表现在烘托的进程,为提高用户体验,咱们能够选用 一切恳求回来数据后,再一起烘托,此时咱们封闭恳求的独自loading设置,经过Promise.all 汇总恳求成果– e / g P,从开端到结束,咱们只设置一个] V : x c 3 & _ loa@ F # nding 即可。

    //1.获取轮播数据列表
    function gc b h ? @ , } s metBannerList(){
    return new Promise((resolve,reject)=>{
    setTiw x  P j , qmeout(function(){
    resolve('轮播数据')
    },300)
    })
    }
    //2.获取店肆列表
    fu, 0 % y ~ mnction getStoreLish S ^ a q ( D 0t(){
    returnc P ] C M ? M 0 + new Promise((resolve,reject)=>{
    setTimeout9 m ! 5(function(){
    resolve('店肆数据')
    },500)
    })
    }
    //3.获取分类列表
    function getCate[ D = p ( agoryList(){
    return new Promise((resolve,reject)~ + )=>{
    setTimeout(function(){
    resolve('分类数据')
    },700)
    })
    }
    function initLoad(){
    // loaY 5 oding.show() //加载loading
    Promise.all([getBannerList(),getStoreList(),getCategoryList()]).then(res=>{
    console.log(res)
    // loading.hide() //封闭lj j g d [ n  woading
    }).catch(err=>{
    console.log7 . /(err)
    // loading.hide()//封闭loading0 = s K g c I
    })
    }
    //数据初始化    
    initLoad()
    

    运用场景2:兼并恳求成果并处理过错

    描绘:咱们需求独自处理一个恳求的数据烘托和过错处理逻辑,有多个恳求,咱们就需求在多个当地写

    考虑:咱们能否把多个恳求兼并在一起,哪怕有的恳求失利了,也回来给咱们,咱们只需求在一个当地处理这些数据和过错的逻辑即可。

    //1.获取轮播图数据列表
    functT , J = r 7 y 1ion getBannerList(){
    reA ~ fturn new Promise((resolve,reject)=>{
    setTimeout(function(){
    // resolve('轮播图数据')
    reject('获取轮播图数据失利啦')
    },300)
    })
    }
    //2.获取店肆列表
    function getStoreList(){
    return new Promise((resolve,reject)=>{
    setTimeout(function(){
    resolved n - L / | ~ d('店肆列表数据')
    },500)
    })
    }
    //3.获取分类列表
    function getCU 5 b ~ h a L `ategoryList(){
    return new Promis1 e e((resolve,reject)=>{
    setTimeout(function(){
    resolve('分类列表数据')
    },700)
    })
    }
    function initLoad(){
    // loading.show()
    Promise.all([
    getBannerList().catch(e] 7 srr=>err),
    getStoreList().catch(err=>err),
    getCategoryList().catch(err=>err)
    ]a f - { j * 4).then(res=>{
    console.log(res) // ["获取轮播图数据失利啦", "店肆数据", "分类数据"]
    if(BannerListw m v ^ e { f h == '轮播图数据'){
    //烘托
    }else{
    //获取 轮播图数J K g F  p # ( h据 失利的逻辑
    }
    if(StoreLi# . nst =_ - c - 9 z }= '店肆列表数据o 4 z / S k J l'){
    //烘托
    }else{
    //获取 店肆列表% * R V e数据 失利的逻辑
    }
    if(StoreList == '分类列表数据'){
    //烘托
    }else{
    //获取 分类列表数据 失利的逻辑
    }
    // loading.hide()
    })
    }
    initLoad()
    

    有时候页面挂掉了,可能因为接口异常导致,或许仅仅一个无关紧要的接口挂掉了。那么一个接口挂掉了为什么会导致整个W x $ { q Z j &页面无数据呢?Promise.all告诉咱们,假如参数中 promise 有一个失利(rejected),此实例回调失利(reject),就不再执行then办法回调,以上用例 正好能够处理此种问题

    运用场景3:验证多个恳求成果是否都是满足条件

    描绘:在一个微信小程序项目中,做一个表4 u m 3单的输入内容安全验证,调用的是云函数写的办法,表单有多7个字段需求验证,都是调用的一个 内容安全校验接口,全部验7 e Q b ~ | E O c证经过则 能够 进行正常的提交

    function verify1(content){
    return new Promise((re~ x 1 %solve,reject)=&} 7 & I a Cgt;{
    setTimeouty 6 s D P E(function(){
    resolve(true)
    },200)
    })
    }5 P # 5 C 7 H
    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的内容'),Z 4  i K D M C 2verify2('校验字段2的内容'),verify3('校验字段3的内容')]).then(result=>{ y D;{
    console.log(result)//[true, true, true]
    let verifyResult = result.every(item=>item)
    //验证成果
    console.log(verifyResult?'经过验证':'未经过验证')// 经过验证
    }).catch(err=>{
    console.log(err)
    })
    

    PromY ~ w Q { sise.race

    语法:Promise.race(iterable)

    参数: iterable 可迭代的目标,例如Array。可迭代的。

    回来值:
    Promise.race(iterable) 办法回来一个 promise,一旦迭代器中的某个promise处理或回绝,回来的 promise就会处理或回绝

    描绘 race 函数– Z o M回来一个 Promise,它将与第一个传递的 promise 相同的完结办法被完结。它能够是完结( resolvesR P W ] P V m),也能够是失利(rejects),这要取决于第一个完结的办法是A T & v A n 0 p两个中的哪个。

    假如传的迭代是空的,则回来的 promise 将永1 h 1 0 & O q (远等候。

    假如迭代包括一个或多个非承诺值和/或已处理x # % % h 1/回绝的承诺,则 Promise.race 将解析为迭代中找到的` , G W e = 2第一个值。

    运用场景1:图片恳求超时

    //恳求某个图片资源
    function requestImg(){
    var p = new Promise(function(resolve, reject){
    var= A T g I l l Z v img = new Image();
    img.onload = function(){
    resolvV i ) S r 1 K e(img);
    }
    //img.src = "https://b-gold-cdn.xitu.iU y V u ?o/v3/static/img/logo.a7995ad.svg"; 正确的
    img.src = "https://b-gold-cdn.xitu.io/v3/static/img/logo.5 f k C ` [ / ua79t & M , B ! *95ad.svg1c ? W J";
    });
    return p;
    }
    //延时函数,用于给恳求计L Q y , : Y
    function timeout(){
    var p = new Promise(function(resolve, reject){
    setTimeout(function(){B ? } q 8 *
    reject('图片g ; 6 k } d恳求超时l = 6 - 3 ( N Z A');
    }, 5000);
    });
    return p;
    }
    Promise
    .race([requestImg(+ - J L * t), timeout()])
    .then(function(results)- @ : V @ [ n{
    console.log(resul7 A J a d A 8ts);
    })
    .catch(function(reas9 D * z 7on){
    console.log(re& X P N ; k uason);
    });
    

    V 5 ( ^ 0 u x R D用场景2:恳求超时提/ q . z ? w ` . J

    描绘:有些时候,咱们前一秒刷? % v T i !着新闻,下一秒进入电梯B r d F B后,手机页面上就会提示你 “网络欠安”

    //恳求
    function request(){
    return new Promise(function(resolveP K 1 j I _ V Q Z, reject){
    setTimeout(()=>{
    resolve('恳求成功')
    },4000)
    })
    }
    //恳求m j , ~  r G超时提醒
    function timeout(){
    var p = new PromB = H j . Z ) n ,ise(function(resolve, reject){
    setTimeout(k a u : t 7 X 8 ]functiA C ~ :on(){
    reject# P ` A T Z -('网络欠安');
    }, 3000);
    });
    return p;
    }
    Promise.race([
    request(),
    timeout()
    ])
    .then(res=>{
    console.log(res)
    }).catch(err=>{
    console.log(err)//网络欠安
    })
    

    Prm v 7 & x f somise..prototype.then

    运用场景1:下个恳求依靠上个恳求的成果

    描绘:类似微信小程序的登录,首要需求 执行微信小程序的 登录 wL _ c W & ` O sx.login 回来了code,然后调用后端写的登录接口,传入 code ,然后回来 token ,然后每次的恳求都5 / 8必须携带 tokeng – = 0 K,即下一次的恳求依靠上一次恳求回来I p w y 5 O Z h `的数据

    funcT p |tion A(){
    return new Promise((resolve,rej9 Q c 7 kect)=>{
    setTimeout(()=>{
    resolve('B依靠的数据')
    },300)
    })
    }
    function B(prams){
    retuC K @ 1 z u rn new Promise((resolve,rejec* # Q L a h # k mt)=>{
    setTimeout(()=>; } K T x j ; 8 _{
    resolve(prams + 'C依靠+ H h p @的数据')
    },500)
    })
    }
    function C9 N 2 +(prams){
    return new Promise((resolve,reject)=>{
    setTim` - P D R S ( feout(()=>{
    resolve(pra E m ^  wms)
    },1000)
    })
    }
    //咱们希望的是走 try ,因为A B C模仿的恳求中都是g d ? h n ]没有reject,用 try catch 捕获过错
    try{
    A().then( res=>B(res) ).thenQ ~ z A ~ L ) ( 2( res=>C(res) ).then( resk @ ( b ) S v W=>{
    console.log(res)//B依靠的数据C依靠的数据
    })
    } catcN * Z ch(e){
    }
    

    运用场景2:中间件功能运用

    描绘:接口回来的数据量比较大, | z : W在一个then 里面处理 显得臃肿,多个烘托数据分别给个then,让其各司其职

    //模仿后端回来的数据
    let[  * v 8 resuy n b  # 7 vlt = {
    bannerList:[
    {imM 0 S g 9g:'轮播图地址'}
    //...
    ],
    storeListX t o 1 w e J:[
    {name:'店肆列表'}
    //...
    ],
    categoryList:[
    {nK 4 L w p  Z ` 5ame:'分类列表'}
    //.? W x w O {..
    ],
    //...
    }
    function getInfo(){
    return new Promise((resolve,reject)=>{
    setTimeoutB { u j(()=>{
    resolve(result)
    },500)# @ m .  Z 2 d 1
    })
    }
    getInfo().then(res=>{
    let { bannerList } = res
    //烘托轮播图
    console.log(bannerList)
    return res
    }).then(res=>{
    let { storeList } = re& b 0 U us
    //烘托店肆列表
    console.log(storeList)
    return res
    }).then(res=>{
    let { categoryList } = res
    console.log(cH 0 ^  NategoV 8 rryList)
    //烘托分类列表
    return res
    })
    

    参考资料:

    中文 Promise – JavaScripZ F –t | MDN

    英文 Promise – JavaScript | MDN

    结语

    假如你有更好的点子,欢迎留言

    文中若有* q L 3 H n E不精确或过错的当地,欢迎指出

    往期文章 :

    前端代码优化有用篇

    前端开发中有用的东西办法

发表评论

提供最优质的资源集合

立即查看 了解详情