Làm cách nào tôi có thể khiến jQuery thực hiện một yêu cầu Ajax đồng bộ, thay vì không đồng bộ?


1208

Tôi có một tiện ích JavaScript cung cấp các điểm mở rộng tiêu chuẩn. Một trong số đó là beforecreatechức năng. Nó sẽ trở lại falseđể ngăn chặn một mục được tạo ra.

Tôi đã thêm một lệnh gọi Ajax vào hàm này bằng jQuery:

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);
  });
}

Nhưng tôi muốn ngăn widget của tôi tạo mục, vì vậy tôi nên quay lại falsetrong chức năng mẹ, không phải trong hàm gọi lại. Có cách nào để thực hiện yêu cầu AJAX đồng bộ bằng jQuery hoặc bất kỳ API trong trình duyệt nào khác không?


30
Cách thích hợp để giải quyết đó là viết lại lời hứa sử dụng điểm mở rộng của tiện ích. Cách này sẽ dễ dàng cho phép bạn thiết lập một hành động không đồng bộ (như yêu cầu ajax) như beforecreate.
Kos

3
Tôi đề xuất chức năng Sajak. Chúng ta có một chữ T? Có vanna, cho tôi 3 T.
Cody O'Dell

2
@Kos là tại chỗ. Đồng bộ hóa XHR không bắt buộc ở đây
Michael Westcott

1
Nếu mọi người hỏi tôi một lời khuyên khi bắt đầu javascript, tôi nói: hãy nắm lấy đặc tính không đồng bộ của javascript, đừng thử ty chống lại điều đó.
Trì hoãn Emmanuel

3
Câu hỏi này giống như hỏi "làm cách nào để lưu trữ mật khẩu người dùng của tôi trong văn bản thuần túy?" Chắc chắn có một câu trả lời, nhưng đừng làm điều đó.
Vectorjohn

Câu trả lời:


1165

Từ tài liệu jQuery : bạn chỉ định tùy chọn không đồng bộsai để nhận yêu cầu Ajax đồng bộ. Sau đó, cuộc gọi lại của bạn có thể thiết lập một số dữ liệu trước khi chức năng mẹ của bạn tiến hành.

Đây là mã của bạn sẽ trông như thế nào nếu được thay đổi như được đề xuất:

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
    });
}

97
Chính xác, không thể sử dụng get (), post (), load () cho các cuộc gọi đồng bộ. Chỉ ajax () có tham số "async", có thể được đặt thành "false".
SLA80

39
@ SLA80 Không. Kể từ jQuery 1.1: stackoverflow.com/questions/6849686/
Kẻ

16
@qualidafial bình luận của tôi nhắm vào bình luận không chính xác của SLA80; có thể sử dụng get (), post (), load () cho các cuộc gọi đồng bộ.
StuperUser

9
async false không còn được hỗ trợ cho jQuery> = 1.8. Tham khảo api.jquery.com/jQuery.ajax
ken

22
@ken async: falsevẫn được hỗ trợ trong jQuery> = 1.8. Khả năng sử dụng async: falsevới jqXHR ( $.Deferred) là những gì không được chấp nhận. Nói cách khác, người ta phải sử dụng các tùy chọn gọi lại thành công / lỗi / hoàn thành mới hơn, thay vì các phương thức cũ, ví dụ : jqXHR.done().
Ben Johnson

255

Bạn có thể đặt thiết lập Ajax của jQuery ở chế độ đồng bộ bằng cách gọi

jQuery.ajaxSetup({async:false});

Và sau đó thực hiện các cuộc gọi Ajax của bạn bằng cách sử dụng jQuery.get( ... );

Sau đó chỉ cần bật lại một lần nữa

jQuery.ajaxSetup({async:true});

Tôi đoán nó hoạt động tương tự như được đề xuất bởi @Adam, nhưng nó có thể hữu ích cho ai đó muốn cấu hình lại jQuery.get()hoặc jQuery.post()theo jQuery.ajax()cú pháp phức tạp hơn .


56
Đây là một ý tưởng thực sự tồi tệ, tại sao bạn lại đặt nó ở cấp độ toàn cầu? Và sau đó bị buộc phải hủy đặt nó sau?
Juan Mendes

11
Ít nhất, đây là ý tưởng tồi tốt nhất. thay vì nói: "KHÔNG CÓ CÁCH NGOẠI TRỪ $.ajax()". ;)
Rzassar

136

Giải pháp tuyệt vời! Tôi nhận thấy khi tôi cố gắng thực hiện nó rằng nếu tôi trả về một giá trị trong mệnh đề thành công, nó sẽ trở lại là không xác định. Tôi đã phải lưu nó trong một biến và trả về biến đó. Đây là phương pháp tôi nghĩ ra:

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;
}

16
Đó là bởi vì bạn đã trả lại một giá trị từ cuộc gọi lại, không phải ra khỏi getWhatever. Vì vậy, bạn trả lại không có nghĩa là undefinedtừ của bạn getWhatever.
Các cuộc đua nhẹ nhàng trong quỹ đạo

