涉及 OpenLayers 和 Geoserver 的 Javascript fetch post 问题

Issue with Javascript fetch post involving OpenLayers and Geoserver

我有一个 MVC 项目,它使用 OpenLayers 进行映射,使用 Geoserver 进行图层存储。大多数图层都是通过 WMTS 加载的。我有一个图层作为矢量加载,因此我可以访问它的各个功能,但在单击时加载,因为图层的大小需要很长时间才能加载,因此只有某些功能加载到 click/draw,具体取决于单击位置或多边形点。

我有事件在 click/draw 结束时执行某些事情。我的相关代码摘要如下:

var global = new Array();

selectInteraction.on('drawend', function (e) {

    vectorSource.clear();
    map.removeLayer(vector);
    var point = e.feature.getGeometry();
    global = new Array();

    loadFeatures(point);

    var feat = global[0];

    drawVectorSource.clear();
    vectorSource.clear();

});

function loadFeatures(intersect) { // intersect is a polygon/point

    vectorSource.clear();

    featureRequest = new ol.format.WFS().writeGetFeature({
        srsName: 'EPSG:3857',
        featureNS: ** url **,
        featurePrefix: ** prefix **,
        featureTypes: ['feature1'],
        outputFormat: 'application/json',
        maxFeatures: 1000,
        filter: ol.format.filter.and(
            ol.format.filter.equalTo('feat_type', 'feature1'),
            ol.format.filter.intersects('geom', intersect, 'EPSG:3857')
        )
    });

    fetch(geoserverUrl, {
        method: 'POST',
        body: new XMLSerializer().serializeToString(featureRequest)
    }).then(function (response) {
        return response.json();
    }).then(function (json) {
        var features = new ol.format.GeoJSON().readFeatures(json);
        vectorSource.addFeatures(features);
        global = new Array();
        features.map(function (feature) {
            global.push(feature.get('text'));
            // In the case of a single point it will only have 1 feature
        });
        map.addLayer(vector);
    });
}

我遇到的问题是 loadFeatures() 函数和名为 global 的数组的 setting/accessing。我在上面的代码中设置了各种断点,结果让我目瞪口呆。我不确定问题出在 Geoserver 获取的 return 还是 javascript 代码本身。

当程序进入 loadFeatures() 函数时,它会进入 fetch 调用的第一部分,但是 returns 和未定义的响应从 featureRequest post 到 URL.然后它继续执行 promises 和函数,将 global 保留为仍然是一个空数组。出于明显的原因,这在尝试设置 var feat = global[0] 时会失败。

