ajaxleafletgeoserverweb-feature-service

2nd AJAX call to same URL fails - but works randomly and rarely


I am trying to get a response from a web service, specifically to add two WFS layers from geoserver to a leaflet web map. The first layer gets added no problem every time, but most of the time, the second layer fails, complaining that the callback function is not defined:

ReferenceError: getJson is not defined

But what is very strange to me is that the second layer will be added, only sometimes. Refreshing the page and trying again will almost always fail.

This is the code making the ajax call:

$(document).ready(function() {

...

    $("#add-network-button").on("click", function() {setLocation("Moscow")}) 

    function setLocation(locationName) {

        var networkParameters = {
            service: 'WFS',
            version: '1.0.0',
            request: 'GetFeature',
            typeName: 'netex:' + locationData[locationName].networkWFSName,
            maxFeatures: 99999,
            outputFormat: 'text/javascript',
            format_options: 'callback: getJson'
        };

        addWebService(map, WFSURL, networkParameters)

        var buildingParameters = {
            service: 'WFS',
            version: '1.0.0',
            request: 'GetFeature',
            typeName: 'netex:' + locationData[locationName].buildingWFSName,
            maxFeatures: 99999,
            outputFormat: 'text/javascript',
            format_options: 'callback: getJson'
        };

        addWebService(map, WFSURL, buildingParameters)

    }

And here is the addWebService function:

var addWebService = function(map, WFSURL, WFSParameters) {

    var leafletWFSParameters = L.Util.extend(WFSParameters);

    console.log(WFSURL + L.Util.getParamString(leafletWFSParameters));

    $.ajax({
        url: WFSURL + L.Util.getParamString(leafletWFSParameters),
        dataType: 'jsonp',
        jsonpCallback: 'getJson',
        success: handleJson,
        cache: false
    });

    // TODO: add style
    function handleJson(data) {
        L.geoJson(data, {}).addTo(map);
    }
}

Solution

  • You're using jsonp, which means the data you're getting back is not JSON, but javascript code that makes a call to a globally-defined function (which name is defined by jsonpCallback).

    jQuery automagically creates a function with that name, performs the network request, and when that function runs, it destroys its own reference from the global scope.

    You're performing two calls to addWebService() in quick succession, which trigger two jQuery $.ajax({jsonpCallback: 'getJson'}) calls. The second call is overwriting the globally-defined getJson callback function. When the first jsonp payload is received by your browser, the globally-defined getJson callback is destroyed. When the second jsonp payload is received, it tries to call a globally-defined getJson function, and failing. A classic race condition.

    Let me quote jQuery's documentation for the jsonpCallback parameter on $.ajax(), empasis mine:

    jsonpCallback

    Type: String or Function()

    Specify the callback function name for a JSONP request. This value will be used instead of the random name automatically generated by jQuery. It is preferable to let jQuery generate a unique name as it'll make it easier to manage the requests and provide callbacks and error handling. You may want to specify the callback when you want to enable better browser caching of GET requests.

    I suggest you either use other transport format than JSONP, or use different callback names for each request.