ฉันจะทำให้ jQuery ดำเนินการซิงโครนัสแทนที่จะเป็นแบบอะซิงโครนัสคำขอ Ajax ได้อย่างไร


1207

ฉันมีวิดเจ็ต JavaScript ที่ให้คะแนนส่วนขยายมาตรฐาน หนึ่งในนั้นคือbeforecreateฟังก์ชั่น ควรกลับfalseไปเพื่อป้องกันไม่ให้สร้างรายการ

ฉันได้เพิ่มการเรียก Ajax ในฟังก์ชันนี้โดยใช้ 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);
  });
}

แต่ฉันต้องการป้องกันไม่ให้วิดเจ็ตของฉันสร้างรายการดังนั้นฉันควรกลับมาfalseในฟังก์ชั่นหลักไม่ใช่ในการติดต่อกลับ มีวิธีดำเนินการคำขอ AJAX แบบซิงโครนัสโดยใช้ jQuery หรือ API ในเบราว์เซอร์อื่นหรือไม่


30
วิธีที่เหมาะสมในการแก้ปัญหานั่นก็คือการเขียนสัญญาการใช้จุดส่วนขยายของวิดเจ็ตของคุณใหม่ วิธีนี้จะช่วยให้คุณได้อย่างง่ายดายในการตั้งค่าการกระทำที่ไม่ตรงกัน (เช่นการร้องขออาแจ็กซ์) beforecreateในฐานะ
Kos

3
ฉันเสนอฟังก์ชัน Sajak เรามีตัวอักษร T หรือไม่? ใช่ vanna ให้ 3 T ของฉัน
Cody O'Dell

2
@Kos เป็นจุดบน ไม่จำเป็นต้องซิงค์ XHR ที่นี่
Michael Westcott

1
หากมีคนถามฉันสำหรับคำแนะนำ 1 ชิ้นเมื่อเริ่มต้นจาวาสคริปต์ฉันพูดว่า: โอบกอดอักขระอะซิงโครนัสของจาวาสคริปต์อย่าลองใช้การต่อสู้แบบนั้น
Emmanuel Delay

3
คำถามนี้เหมือนกับถามว่า "ฉันจะเก็บรหัสผ่านผู้ใช้ของฉันเป็นข้อความธรรมดาได้อย่างไร" แน่นอนว่ามีคำตอบ แต่อย่าทำ
Vectorjohn

คำตอบ:


1165

จากเอกสาร jQuery : คุณระบุตัวเลือกแบบอะซิงโครนัสเป็นเท็จเพื่อรับคำขออาแจ็กซ์แบบซิงโครนัส จากนั้นการโทรกลับของคุณสามารถตั้งค่าข้อมูลบางอย่างก่อนหน้าที่แม่ของคุณดำเนินการต่อไป

นี่คือรหัสของคุณหากมีการเปลี่ยนแปลงตามที่แนะนำ:

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
ไม่สามารถใช้ get (), post (), load () สำหรับการโทรแบบซิงโครนัสได้ เฉพาะ ajax () มีพารามิเตอร์ "async" ซึ่งสามารถตั้งค่าเป็น "false"
SLA80

39
@ SLA80 Nope ตั้งแต่ jQuery 1.1: stackoverflow.com/questions/6849686/…
StuperUser

16
@qualidafial ความคิดเห็นของฉันมีวัตถุประสงค์เพื่อความคิดเห็นที่ไม่ถูกต้องของ SLA80; เป็นไปได้ที่จะใช้ get (), post (), load () สำหรับการโทรแบบซิงโครนัส
StuperUser

9
ไม่สนับสนุน async false อีกต่อไปสำหรับ jQuery> = 1.8 อ้างถึง api.jquery.com/jQuery.ajax
ken

22
@ken async: falseยังคงรองรับ jQuery> = 1.8 ความสามารถในการใช้async: falseกับ jqXHR ( $.Deferred) เป็นสิ่งที่ถูกคัดค้าน ในคำอื่น ๆ หนึ่งจะต้องใช้ตัวเลือกการประสบความสำเร็จ / ข้อผิดพลาด / jqXHR.done()โทรกลับสมบูรณ์ใหม่แทนวิธีเดิมเช่น
เบ็นจอห์นสัน

