web前端经过百度地图API批量逆解析地址

前言

最近碰到一个需求,就是将咱们系统中要导出一系列的工做数据,这里面有一个需求就是根据工做人员的经纬度去获取他可能的位置。说到这里你们确定能想到用地图API了,我这里用的是百度地图的API(详情可参考)。而后这里就涉及到一个问题,工做数据是不少条的,可是这里的API很明显就只能一条一条的去请求,那么咱们怎么封装可以达到咱们的目的呢。javascript

获取百度AK

首先呢,咱们想要使用百度地图相关的API的话,确定是要去注册申请相关的使用资格的,详细的帐号申请流程呢,请戳这里,这里面详细介绍了如何注册并申请百度AK,只有拿到了AK,咱们在使用相关的API时才会有效,不然是不生效的话,因此你们必定要保证有AK而且是有效的哈。php

两种逆地址解析的方法

申请好了AK以后呢,这里有两种使用方法: 一种是直接经过url来进行请求,像是下边这种html

http://api.map.baidu.com/geocoder?location=39.910093,116.403945&output=json&key=你的百度AK
复制代码

这种方法使用的话,你们能够直接把这个url放到axios或者ajax里面,而后他的回调里面返回的就是咱们想要的地址等相关信息了。另外一种方法就是官网里面介绍的方法:java

// 初始化地图,这里的window可能须要从父组件传过来,原理还没弄清楚
  var map = new window.BMap.Map("allmap");
  // 建立地理编码实例
  var myGeo = new window.BMap.Geocoder();
  // 根据坐标获得地址描述
  myGeo.getLocation(new window.BMap.Point(116.404, 39.915), function(result){
    if (result){
      console.log('这就是解析以后的地址了',resule.address)
    }
  })
复制代码

注意:用第二种方法的话,咱们须要在index.html里面引用咱们上面的AK,以下ios

<script src="https://api.map.baidu.com/api?v=2.0&ak=你的百度AK&s=1"></script>
复制代码

上面的两种方法,均可以达到咱们获取地址信息的目的哈。我这里选用的是第二种方法,而后后面咱们批量请求的话,也是针对第二种方式来进行改装的。git

问题分析

刚开始个人思路是想着,既然这种方法只可以一条一条请求的话,那我就将经纬度构建成一个数组,经过循环调用的方法来给这个数组中的值赋值,代码以下ajax

gpsDatas.forEach((gpsItem)=>{
var map = new window.BMap.Map("allmap");
// 建立地理编码实例
var myGeo = new window.BMap.Geocoder();
// 根据坐标获得地址描述,将每一项的经纬度传入
myGeo.getLocation(new window.BMap.Point(gpsItem.longitude, gpsItem.latitude), function(result:any){
  if (result){
  // 将返回的值赋给该字段
    gpsItem.maybePosition = result.address
  }
})
})
// 返回咱们要输出的数据
console.log('gpsDatas',gpsDatas)
console.log('gpsDatas[0]',gpsDatas[0].maybePosition)
let a = gpsDatas[0].maybePosition

return gpsDatas
复制代码

若是你们执行到了这里的话,咱们就会发现一个很经典的问题,也是咱们常常可能会碰到的问题,就是咱们能够看到第一个打印出来的gpsDatas数组里面是可以看到咱们拿到了咱们想要的值,可是第二个打印咱们可能就会看到一个undefined了,那么有小伙伴就可能会产生这样一个疑惑了,为何我明明打印出来看有这个值,可是为何取不到值呢,这是由于在咱们取值的时候,myGeo.getLocation这个异步函数尚未执行完毕,因此取值的时候咱们是取不到这个值的,可是由于gpsDatas是一个引用数据类型,因此在异步函数执行完毕后,他会把数据填充到这个数组里面,由于引用地址没有改变,因此咱们能够看到数组中的地址已经有值了。json

能够这样理解,console输出数据的时候,他输出引用数据类型和基本数据类型是不一样的。输出引用类型的话,其实他是输出了一个指针,咱们看到的就是指向内存中的一片地址中的数据,因此尽管他是后边异步把数据放上来的,可是由于空间指向没有改变,因此输出的数据其实一直是在改变的,不过是console没有把这一步表现出来而已。axios

那么很显然,如今这种状况确定是不知足咱们的需求的,那么这里咱们就须要将咱们的方法就行改装一下了。api

最终解决方案

通过前面的分析,咱们可知,问题的产生是由于咱们是一个循环调用异步函数的问题,循环先走完了,可是异步没有走完,因此致使咱们取不出数据,那么你们其实很容易想到Promise,咱们能够利用Promise.all,将全部的异步操做一块儿执行,而后在.then里面获取返回结果。实现以下:

getMaybePositionByLaLo(window,positionDatas){
  // 定义一个Promise数组,来将异步操做放进来
  let apiDatas = []
  positionDatas.forEach((gpsItem)=>{
    let apiItem = this.getMapInfo(window,gpsItem)
    apiDatas.push(apiItem)
  })
  // 这里.all会将全部的异步操做一块儿放在队列中,等待全部异步执行完毕后才会执行.then,这就保证了咱们的同步获取数据
  return Promise.all(apiDatas)
    .then((gpsData)=>{
      return gpsData
    })
}
// 将单个获取地理位置的方法封装成一个方法
// 这里传入window的目的是,有些地方直接new BMap会报错,须要new window.BMap才能够
getMapInfo(window,gpsItem){
  return new Promise((resolve, reject)=>{
    var map = new window.BMap.Map("allmap");
    // 建立地理编码实例
    var myGeo = new window.BMap.Geocoder();
    // 根据坐标获得地址描述
    myGeo.getLocation(new window.BMap.Point(gpsItem.longitude, gpsItem.latitude), function(result){
      if (result){
        gpsItem.maybePosition = result.address;
        resolve(gpsItem)
      }
    })
  })
}
// 而后咱们就能够在页面直接调用了
this.getMaybePositionByLaLo(window,positionDatas)
.then((positionDatas)=>{
    // 这里就能够去进行咱们的取值赋值操做了
})
复制代码

以上咱们就完成了咱们的批量改装,其实核心就是对于Promise的应用,如何合理的运用Promise,对于咱们之后的开发有着很大的好处,我也是最近才开始发现Promise的好处,以前只是了解,也没有多的去使用,欢迎你们之后一块儿学习指正。

相关文章
相关标签/搜索