4

同期クロスドメイン呼び出しでスタックしました。

私のアプリケーションの初期にはドメイン呼び出しがあったので、問題はありませんでした

呼び出しを行うための以前の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の変更は、呼び出しに「async:false」を入れると正常に機能しますが、私の知る限り、クロスドメインで同期呼び出しを行うことはできません。「async:true」に変更すると、呼び出しでエラーが発生し始めます。 Odata( for (i = 0, length = oData.length; i < length; i++))は2番目の「airportxml」に入力する必要があり、両方の呼び出しが相互に依存しているように見えるため、最初の呼び出しが送信されるたびに、同時に次の呼び出しにも進みます。

これにもajaxQueueを使用しましたが、運がありません。

どのような変更を行う必要があるかを提案してください。

4

4 に答える 4

6

zi42とjQuery.ajax()ドキュメントで説明されているように、「クロスドメインリクエストとdataType: "jsonp"リクエストは同期操作をサポートしていません。」

同期呼び出しは、応答が返されるまでブラウザーをロックするため、ユーザーエクスペリエンスが低下する傾向があることを考えると、これは悪いことではありません。したがって、標準のAjaxを使用している場合でも、同期呼び出しを行うことは避けたいと思います。実装が簡単です。さらに悪いことに、2つの同期呼び出しを続けて行う必要があります。

コメントで提案されている回避策zi42(独自のドメインに対して同期Ajax呼び出しを行い、次にサーバーからクロスドメイン呼び出しを行う)は、本当に同期させたい場合に採用できる最善のアプローチです。

もう1つの明らかなアプローチは、各jsonpリクエストの後に実行したいことを成功コールバックに入れることで、非同期で機能するようにコードを再構築することです。つまり、最初のjsonpリクエストの成功コールバック内で、2番目のjsonpリクエストを作成します。2番目の成功コールバック内で、最終処理を行います。最終結果をコードの別の部分に渡す必要がある場合は、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
});
于 2012-05-28T23:48:58.020 に答える
3

JSONPを使用する場合、リクエストはXHRを介してではなく、実際の<script>タグをDOMに追加することによって行われます。そのため、同期させることはできません。それは単に不可能です。

于 2012-05-28T07:23:55.900 に答える
0

もう1つのオプションは、UIをブロックすることです(実行をブロックしないでください)。

通話が終了するまで画面を「灰色」にするBlockUIのようなものを使用します。

于 2015-05-10T07:26:10.693 に答える
0

私は新しいJQueryとAjaxです。私が同様の問題に遭遇したとき、私のために働いた1つのオプションは、データ型をJSONPからtextおよびasync:falseに変換することです。これで、それに応じてテキスト内の応答を解析する必要があります。

$.ajax({
        url: url,
        timeout: 600000,
        dataType: "text",
        async:false,
        success: function (data) {
            console.log(data);
        },
        error: function (xhr, textStatus, errorThrown) {
            console.log('failed to download);
            console.log("error: " + errorThrown);
        }
于 2019-07-23T14:01:17.097 に答える