小顺序异步题目:多个网络要求顺次实行并顺次网络要求效果

营业逻辑

近来开辟一个便签小顺序的时刻,有如许一个需求:用户能够在写便签的时刻增加一个或多个图片。

关于这个需求,我们用户按下保留键时,内部详细的完成上是如许的逻辑:

  1. 起首检测用户是不是传入了图片,假如存储当地图片地点的数组长度>=1,则将图片数组放入上传图片的函数。
  2. 由于小顺序网络要求大小限定,我们只能采用轮回上传单文件,然后网络每次要求的结果–图片在服务器的地点,末了将结果放在一个数组中供后续的操纵运用。
  3. 当图片上传函数悉数实行终了后,将数组中的图片数组取出来,赋值到日志对象中,再将全部日志对象提交到服务器。
  4. 服务器返回保留胜利或失利。

思绪实在异常清楚简朴,然则在代码完成上却翻了大跟头。

异步带来的题目

小顺序的网络要求是异步的:我们没法经由过程return来将网络要求结果返回出来运用。


    wx.request({

          //...省略其他属性

          success: function (res) {

          },

          fail: function (res) {

          }

    })

比方在微信中发送网络要求,我们只能运用微信供应的要领wx.xxx,个中要求的结果保留在res中,而res没法直接return获得。

处置惩罚:res虽然没法直接猎取,然则我们能经由过程将须要运用到这个要求结果的营业逻辑代码放入这个网络要求的回调函数中直接读取网络要求结果,也就是一切都须要经由过程回调来处置惩罚。


    wx.request({

          //...省略其他属性

          success: function (res) {

            console.log(res);

            //接营业逻辑代码

          },

          fail: function (res) {

            console.log(res);

          }

    })

比方这个微信的网络要求,我们能够经由过程success和fail的回调函数来读取res的值从而完成依靠res结果的营业逻辑。

回调地狱

虽然处置惩罚了结果猎取的题目,然则又产生了另一个题目,当多个要求中有明白的先后顺序时,回调会嵌套的很厉害,形成回调地狱,代码可读性和可维护性都邑很差。
比方关于一个日志页面,须要先要求到页面的数据(内里包含了图片数据和其他数据的地点),再依据页面数据去要求图片数据后再要求音频数据。比方以下代码:


   //要求页面团体数据

   wx.request({

         //...省略其他属性

         success: function (res) {//胜利

               //要求图片数据

               wx.request({

                 success: function (res) {//胜利

                     //要求音频数据

                     wx.request({

                         success: function (res) {//胜利

                         },

                         fail: function (res) {//失利

                             console.log("要求失利:"+res);

                         }

                     })

                 },

                 fail: function (res) {//失利

                     console.log("要求失利:"+res);

                 }

               })

         },

         fail: function (res) {//失利

             console.log("要求失利:"+res);

         }

   })

怎样优化?荣幸的是,在es6内里我们能够用promise去优化我们的回调,用then替代回调,起首将网络要求封装成一个Promise:


   // 背景post要求

   function postRequest(posturl, postdata) {

     return new Promise((resolve, reject) => {

       wx.request({

         //省略其他属性

         success: function (res) {

           console.log("at post request: 要求胜利")

           resolve(res.data)//设置promise胜利标志

         },

         fail: function (res) {

           console.log("at post request: 要求失利")

           reject(res.data)//设置promise失利标志

         }

       })

     });

   }

如许封装今后,我们的网络要求会在success和fail后回调resolve,如许能够通知promise,“hey,我完成我的工作了,你能够举行你的then操纵了”,如许就能够用then来简化嵌套逻辑。运用promise来完成上面谁人题目的要求将会是如许的:


    postRequest(posturl,postdata)

    .then(function(res){

      //营业逻辑

      //挪用下一个要求

      return postRequest(next_posturl,next_postdata);

    })

    .then(function(res){

      //营业逻辑

      //挪用下一个要求

      return postRequest(next_next_posturl,next_next_postdata);

    })

    .then(function(res){

      //营业逻辑

    });

是不是是简约的多~

一个看似简朴的需求