255

คุณสามารถตั้งค่า Ajax ของ jQuery ในโหมดซิงโครนัสได้ด้วยการโทร

jQuery.ajaxSetup({async:false});

จากนั้นทำการโทรอาแจ็กซ์ของคุณโดยใช้ jQuery.get( ... );

จากนั้นเพียงเปิดอีกครั้ง

jQuery.ajaxSetup({async:true});

ฉันเดาว่ามันจะออกมาในลักษณะเดียวกับที่ @Adam แนะนำ แต่อาจเป็นประโยชน์กับคนที่ต้องการกำหนดค่าใหม่jQuery.get()หรือไวยากรณ์ที่jQuery.post()ซับซ้อนยิ่งขึ้นjQuery.ajax()


56
นี่เป็นความคิดที่แย่จริงๆทำไมคุณถึงตั้งไว้ในระดับโลก? และจากนั้นถูกบังคับให้ยกเลิกการตั้งค่าหลังจากนั้น?
Juan Mendes

11
อย่างน้อยนี่เป็นความคิดที่ดีที่สุด แทนที่จะพูดว่า: "ไม่มีทางยกเว้น$.ajax()" ;)
Rzassar

136

ทางออกที่ดีเยี่ยม! ฉันสังเกตเห็นเมื่อฉันพยายามที่จะใช้มันว่าถ้าฉันคืนค่าในข้อความสำเร็จมันกลับมาเป็นไม่ได้กำหนด ฉันต้องเก็บมันไว้ในตัวแปรแล้วคืนค่าตัวแปรนั้น นี่เป็นวิธีที่ฉันคิดขึ้นมา:

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
getWhateverนั่นเพราะคุณกำลังจะกลับค่าจากการเรียกกลับไม่ได้ออกจาก ดังนั้นคุณกลับไม่มีอะไรเช่นจากคุณundefined getWhatever
Lightness Races ในวงโคจร

6
มันผิดอย่างแน่นอน คุณไม่แน่ใจว่าการโทรแบบอะซิงโครนัสเสร็จสิ้นเมื่อส่งคืน 'strReturn'
Thomas Fritz

61
นี่คือการโทรแบบซิงโครนัส (async: false)
James ใน Indy

85

คำตอบทั้งหมดเหล่านี้พลาดจุดที่ทำการโทร Ajax ด้วย async: false จะทำให้เบราว์เซอร์หยุดทำงานจนกว่าคำขอ 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();
}

4
การโทรแบบซิงโครนัสนั้นมีประโยชน์ถ้าคุณต้องการรวมสายทดสอบทดสอบอย่างรวดเร็วสำหรับส่วนหลัง REST และต้องการความเรียบง่ายมากกว่านรกโทรกลับ
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
โปรดทราบว่าแม้ว่าคุณอาจได้รับสิ่งนี้: 'Synchronous XMLHttpRequest ในเธรดหลักเลิกใช้งานเนื่องจากมีผลเสียต่อการใช้งานของผู้ใช้'
Hari

5
@Hari วิธีการโทร ajax แบบซิงโครนัสโดยใช้ jQuery โดยไม่ต้องใช้เธรดหลักคืออะไร
Jose Nobile

7
ฉันไม่เห็นว่าคำตอบนี้มีอะไรที่จะนำเสนอมันเป็นเพียงคำตอบที่ได้รับการยอมรับซึ่งห่อไว้ในฟังก์ชั่นและตอบกลับสี่ปีต่อมา มันเป็นสิ่งที่ไม่ดีที่จะแนะนำผู้คนให้รู้จักกับ C + P เพราะฟังก์ชั่นไม่ได้ระบุว่ามันทำอะไร "ดังนั้นgetURLVS getทำไมหนึ่งไม่แขวนเบราว์เซอร์ของฉัน" ฯลฯ
moopet

27

หมายเหตุ: คุณไม่ควรใช้async: falseเนื่องจากข้อความเตือนนี้:

