解决回调黑洞的async,await实用

1,694 阅读4分钟

关注掘金已经好久好久,一直没有动笔,因为博主不是在加班就是在加班的路上,啦啦啦!废话少说,进入正文......

前几天,小伙伴遇到问题,就是传说中的回调黑洞,说黑洞有点夸张了,就是两层而已。下面讲述下背景,一个vue项目,首先在工具方法里写了两个公共的方法:

  • (1)定位接口获取经纬度,
  • (2)再用获取的经纬度执行下一个异步获取城市信息,包括城市id,城市名称等。

当然这两个方法写在工具脚本里。然后,在.vue的单文件组件里面调用这个方法,并且获取到城市id。

遇到这种情况,最low的办法,是啥呢?就是这个

function a(){
    //异步成功
    b();
}
function b(){
    //执行异步
    retun obj;
}

当然这样写,在正常情况下,没毛病,但是小伙伴这个是要在组件里调用呀,这样用根本拿不到值的,别说有两个异步,就算有一个异步也是undefined

小伙伴百思不得其解,怎么拿不到呢?怎样才能拿到呢? 纠结了好久后,来问我。首先我一看脚本,就跟他说了同步异步的问题,如果要拿到值,就要异步转同步。

此处科普下,异步转同步的方法generator函数,yield关键字,还有最新的号称完美解决回调黑洞的async、await。还有其他欢迎大神们补充。

回到正题,我就开始给小伙伴改代码。先上原来的代码:

function wxGetLocation() {
         wx.getLocation({
             success: function(res) {
                 var lat = res.latitude; // 纬度,浮点数,范围为90 ~ -90
                 var lng = res.longitude; // 经度,浮点数,范围为180 ~ -180。
                 var arr = [];
                 if (lat && lng) {
                     changeLonLat(lon,lat)
                 } else {
                     // 默认经纬度
                    changeLonLat(lon,lat)
                 }
             },
             cancel: function(res) {
                 alert('用户拒绝授权获取地理位置');
             },
             fail: function(e) {
                 alert('定位失败了~');
             }
         })
     })
 }
 function changeLonLat(lon, lat) {
      axios.get('/lonLatGetCityMessage/?lon=' + lon + '&lat=' + lat)
         .then(response => {
          //一系列操作
           return cityParams;
             
         })
         .catch(error => {
             alert('error' + JSON.stringify(error))
         })
 }
//调用
var a = wxGetLocation();
alert(a)
// of course  undefined

刚开始吧,我给小伙伴讲了下思路,大概就是用async await变异步为同步。然后一边在改,当然是在他的基础上加了两个关键字,在需要异步取得数据的地方加了两个关键字,没毛病。但是呢,结果不行。

于是乎我就思考哪里的问题?思路没毛病呀;想到在需要异步回调的时候,(此处划重点,敲黑板)await后面的方法需要返回promise!

于是乎我就继续在那基础上改。还是没解决。既然promise有了,还有啥问题?

想到中心思想是 变异步为同步 ,那都是同步了,还用得着一个套一个?

于是乎把他的代码推掉,重新来过!

完美的写完(后面附代码)!

满怀信心的运行,咦?怎么结果还是underfined,我打包票没毛病

经过alert,确实是按照自己的想法走的,执行完异步才返回数据的。

突然发现promise的resolve参数只有一个,什么鬼?欺负我没new Promise过。果然经过度娘发现,promise的返回只能一个参数。再次修复,测试完美。 下面代码:

function wxGetLocation() {
    return new Promise((resolve, reject) => {
        wx.getLocation({
            success: async function(res) {
                var lat = res.latitude; // 纬度,浮点数,范围为90 ~ -90
                var lng = res.longitude; // 经度,浮点数,范围为180 ~ -180。
                var arr = [];
                if (lat && lng) {
                    arr = [lng, lat];
                    resolve(arr);
                } else {
                    // 默认经纬度
                    arr = ['120.678923', '31.324308']
                    reject(arr)
                }
            },
            cancel: function(res) {
                alert('用户拒绝授权获取地理位置');
            },
            fail: function(e) {
                alert('定位失败了~');
            }
        })
    })
}
function changeLonLat(lon, lat) {
  undefined
    return  axios.get('/lonLatGetCityMessage/?lon=' + lon + '&lat=' + lat)
         .then(response => {
          //一系列操作
           return cityParams;
             
         })
         .catch(error => {
             alert('error' + JSON.stringify(error))
         })
}
//调用方法:
    let lonAndLat;
    await wxGetLocation().then(async (arr)=>{
         lonAndLat =  await changeLonLat(arr[0], arr[1])
    },async (arr)=>{
         lonAndLat = await changeLonLat(arr[0], arr[1])
   });

我自己的项目没有正儿八经的写过这个方法(一直在维护古老的内容),通过帮小伙伴解决这个问题吧,发现我虽然大面上知道怎么做,但是还是需要很多细节的维护的,只能说继续加油!

ps:刚聚完餐,吃的好饱!!