You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中如何从XMLHttpRequest异步请求提取Leaflet GeoJSON图层变量并转为JSON复用?

Hey there! Let's break down your problem step by step—this is super common when you're getting started with async code, so don't worry, we'll get it sorted.

First, let's nail down the core issue: your XMLHttpRequest runs asynchronously, meaning the code doesn't wait for the server to send back data before moving on. When you try to use the arrond variable outside the onreadystatechange callback, it hasn't even been created yet! The callback only executes after the server responds, but your layer control code runs immediately after calling xhttp2.send().

1. Fix the Async Variable Scope Issue

Here are two practical solutions to reuse the arrond layer outside the callback:

Option A: Move Dependent Logic Into the Callback

The simplest fix is to put all code that needs arrond directly inside the callback, so it only runs after the layer is created:

// 地图初始化
var map1 = L.map('map1');
var osmUrl='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
var osmAttrib='Map data © OpenStreetMap contributors';
var osm = new L.TileLayer(osmUrl, {attribution: osmAttrib});
map1.setView([45.76, 4.85], 12);

// 添加额外底图
var osmhumanUrl='https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png';
var osmhuman = new L.TileLayer(osmhumanUrl, {attribution: osmAttrib}).addTo(map1);
var Esri_WorldImagery = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
 attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
});

// 预定义底图分组
var baseMaps = { "OSM": osm, "OSM Humanitarian": osmhuman, "Satellite": Esri_WorldImagery };
var Jardins = L.geoJSON(jardins, {
 onEachFeature: function (feature, layer) {
 layer.bindPopup(feature.properties.title);
 }
}).addTo(map1);

// 调用设备图层
var xhttp2 = new XMLHttpRequest();
xhttp2.onreadystatechange = function() {
 if (this.readyState == 4 && this.status ==200) {
  try {
    // 解析响应为JSON(添加try-catch防止解析错误)
    let response = JSON.parse(xhttp2.responseText);
    document.getElementById("demo").innerHTML = JSON.stringify(response, null, 2); // 格式化展示数据

    // 创建GeoJSON图层
    let arrond = L.geoJSON(response).addTo(map1);

    // --- 把依赖arrond的代码移到这里 ---
    // 更新 overlayMaps 并添加图层控制
    var overlayMaps = { 
      "Initiatives existantes": Jardins,
      "PostgreSQL Data Layer": arrond // 给你的图层起个自定义名称
    };
    L.control.layers(baseMaps, overlayMaps).addTo(map1);

    // 将Leaflet图层转为JSON格式(满足你的需求)
    let arrondJson = arrond.toGeoJSON();
    console.log("GeoJSON as JSON object:", arrondJson);
    // 如果需要JSON字符串:JSON.stringify(arrondJson)
  } catch (err) {
    console.error("Error processing data:", err);
    document.getElementById("demo").innerHTML = "Failed to load data: " + err.message;
  }
 }
};
xhttp2.open("GET", "js/test3.php",true);
xhttp2.send();

Option B: Use Promises + Async/Await (Modern Approach)

If you prefer cleaner, more readable code that behaves like synchronous logic, wrap the XMLHttpRequest in a Promise and use async/await:

// 地图初始化(和之前一样)
var map1 = L.map('map1');
var osmUrl='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
var osmAttrib='Map data © OpenStreetMap contributors';
var osm = new L.TileLayer(osmUrl, {attribution: osmAttrib});
map1.setView([45.76, 4.85], 12);

var osmhumanUrl='https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png';
var osmhuman = new L.TileLayer(osmhumanUrl, {attribution: osmAttrib}).addTo(map1);
var Esri_WorldImagery = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
 attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
});

var baseMaps = { "OSM": osm, "OSM Humanitarian": osmhuman, "Satellite": Esri_WorldImagery };
var Jardins = L.geoJSON(jardins, {
 onEachFeature: function (feature, layer) {
 layer.bindPopup(feature.properties.title);
 }
}).addTo(map1);

// 封装请求为Promise函数
function fetchGeoJSON(url) {
  return new Promise((resolve, reject) => {
    const xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
      if (this.readyState === 4) {
        if (this.status === 200) {
          try {
            const data = JSON.parse(this.responseText);
            resolve(data);
          } catch (err) {
            reject(new Error("Failed to parse JSON: " + err.message));
          }
        } else {
          reject(new Error("Request failed with status: " + this.status));
        }
      }
    };
    xhttp.open("GET", url, true);
    xhttp.send();
  });
}

// 用async函数处理请求
async function loadMapLayers() {
  try {
    // 等待请求完成,获取GeoJSON数据
    const response = await fetchGeoJSON("js/test3.php");
    document.getElementById("demo").innerHTML = JSON.stringify(response, null, 2);

    // 创建图层
    let arrond = L.geoJSON(response).addTo(map1);

    // 现在你可以在这个函数内任意复用arrond
    var overlayMaps = { 
      "Initiatives existantes": Jardins,
      "PostgreSQL Data Layer": arrond
    };
    L.control.layers(baseMaps, overlayMaps).addTo(map1);

    // 转为JSON格式
    let arrondJson = arrond.toGeoJSON();
    console.log(arrondJson);
  } catch (err) {
    console.error("Error loading data:", err);
    document.getElementById("demo").innerHTML = err.message;
  }
}

// 执行async函数
loadMapLayers();

2. Converting Leaflet GeoJSON Layer to JSON

To turn the arrond Leaflet layer into a JSON object, use Leaflet's built-in toGeoJSON() method. This returns a standard GeoJSON JavaScript object. If you need a JSON string, wrap it in JSON.stringify(arrond.toGeoJSON()).

内容的提问来源于stack exchange,提问作者Veko047

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 08:27:43