เริ่มต้นด้วย Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27) การร้องขอแบบซิงโครนัสบนเธรดหลักได้ถูกคัดค้านเนื่องจากผลกระทบด้านลบต่อประสบการณ์ของผู้ใช้

Chrome ยังเตือนเกี่ยวกับสิ่งนี้ในคอนโซล:

XMLHttpRequest แบบซิงโครนัสบนเธรดหลักถูกคัดค้านเนื่องจากผลกระทบที่เป็นอันตรายต่อประสบการณ์ของผู้ใช้ สำหรับความช่วยเหลือเพิ่มเติมให้ตรวจสอบhttps://xhr.spec.whatwg.org/

นี่อาจทำให้เพจของคุณพังถ้าคุณทำสิ่งนี้เพราะหยุดทำงานได้ทุกวัน

หากคุณต้องการทำในลักษณะที่ยังรู้สึกเหมือนเป็นซิงโครนัส แต่ยังไม่ปิดกั้นคุณควรใช้ async / await และอาจเป็น ajax ที่ยึดตามสัญญาเช่นFetch API ใหม่

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


โปรดทราบว่าคุณควรตัดawait fetch(url)สายของคุณในtry... catchบล็อกเพื่อตรวจจับข้อผิดพลาดแบบอะซิงโครนัส
inostia

4
ฟังก์ชั่น foo ถูกแปลงเป็นคำสัญญาเพียงแค่ใช้คำว่าasyncในตอนแรกดังนั้นคุณสามารถทำได้foo().catch(...)เพื่อจับมัน
Endless

Chrome ไม่อนุญาต async ajax ในหน้าbeforeunloadแล้วยกเลิกการเปลี่ยนแปลงกลับไปหลังจากข้อเสนอแนะเชิงลบbugs.chromium.org/p/chromium/issues/detail?id=952452
Alex

26

โปรดทราบว่าหากคุณกำลังทำการเรียก Ajax ข้ามโดเมน (โดยใช้JSONP ) - คุณไม่สามารถทำแบบซิงโครนัสได้การasyncตั้งค่าสถานะจะถูกละเว้นโดย jQuery

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

สำหรับการโทร JSONP คุณสามารถใช้:

  1. Ajax โทรไปยังโดเมนของคุณ - และทำการโทรข้ามโดเมนฝั่งเซิร์ฟเวอร์
  2. เปลี่ยนรหัสของคุณให้ทำงานแบบอะซิงโครนัส
  3. ใช้ไลบรารี "function sequencer" เช่น Frame.js ( คำตอบนี้)
  4. บล็อก UI แทนการบล็อกการดำเนินการ ( คำตอบนี้) (วิธีที่ฉันชอบ)

12

เมื่อasync: falseคุณได้รับเบราว์เซอร์ที่ถูกบล็อกด้วยตัวคุณเอง สำหรับโซลูชันแบบซิงโครนัสที่ไม่มีการบล็อกคุณสามารถใช้สิ่งต่อไปนี้:

ES6 / ECMAScript2015

