web-dev-qa-db-ja.com

非同期のAjaxリクエストではなく同期のAjaxリクエストをjQueryに実行させるにはどうすればよいですか。

標準の拡張ポイントを提供するJavaScriptウィジェットがあります。そのうちの一つがbeforecreate関数です。アイテムが作成されないようにするためにfalseを返すべきです。

JQueryを使ってこの関数にAjax呼び出しを追加しました。

beforecreate: function (node, targetNode, type, to) {
  jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),

  function (result) {
    if (result.isOk == false) 
        alert(result.message);
  });
}

しかし、私は自分のウィジェットがその項目を作成しないようにしたいので、コールバックではなくmother-functionにfalseを返さなければなりません。 jQueryまたは他のブラウザ内APIを使用して同期AJAX要求を実行する方法はありますか?

1139

jQueryのドキュメントから :同期Ajaxリクエストを取得するには、 Asynchronous オプションを false に指定します。そうすれば、あなたのコールバックはあなたのmother関数が進む前にデータを設定することができます。

提案されたように変更された場合、コードは次のようになります。

beforecreate: function (node, targetNode, type, to) {
    jQuery.ajax({
        url: 'http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),
        success: function (result) {
            if (result.isOk == false) alert(result.message);
        },
        async: false
    });
}
1103
Adam Bellaire

次のようにしてjQueryのAjax設定を同期モードにすることができます。

jQuery.ajaxSetup({async:false});

そしてjQuery.get( ... );を使ってAjax呼び出しを実行します。

それからちょうどそれをもう一度回しなさい

jQuery.ajaxSetup({async:true});

@Adamで提案されているのと同じことがうまくいくと思いますが、jQuery.get()jQuery.post()をもっと複雑なjQuery.ajax()構文に再設定したい人には役に立つかもしれません。

245
Sydwell

優れた解決策!それを実装しようとしたときに気付いたのですが、success句に値を返すと、未定義の値が返されることになります。変数に格納してその変数を返す必要がありました。これが私が思いついた方法です。

function getWhatever() {
  // strUrl is whatever URL you need to call
  var strUrl = "", strReturn = "";

  jQuery.ajax({
    url: strUrl,
    success: function(html) {
      strReturn = html;
    },
    async:false
  });

  return strReturn;
}
133
James in Indy

これらの答えはすべて、async:falseを指定してAjax呼び出しを行うと、Ajax要求が完了するまでブラウザーがハングするという点を見逃しています。フロー制御ライブラリを使用すると、ブラウザを停止せずにこの問題を解決できます。これは Frame.js の例です。

beforecreate: function(node,targetNode,type,to) {

    Frame(function(next)){

        jQuery.get('http://example.com/catalog/create/', next);
    });

    Frame(function(next, response)){

        alert(response);
        next();
    });

    Frame.init();
}
83
BishopZ
function getURL(url){
    return $.ajax({
        type: "GET",
        url: url,
        cache: false,
        async: false
    }).responseText;
}


//example use
var msg=getURL("message.php");
alert(msg);
49
Carcione

クロスドメインのAjax呼び出しを( _ jsonp _ を使用して)行っている場合 - you 同期できない は、jQueryではasyncフラグを無視します。

$.ajax({
    url: "testserver.php",
    dataType: 'jsonp', // jsonp
    async: false //IGNORED!!
});

JSONP呼び出しの場合は、次のものを使用できます。

  1. 自分のドメインへのAjax呼び出し - そしてクロスドメイン呼び出しをサーバーサイドで行う
  2. コードが非同期に動作するように変更する
  3. Frame.jsのような "function sequencer"ライブラリを使う(this answer
  4. 実行をブロックする代わりにUIをブロックします(this answer )(私の好きな方法)
24
Serge Shultz

注:この警告メッセージが表示されるため、async: falseを使用しないでください。

Gecko 30.0(Firefox 30.0/Thunderbird 30.0/SeaMonkey 2.27)以降では、メインスレッド上の同期リクエストはユーザーエクスペリエンスに悪影響を与えるため非推奨になりました。

Chromeはコンソールでこれについて警告します:

メインスレッド上の同期XMLHttpRequestは、エンドユーザーのエクスペリエンスに悪影響を与えるため、推奨されません。詳細については、 https://xhr.spec.whatwg.org/ /を確認してください。

このようなことをしていると、これはあなたのページを壊す可能性があります。

まだ同期しているのにまだブロックしていないような感じでやりたいのなら、async/awaitとおそらく新しい Fetch APIのような約束に基づくajaxを使うべきです。

async function foo() {
  var res = await fetch(url)
  console.log(res.ok)
  var json = await res.json()
  console.log(json)
}

編集 chromeは/に取り組んでいます ページを閉じるときに同期XHRを許可しない ユーザーがページを移動したり閉じたりしているとき。これには、アンロード前、アンロード、ページ非表示、および可視性の変更が含まれます。

これがあなたのユースケースであるならば、あなたは navigator.sendBeacon を見たいと思うかもしれません

Httpヘッダーまたはiframeのallow属性のいずれかを使用して同期要求を無効にすることも可能です。

23
Endless

私はCarcioneから与えられた答えを使い、JSONを使うように修正しました。

 function getUrlJsonSync(url){

    var jqxhr = $.ajax({
        type: "GET",
        url: url,
        dataType: 'json',
        cache: false,
        async: false
    });

    // 'async' has to be 'false' for this to work
    var response = {valid: jqxhr.statusText,  data: jqxhr.responseJSON};

    return response;
}    

function testGetUrlJsonSync()
{
    var reply = getUrlJsonSync("myurl");

    if (reply.valid == 'OK')
    {
        console.dir(reply.data);
    }
    else
    {
        alert('not valid');
    }    
}

dataType / 'JSON' を追加し、 .responseText responseJSON に変更しました。

返されたオブジェクトの statusText プロパティを使用してステータスも取得しました。これはAjaxレスポンスのステータスであり、JSONが有効かどうかではありません。

バックエンドは正しい(整形式の)JSONで応答を返さなければなりません。そうでなければ返されるオブジェクトは未定義になります。

元の質問に答えるときに考慮する2つの側面があります。 1つはAjaxに( async:false を設定して)同期的に実行するように指示し、もう1つはコールバック関数ではなく呼び出し側関数のreturnステートメントを介して応答を返します。

私はPOSTでも試してみましたが、うまくいきました。

GETをPOSTに変更し、 data:postdata を追加しました

function postUrlJsonSync(url, postdata){

    var jqxhr = $.ajax({
        type: "POST",
        url: url,
        data: postdata,
        dataType: 'json',
        cache: false,
        async: false
    });

    // 'async' has to be 'false' for this to work
    var response = {valid: jqxhr.statusText,  data: jqxhr.responseJSON};

    return response;
}

上記のコードは async false の場合にのみ機能することに注意してください。 async:true /返されるオブジェクト jqxhr は、AJAX呼び出しが戻った時点では有効ではありませんが、あとで非同期呼び出しが終了したときに限ります。 response 変数を設定するには遅すぎます。

11
paulo62

async: falseを使えば、ブロックされたブラウザになります。ノンブロッキング同期ソリューションの場合は、次のものを使用できます。

ES6/ECMAScript2015

ES6ではジェネレータと coライブラリ を使うことができます。

beforecreate: function (node, targetNode, type, to) {
    co(function*(){  
        let result = yield jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));
        //Just use the result here
    });
}