6
Điều này là hoàn toàn sai. Bạn không thể chắc chắn rằng một cuộc gọi không đồng bộ đã kết thúc khi trả về 'strReturn'.
Thomas Fritz

61
Đây là một cuộc gọi đồng bộ (async: false).
James ở Indy

85

Tất cả các câu trả lời này đều bỏ lỡ điểm thực hiện cuộc gọi Ajax với async: false sẽ khiến trình duyệt bị treo cho đến khi yêu cầu Ajax hoàn thành. Sử dụng thư viện kiểm soát luồng sẽ giải quyết vấn đề này mà không cần treo trình duyệt. Dưới đây là một ví dụ với 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();
}

4
Các cuộc gọi đồng bộ rất tiện dụng nếu bạn muốn kết hợp khai thác thử nghiệm nhanh cho back-end REST và muốn đơn giản hơn địa ngục gọi lại.
Distortum

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


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

10
Tuy nhiên, xin lưu ý rằng bạn có thể nhận được điều này: 'XMLHttpRequest trên luồng chính bị phản đối vì những tác động bất lợi của nó đối với trải nghiệm của người dùng cuối.'
Hari

5
@Hari Cách để thực hiện cuộc gọi ajax đồng bộ bằng jQuery mà không sử dụng luồng chính là gì?
Jose Nobile

7
Tôi không thấy rằng câu trả lời này có bất cứ điều gì để cung cấp, đó chỉ là câu trả lời được chấp nhận được gói vào một chức năng và trả lời bốn năm sau đó. Thật là một điều tồi tệ khi khuyên mọi người về C + P, bởi vì chức năng này không cho biết nó làm gì. "Vậy getURLvs get? Tại sao một người treo trình duyệt của tôi?" vv
moopet

27

Lưu ý: Bạn không nên sử dụng async: falsedo các thông báo cảnh báo này:

Bắt đầu với Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), các yêu cầu đồng bộ trên luồng chính đã không được chấp nhận do ảnh hưởng tiêu cực đến trải nghiệm người dùng.

Chrome thậm chí còn cảnh báo về điều này trong bảng điều khiển:

XMLHttpRequest đồng bộ trên luồng chính bị phản đối vì những tác động bất lợi của nó đối với trải nghiệm của người dùng cuối. Để được trợ giúp thêm, hãy kiểm tra https://xhr.spec.whatwg.org/ .

Điều này có thể phá vỡ trang của bạn nếu bạn đang làm một cái gì đó như thế này vì nó có thể ngừng hoạt động bất cứ ngày nào.

Nếu bạn muốn thực hiện theo cách vẫn có cảm giác như nếu nó đồng bộ nhưng vẫn không chặn thì bạn nên sử dụng async / await và có lẽ một số ajax dựa trên lời hứa như API Fetch mới

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

Chỉnh sửa chrome đang hoạt động trên Không cho phép đồng bộ hóa XHR khi loại bỏ trang khi trang đang bị người dùng điều hướng đi hoặc đóng. Điều này liên quan đến tải trước, dỡ, trang da và khả năng hiển thị.

nếu đây là trường hợp sử dụng của bạn sau đó bạn có thể muốn có một cái nhìn tại navigator.sendBeacon thay

Trang cũng có thể vô hiệu hóa req đồng bộ hóa với các tiêu đề http hoặc thuộc tính cho phép của iframe


Lưu ý rằng bạn nên gói await fetch(url)cuộc gọi của mình trong một try... catchkhối để bắt bất kỳ lỗi không đồng bộ nào.
inostia

4
chức năng foo đã được chuyển đổi thành một lời hứa chỉ bằng cách sử dụng từ asyncđầu, vì vậy bạn chỉ có thể thực hiện foo().catch(...)để nắm bắt nó
Vô tận

Chrome đã không cho phép async ajax bên trong trang beforeunloadnhưng sau đó đã hoàn nguyên thay đổi sau các lỗi phản hồi tiêu cực.chromium.org/p/chromium/issues/detail?id=952452
Alex

26

Hãy nhớ rằng nếu bạn đang thực hiện một cuộc gọi Ajax tên miền chéo (bằng cách sử dụng JSONP ) - bạn không thể thực hiện đồng bộ hóa, asynccờ sẽ bị jQuery bỏ qua.

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

Đối với các cuộc gọi JSONP bạn có thể sử dụng:

  1. Gọi Ajax đến miền của riêng bạn - và thực hiện phía máy chủ cuộc gọi tên miền chéo
  2. Thay đổi mã của bạn để làm việc không đồng bộ
  3. Sử dụng thư viện "chuỗi trình tự chức năng" như Frame.js ( câu trả lời này )
  4. Chặn UI thay vì chặn thực thi ( câu trả lời này ) (cách yêu thích của tôi)

12

Với async: falsebạn có được cho mình một trình duyệt bị chặn. Đối với một giải pháp đồng bộ không chặn, bạn có thể sử dụng như sau:

ES6 / ECMAScript2015

Với ES6, bạn có thể sử dụng trình tạo và thư viện đồng :

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

Với ES7, bạn có thể sử dụng asyc await:

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
    })(); 
}