ด้วย ES6 คุณสามารถใช้ตัวสร้าง & ไลบรารีร่วม :

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 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
แจ้งให้ทราบว่าคุณสามารถส่งผ่านasync functionไปก่อนสร้าง beforecreate: async function(....และลบฟังก์ชัน async ที่เรียกใช้ด้วยตนเอง
Daniel Krom

12

ฉันใช้คำตอบที่ได้รับจาก 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 ที่ถูกต้อง (มีรูปแบบถูกต้อง) ไม่เช่นนั้นวัตถุที่ส่งคืนจะไม่ถูกกำหนด

มีสองด้านที่ควรพิจารณาเมื่อตอบคำถามต้นฉบับ มีคนหนึ่งแจ้งให้อาแจ็กซ์ดำเนินการแบบซิงโครนัส (โดยการตั้งค่าasync: false ) และอีกอันกำลังส่งคืนการตอบสนองผ่านคำสั่งส่งคืนของฟังก์ชั่นการโทรแทนที่จะเข้าสู่ฟังก์ชันการโทรกลับ

ฉันยังลองกับ POST และใช้งานได้

ฉันเปลี่ยน GET เป็น POST และเพิ่มข้อมูล: 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เป็นเท็จ หากคุณต้องตั้งค่าasync: trueอ็อบเจ็กต์ที่ส่งคืนjqxhrจะไม่ถูกต้องในขณะที่การโทร AJAX ส่งคืนเฉพาะในภายหลังเมื่อการโทรแบบอะซิงโครนัสเสร็จสิ้นแล้ว แต่การตั้งค่าตัวแปรตอบกลับช้าเกินไป


7

นี่คือตัวอย่าง:

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

1
จุดประสงค์ของการใช้async falseกับโซลูชันที่อิงตามสัญญาคืออะไร นี่ล็อคเบราว์เซอร์เท่านั้นเพื่อประโยชน์ใด ๆ เลย
ไปที่การเข้ารหัส

2
@GoneCoding มีสถานการณ์ที่ต้องการรันโค้ดตามลำดับที่แน่นอนในสถานการณ์นั้นเราสามารถใช้ async false ได้
Nikki

1
@ นิกกี้: นั่นไม่ใช่วิธีที่จะเรียกใช้ตามลำดับ ใช้สัญญา async (ซึ่งajaxโทรกลับแล้ว) และ.then()หรือdone()(ตามที่แสดงแล้ว) การล็อกเบราว์เซอร์เป็นประสบการณ์ของผู้ใช้ที่แย่มาก อย่างที่ฉันบอกว่าการมีasync: falseในตัวอย่างนี้เป็นการเสียเวลาโดยสิ้นเชิง
Gone Coding

4

ประการแรกเราควรเข้าใจเมื่อเราใช้ $ .ajax และเมื่อเราใช้ $ .get / $. post

เมื่อเราต้องการการควบคุมระดับต่ำสำหรับการร้องขอ ajax เช่นการตั้งค่าส่วนหัวคำขอการตั้งค่าแคชการตั้งค่าแบบซิงโครนัส ฯลฯ จากนั้นเราควรไปที่ $ .ajax

$ .get / $. โพสต์: เมื่อเราไม่ต้องการการควบคุมระดับต่ำกว่าคำขอ ajax เพียงรับ / โพสต์ข้อมูลไปยังเซิร์ฟเวอร์ มันเป็นชวเลขของ

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

และด้วยเหตุนี้เราจึงไม่สามารถใช้คุณสมบัติอื่น ๆ (ซิงค์แคช ฯลฯ ) กับโพสต์ $ .get / $

ดังนั้นสำหรับการควบคุมระดับต่ำ (ซิงค์แคช ฯลฯ ) ผ่านการร้องขอ ajax เราควรไปที่ $ .ajax

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

2

นี่คือการใช้งานที่เรียบง่ายสำหรับคำขอ ASYNC กับ jQuery ฉันหวังว่านี่จะช่วยให้ทุกคน

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

เนื่องจากXMLHttpReponseการดำเนินการแบบซิงโครนัสเลิกใช้ฉันจึงคิดวิธีแก้ไขปัญหาดังต่อไปนี้XMLHttpRequestการดำเนินการซิงโครจะเลิกฉันมากับการแก้ปัญหาต่อไปนี้ที่ตัดสิ่งนี้ทำให้คำสั่ง AJAX ที่สั่งไว้นั้นยังคงเป็น asycnronous ในธรรมชาติซึ่งมีประโยชน์มากสำหรับโทเค็น 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

เนื่องจากคำถามเดิมเกี่ยวกับjQuery.getมันเป็นมูลค่าการกล่าวถึงที่นี่ที่ (ดังกล่าวถึงที่นี่ ) หนึ่งสามารถใช้async: falseใน$.get()แต่หลีกเลี่ยงนึกคิดเพราะไม่ตรงกันไม่XMLHTTPRequestสนับสนุน

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

1
ทำไม downvote นี้
alias51

-2

ตั้งค่าasyn:falseในคำขอ ajax เพื่อให้ซิงโครนัส

นี่คือตัวอย่างโค้ด:

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

สิ่งนี้สามารถทำให้หน้าจอไม่ตอบสนอง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.