如何使同步JSONP跨域调用(How to make synchronous JSONP cross

2019-06-24 20:56发布

我被困在同步跨域调用。

在我们吃域呼叫我的应用比较早,所以没有问题

为使呼叫我先前的JavaScript代码是如下:

function EKXMLProvider(oDropdown, sDefault, sXML, sFilterUrl, fireRequestOnce)
{
    var oXMLHTTP, i, length, oData, sValue, sDisplay, sName, sMatch, oRegExp;

    if (!oDropdown)
        return;

    // XMLHTTP Object to retrieve the xml document
    oXMLHTTP = this.createXMLHttpRequest();
    this.FilterUrl = sFilterUrl;
    if (sFilterUrl != previousFilterUrl){
        oXMLHTTP.open("GET", sFilterUrl, false);
        oXMLHTTP.send(null);
        sFilterData = oXMLHTTP.responseText
        previousFilterUrl = sFilterUrl;
    }
    if(!fireRequestOnce ||(fireRequestOnce && retrievedData == null))
    {
        this.documentUrl = sXML;
        oXMLHTTP.open("GET", this.documentUrl, false);
        oXMLHTTP.send(null);

        oData = oXMLHTTP.responseXML.documentElement.childNodes;

        if(fireRequestOnce)
            retrievedData = oData;
    }
    else if(retrievedData != null)
    {
        oData = retrievedData;
    }
    this.suggestData = new Array();

    // Filter out all 2 and 3 letter codes (airport, city, country)
    oRegExp = new RegExp("\\s+\\(\\w{2,3}\\)", "gi");
    var iCount = 0    
    for (i = 0, length = oData.length; i < length; i++)
    {
        sValue = oData[i].attributes.getNamedItem("v").value;
        sDisplay = oData[i].attributes.getNamedItem("d").value;
        sName = oData[i].attributes.getNamedItem("n").value;
        //sMatch = oData[i].attributes.getNamedItem("m").value;
        sMatch = oData[i].attributes.getNamedItem("e").value;

        if (sFilterData.search(sValue) != -1){
            this.suggestData[iCount] = new EKSuggestData(sName + " (" + sValue + ")", sDisplay, sValue, sMatch, sMatch.replace(oRegExp, ""));
            iCount++;
        }
    }

    // Call the inherited class
    EKSuggestProvider.call(this, oDropdown, sDefault);
}

现在,当我们搬到了我们对不同的域的呼叫,我们需要做跨域调用,我改变了上面如下跨域代码:

function EKXMLProvider(oDropdown, sDefault, sXML, sFilterUrl, fireRequestOnce)
{
    var oXMLHTTP, i, length, oData, sValue, sDisplay, sName, sMatch, oRegExp;
    var qr = "&jsonpcall=true";
    if (!oDropdown)
        return;

    // XMLHTTP Object to retrieve the xml document
    oXMLHTTP = this.createXMLHttpRequest();

    this.FilterUrl = sFilterUrl;

    if (sFilterUrl != previousFilterUrl){
    //alert(sFilterUrl);
        //oXMLHTTP.open("GET", sFilterUrl, false);
        //oXMLHTTP.send(null);
        //sFilterData = oXMLHTTP.responseText

        // queue up an ajax request
        $.ajax({
        url: sFilterUrl + qr,
        type: "GET",
        cache: true,
        async:false,
        contentType: "application/javascript; charset=utf-8",
        dataType: "jsonp",
        jsonpCallback: "airport", 
        success: function(data, textStatus, jqXHR) 
        {               
            if (data.airport[0] != '')
            {
                    sFilterData = data.airport[0];
            } 
        }
        });

        previousFilterUrl = sFilterUrl;        
    }

    if(!fireRequestOnce ||(fireRequestOnce && retrievedData == null))
    {
        //alert(sXML);
        this.documentUrl = sXML;
        //oXMLHTTP.open("GET", this.documentUrl, false);
        //oXMLHTTP.send(null);

        // queue up an ajax request
          $.ajax({
            url: sXML + qr,
            type: "GET",
            async:false,
            cache: true,
            contentType: "application/javascript; charset=utf-8",
            dataType: "jsonp",
            jsonpCallback: "airportxml", 
            success: function(data, textStatus, jqXHR) 
            {                 
                  var xmlDoc = $.parseXML(data.myresult);
                oData = xmlDoc.documentElement.childNodes; 
                alert(oData);
            }
            });

        //oData = oXMLHTTP.responseXML.documentElement.childNodes;

         if(fireRequestOnce)
             retrievedData = oData;
    }
    else if(retrievedData != null)
    {
        oData = retrievedData;
    }
    this.suggestData = new Array();

      // Filter out all 2 and 3 letter codes (airport, city, country)
      oRegExp = new RegExp("\\s+\\(\\w{2,3}\\)", "gi");
      var iCount = 0    
    for (i = 0, length = oData.length; i < length; i++)
    {
        sValue = oData[i].attributes.getNamedItem("v").value;
        sDisplay = oData[i].attributes.getNamedItem("d").value;
        sName = oData[i].attributes.getNamedItem("n").value;
        //sMatch = oData[i].attributes.getNamedItem("m").value;
        sMatch = oData[i].attributes.getNamedItem("e").value;

          if (sFilterData.search(sValue) != -1){
            this.suggestData[iCount] = new EKSuggestData(sName + " (" + sValue + ")", sDisplay, sValue, sMatch, sMatch.replace(oRegExp, ""));
            iCount++;
        }
    }

    // Call the inherited class
    EKSuggestProvider.call(this, oDropdown, sDefault);
}

上述jQuery的变化是工作正常,当我把“异步:假,”在我的电话,但是按我的知识,我们不能有同步调用的跨域,如果我更改为“异步:真”的号召,开始给错误就行了( for (i = 0, length = oData.length; i < length; i++))作为ODATA需要装上第二个“airportxml”,它似乎两个呼叫都依赖于彼此,所以每当第一呼叫发送同时也适用于下一个电话也。

我用ajaxQueue这个还可以,但没有运气。

请建议我需要做什么样的变化。

Answer 1:

正如zi42解释,并通过jQuery.ajax()文档 ,“跨域请求和dataType: "jsonp"请求不支持同步操作”。

这不是一件坏事,因为同步调用往往会导致糟糕的用户体验,因为它直到响应回来锁定了浏览器,所以我会避开使得即使有标准的AJAX同步调用它在哪里的容易实现。 你想在连续两个同步调用,这样会更糟。

在评论zi42建议的解决方法 - 做一个同步Ajax调用自己的域名,然后让从服务器跨域调用 - 就是如果你真的希望它是同步的,你可以采取的最好的办法。

另一个显而易见的方法是调整你的代码,以便它会异步工作,通过把希望每个JSONP要求转化到成功回调后做的东西。 也就是说,第一JSONP请求你继续做第二JSONP请求的成功回调中。 在第二的成功回调,你会做任何最终处理。 如果您需要通过最终的结果你的代码的另一部分则摆在那需要一个回调函数作为参数的函数Ajax代码:

function doMyAjaxCalls(callbackFunc) {
   // make first request
   $.ajax({
      ...
      dataType: "jsonp",
      success: function(data, textStatus, jqXHR) {
         // do something with first response, then
         // make second request              
         $.ajax({
            ...
            dataType: "jsonp",
            success: function(data, textStatus, jqXHR) {
               // do something with second response, then
               // do final processing, then
               callbackFunc(dataHere);
            }
         });
      }
   });
}

doMyAjaxCalls(function(response) {
   // do something with response
});


Answer 2:

当您使用JSONP,请求不是直通XHR完成,但通过添加一个实际<script>标记添加到DOM。 这就是为什么你不能让它同步。 这是根本不可能的。



Answer 3:

另一种选择是,以阻止用户界面(未阻塞的执行)。

使用类似BlockUI是将“灰”屏幕,直到您的通话结束。



文章来源: How to make synchronous JSONP crossdomain call