3
Lưu ý rằng bạn chỉ có thể vượt qua async functionđể được điều trị trước beforecreate: async function(....và loại bỏ chức năng async tự gọi
Daniel Krom

12

Tôi đã sử dụng câu trả lời do Carcione đưa ra và sửa đổi nó để sử dụng 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');
    }    
}

Tôi được thêm vào datatype của 'JSON' và thay đổi .responseText để responseJSON .

Tôi cũng đã lấy trạng thái bằng cách sử dụng thuộc tính statusText của đối tượng được trả về. Lưu ý rằng đây là trạng thái của phản hồi Ajax, không phải là liệu JSON có hợp lệ hay không.

Back-end phải trả về phản hồi trong JSON chính xác (được định dạng tốt), nếu không, đối tượng được trả lại sẽ không được xác định.

Có hai khía cạnh để xem xét khi trả lời câu hỏi ban đầu. Một người đang bảo Ajax thực hiện đồng bộ (bằng cách đặt async: false ) và người kia đang trả lời phản hồi thông qua câu lệnh trả về của hàm gọi, thay vì vào hàm gọi lại.

Tôi cũng đã thử nó với POST và nó hoạt động.

Tôi đã thay đổi GET thành POST và thêm dữ liệu: 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;
}

Lưu ý rằng đoạn mã trên chỉ có tác dụng trong trường hợp asyncsai . Nếu bạn đã đặt async: true , đối tượng được trả về jqxhr sẽ không hợp lệ tại thời điểm cuộc gọi AJAX trả về, chỉ sau đó khi cuộc gọi không đồng bộ kết thúc, nhưng đã quá muộn để đặt biến phản hồi .


7

Đây là ví dụ:

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

1
Điểm của việc sử dụng async falsevới một giải pháp dựa trên lời hứa là gì. Điều này chỉ khóa trình duyệt không có lợi ích gì cả.
Mã hóa

2
@GoneCoding có những tình huống muốn thực thi mã theo trình tự chính xác, trong tình huống đó chúng ta có thể sử dụng async false
Nikki

1
@Nikki: Đó hoàn toàn không phải là cách để chạy chúng tuần tự. Sử dụng lời hứa không đồng bộ ( ajaxcuộc gọi đã trả về) và .then()hoặc done()(như đã hiển thị). Khóa trình duyệt là một trải nghiệm người dùng rất kém. Như tôi đã nói có async: falsetrong ví dụ này là một sự lãng phí hoàn toàn thời gian.
Mã hóa

4

Đầu tiên chúng ta nên hiểu khi nào chúng ta sử dụng $ .ajax và khi chúng ta sử dụng $ .get / $.

Khi chúng tôi yêu cầu kiểm soát mức độ thấp đối với yêu cầu ajax, chẳng hạn như cài đặt tiêu đề yêu cầu, cài đặt bộ đệm, cài đặt đồng bộ, v.v. chúng tôi nên sử dụng $ .ajax.

$ .get / $. post: Khi chúng tôi không yêu cầu kiểm soát mức độ thấp đối với yêu cầu ajax. Chỉ đơn giản là nhận / đăng dữ liệu lên máy chủ. Nó là viết tắt của

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

và do đó chúng tôi không thể sử dụng các tính năng khác (đồng bộ hóa, bộ đệm, v.v.) với bài đăng $ .get / $.

Do đó, để kiểm soát mức độ thấp (đồng bộ hóa, bộ đệm, v.v.) theo yêu cầu ajax, chúng ta nên sử dụng $ .ajax

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

2

đây là cách triển khai đơn giản của tôi cho các yêu cầu ASYNC với jQuery. Tôi hy vọng điều này sẽ giúp bất cứ ai.

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();

2

Bởi vì XMLHttpReponsehoạt động đồng bộ không được chấp nhận, tôi đã đưa ra giải pháp sau đây kết thúc tốt đẹp XMLHttpRequest. Điều này cho phép các truy vấn AJAX được đặt hàng trong khi vẫn có tính chất đơn phương, rất hữu ích cho các mã thông báo CSRF sử dụng một lần.

Nó cũng trong suốt nên các thư viện như jQuery sẽ hoạt động trơn tru.

/* 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

Vì câu hỏi ban đầu là về jQuery.get, điều đáng nói ở đây là (như đã đề cập ở đây ) người ta có thể sử dụng async: falsemột cách $.get()nhưng lý tưởng là tránh nó vì không đồng bộ XMLHTTPRequestbị phản đối (và trình duyệt có thể đưa ra cảnh báo):

$.get({
  url: url,// mandatory
  data: data,
  success: success,
  dataType: dataType,
  async:false // to make it synchronous
});

1
Tại sao điều này bị hạ cấp?
bí danh51

-2

Đặt asyn:falsetrong yêu cầu ajax để làm cho nó đồng bộ.

Đây là mẫu mã:

 $.ajax({
    url: 'some_url',
    type: "GET",
    async: false,
    cache: false,
    dataType: "JSON",
    data: { 
      "p1": v1, 
      "p2": v2
    },
    success: function(result) {
    }  
  }
});

Điều này có thể làm cho màn hình không phản hồi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.