关注掘金已经好久好久,一直没有动笔,因为博主不是在加班就是在加班的路上,啦啦啦!废话少说,进入正文......
前几天,小伙伴遇到问题,就是传说中的回调黑洞,说黑洞有点夸张了,就是两层而已。下面讲述下背景,一个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:刚聚完餐,吃的好饱!!