如果仅此而已,我认为问题出在地理服务器获取上。但这还不是全部。如果我在 .then(function (json) { ... }.then(function (response) { .. . }) 在函数调用之后让程序继续 运行 ,并且正确的特征 已成功添加到矢量源并显示在地图上 但直到所有其他代码都已执行后才会显示。此外,内部没有其他断点除了两次 .then() 调用中的函数外,该函数在明显的第二次传递期间被命中。

这让我假设 fetch 只是需要一段时间才能给出响应。问题是我对这个假设有点不适应。我尽力使 loadFeatures() 函数与 promises 异步,甚至在函数调用后抛出一个 while 循环,以便在继续之前给函数时间完成,但它所做的只是打破我的 chrome 并继续无休止。

任何人都可以帮助阐明它实际上在做什么吗?我无法确定这是我的操作方式有问题 javascript 还是与地理服务器通信的错误。

Hank,您所描述的这类问题确实有点像某些异步代码没有按预期执行。我有一些可能有用的建议。

不幸的是,我从未使用过 OpenLayers,只有 Esri 的 ArcGIS API 用于 JavaScript,所以我不完全理解代码的作用。

首先,我会在您的 Promise 链的末尾添加一个 .catch() 。听起来您并没有收到异常,但这是一个很好的做法。

其次,我会将 loadFeatures 代码包装在 Promise 中。这样,调用 loadFeatures 的 drawend 事件处理程序可以在 loadFeatures 完成其工作和 returns 之后等待访问名为 global 的数组。我会添加一个 getFeatures 函数,它 return 是一个 Promise 和特性,只是为了坚持单一职责原则。

另一个我不太清楚的项目是几个全局变量的使用,我没有看到它们的声明。我还看到您已多次为 global 调用 new Array() ,但我不明白为什么有必要这样做。您可能会新建一次,然后在再次填充之前清除它。我不确定我是否遵循了您对 global 所做的操作,并相信您可以调试该变量值。

Promises 的关键是 return 链接时来自所有函数的 Promise。因此,请检查所有 Promise 是否已解决或已拒绝。否则,他们将永远闲逛。

另外,drawend 会被多次调用吗?也许在再次调用之前没有完成提取功能?

下面的代码只是重构,可能会帮助您找到问题所在。我没有测试代码,并且缺少全局变量声明,这是我试图通过一些清理来保持您的逻辑。通过查看 OpenLayers 上的几个示例,您似乎创建了一个新的 Vector,向 Vector 对象添加特征,然后将其作为图层添加到地图。

var globalArray = [];
var vectorSource = new ol.source.Vector();
var vector = new ol.layer.Vector({
   source: vectorSource,
   style: new ol.style.Style({
       stroke: new ol.style.Stroke({
           color: 'rgba(0, 0, 255, 1.0)',
           width: 2
       })
   })
});

selectInteraction.on('drawend', function (e) {
    var point = e.feature.getGeometry();

    // Remove all features from the source.
    vectorSource.clear();
    // Remove the layer from the map
    map.removeLayer(vector);      

    loadFeatures(point).then(function(results) {
        // clear the globalArray property
        globalArray.length = 0;
        // fill globalArray with the results from loadFeatures
        globalArray = results;

        // Do other stuff...
        var feat;
        if (global) {
            feat = global[0];
        }
        drawVectorSource.clear();
        vectorSource.clear();
    }).catch(error) {
          // perhaps clear arrays or other cleanup when an error occurs 
    });

});

function loadFeatures(intersect) { // intersect is a polygon/point
    return new Promise(function (resolve, reject) {    
       getFeatures(intersect).then(function (features) {
           vectorSource.addFeatures(features);
           var featureTextArray = [];
           features.map(function (feature) {
               featureTextArray.push(feature.get('text'));
               // In the case of a single point it will only have 1 feature
           });
           map.addLayer(vector);
           return resolve(featureTextArray);
       }).catch(error) {
            // reject the Promise returning the error
            reject(error);
       });  
    })
}

function getFeatures(intersect) {
    return new Promise(function (resolve, reject) {
        var featureRequest = new ol.format.WFS().writeGetFeature({
            srsName: 'EPSG:3857',
            featureNS: ** url **,
            featurePrefix: ** prefix **,
            featureTypes: ['feature1'],
            outputFormat: 'application/json',
            maxFeatures: 1000,
            filter: ol.format.filter.and(
                ol.format.filter.equalTo('feat_type', 'feature1'),
                ol.format.filter.intersects('geom', intersect, 'EPSG:3857')
            )
        });

        fetch(geoserverUrl, {
            method: 'POST',
            body: new XMLSerializer().serializeToString(featureRequest)
        }).then(function (response) {
            // return JSON in a Promise
            return response.json();
        }).then(function (json) {
            var features = new ol.format.GeoJSON().readFeatures(json);
            // resolve the Promise and return the features
            return resolve(features);
        }).catch(error) {
            // log it and reject the Promise returning the error
            reject(error);
        });    
    });
}

在 Promises 的两个回调函数中添加一个断点。因此,这将是对 getFeatures() 的调用和设置变量 featureRequest 的代码行。看看它是否仍然被调用两次。祝你好运!