ES7

ES7では、asycを使うことができます。

beforecreate: function (node, targetNode, type, to) {
    (async function(){
        let result = await jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));
        //Just use the result here
    })(); 
}
11
Spen

これは例です。

$.ajax({
  url: "test.html",
  async: false
}).done(function(data) {
   // Todo something..
}).fail(function(xhr)  {
   // Todo something..
});
6
searching9x

まず$ .ajaxを使うときと$ .get/$を使うときを理解する必要があります

リクエストヘッダの設定、キャッシュ設定、同期設定など、Ajaxリクエストを低レベルで制御する必要がある場合は、$。ajaxを使用してください。

$ .get/$。post:ajaxリクエストを低レベルで制御する必要がない場合。単純にデータをサーバーに取得/投稿します。の省略形です

$.ajax({
  url: url,
  data: data,
  success: success,
  dataType: dataType
});

したがって、他の機能(同期、キャッシュなど)を$ .get/$。postで使用することはできません。

したがって、Ajaxリクエストに対する低レベルの制御(同期、キャッシュなど)の場合は、$。ajaxを使用する必要があります

 $.ajax({
     type: 'GET',
      url: url,
      data: data,
      success: success,
      dataType: dataType,
      async:false
    });
3

XMLHttpReponse同期操作は推奨されないため、XMLHttpRequestをラップする次のような解決策を思いつきました。これにより、本質的に非同期でありながら、AJAXクエリを順番に並べることができます。これは使い捨てのCSRFトークンには非常に便利です。

また、透過的なので、jQueryなどのライブラリはシームレスに動作します。

/* wrap XMLHttpRequest for synchronous operation */
var XHRQueue = [];
var _XMLHttpRequest = XMLHttpRequest;
XMLHttpRequest = function()
{
  var xhr   = new _XMLHttpRequest();
  var _send = xhr.send;

  xhr.send = function()
  {
    /* queue the request, and if it's the first, process it */
    XHRQueue.Push([this, arguments]);
    if (XHRQueue.length == 1)
      this.processQueue();
  };

  xhr.processQueue = function()
  {
    var call = XHRQueue[0];
    var xhr  = call[0];
    var args = call[1];

    /* you could also set a CSRF token header here */

    /* send the request */
    _send.apply(xhr, args);
  };

  xhr.addEventListener('load', function(e)
  {
    /* you could also retrieve a CSRF token header here */

    /* remove the completed request and if there is more, trigger the next */
    XHRQueue.shift();
    if (XHRQueue.length)
      this.processQueue();
  });

  return xhr;
};
1
Geoffrey

これはjQueryを使ったASYNCリクエストのための私の簡単な実装です。これが誰にでも役立つことを願っています。

var queueUrlsForRemove = [
    'http://dev-myurl.com/image/1', 
    'http://dev-myurl.com/image/2',
    'http://dev-myurl.com/image/3',
];

var queueImagesDelete = function(){

    deleteImage( queueUrlsForRemove.splice(0,1), function(){
        if (queueUrlsForRemove.length > 0) {
            queueImagesDelete();
        }
    });

}

var deleteImage = function(url, callback) {
    $.ajax({
        url: url,
        method: 'DELETE'
    }).done(function(response){
        typeof(callback) == 'function' ? callback(response) : null;
    });
}

queueImagesDelete();
1
Felipe Marques

これは私の“ Thread ”名前空間です。

var Thread = {
    sleep: function(ms) {
        var start = Date.now();

        while (true) {
            var clock = (Date.now() - start);
            if (clock >= ms) break;
        }

    }
};

そしてこれが私の呼称です。

var d1 = new Date();
console.log('start ' + d1.toLocaleTimeString());
Thread.sleep(10000);
var d2 = new Date();
console.log('end ' + d2.toLocaleTimeString());

コンソールを見ると、次のようになります。

start 1:41:21 PM
end 1:41:31 PM
1
Tell Me How