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的好處,以前只是瞭解,也沒有多的去使用,歡迎你們之後一塊兒學習指正。

相關文章
相關標籤/搜索