我们的有一个很简朴的需求是须要对一组数目不定的图片做离别上传(由于微信限定所以没法做多上传),而且在上传完成今后须要猎取到一切的返回结果。

那末用我们前面的回调函数+then的话,很天然的想到如许的写法


postRequest(posturl,postdata)

.then(function(res){

    //猎取返回res

    //上传下一个图片

    return postRequest(next_posturl,next_postdata);

})

.then(function(res){

    //猎取返回res

    //上传下一个图片

    return postRequest(next_next_posturl,next_next_postdata);

})

.then(function(res){

    //猎取返回res

});

如许看起来很简朴清楚明了,然则我的图片数目是不定的,怎样动态的构建.then.then.then如许的链式挪用呢?经由我的研讨后发明能够经由过程一个辅佐的promise链去完成主链的链式构建。


//多文件上传

function jabingp_upLoad(uploadurl, files) {

  return new Promise((resolve, reject) => {

    //初始化promise链

    var mergedAjax = Promise.resolve();

    var response = [];

    // 轮回上传

   
    // 这里一定要运用let来为没一次轮回构建一个块级作用域
    // 运用var则须要合营马上实行函数
    for (let i = 0; i < files.length; i++) {

      mergedAjax = mergedAjax.then(() => {

        return jabingp_upLoadSingle(uploadurl, files[i]).then((res) => {

          response.push(res);

        });

      });

    }

    //当前面轮回中一切的then实行终了时会实行这个then

    mergedAjax.then(() => {

      resolve(response);            //设置这个函数的promise对象为完成状况并放入数据

    });

  });

}

经由过程这个函数,就完成了多个要求顺次实行并网络结果的结果。这个函数的重点在于应用别的一个已处于完成状况的promise,不停的迭代本身,在每次迭代的then内部经由过程return来完成辅佐链到营业链的切换。

2019-04-27 更新

运用await/async越发文雅地处置惩罚异步吧!

在es7规范中,引入了await和async这对兄弟,它们能够让我们的异步代码看起来和同步代码一样。让我们来看看await和async都能做什么吧。

await能够守候一个promise运转到完成状况而且猎取结果,或许守候一个async润饰的函数运转完成并猎取结果,然则运用await的时刻,必须在async函数体内部。比方我有如许一个网络要求:

 function postRequest(posturl, postdata) {

     return new Promise((resolve, reject) => {

       wx.request({

         //省略其他属性

         success: function (res) {

           console.log("at post request: 要求胜利")

           resolve(res.data)//设置promise胜利标志

         },

         fail: function (res) {

           console.log("at post request: 要求失利")

           reject(res.data)//设置promise失利标志

         }

       })

     });

   }

那末假如不运用await,我就须要如许获得要求结果

function test(){
  postRequest(xxx,xxx).then(function(res){
      // 这内里能够读取要求结果res了
      console.log(res);
  });
}
test();

能够看到,如许的代码不太相符通例逻辑,我们希望函数作用是返回数据,如许更清楚清楚明了,有了await,我们的希望就能够完成了。

async function test(){
 let res = await  postRequest(xxx,xxx);
 // 下面就能够一般写对res的读取了
 console.log(res);
}
test();

注重我给函数加上了async,有了async和await,我们就能够像同步代码一样运用异步要求了~
那末上面谁人经由过程庞杂的构建链完成的需求,经由过程await完成将会变得异常简朴易懂。

async function jabingp_upLoad(uploadurl, files) {
    let response = [];
  
    // 轮回顺次守候上传结果
    for (let i = 0; i < files.length; i++) {
        let  res = await jabingp_upLoadSingle(uploadurl, files[i]);
        // 结果放入数组
        response.push(res);
    }
    // 返回结果
    return  response ;
}

代码一会儿变得简约易懂了,注重挪用的时刻也一样须要在一个async函数内部实行await。

async function test(){
 let response = await  jabingp_upLoad(xxx,xxx);
 console.log(response );
}
test();

是不是是异常简朴呢,赶忙在你的异步要求中运用async和await吧~

    原文作者:JabinGP
    原文地址: https://segmentfault.com/a/1190000019064968
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