รอจนกระทั่งคำขอ jQuery Ajax ทั้งหมดเสร็จสิ้นหรือไม่


675

ฉันจะทำให้ฟังก์ชั่นรอจนกระทั่งคำขอ jQuery Ajax ทั้งหมดเสร็จสิ้นภายในฟังก์ชั่นอื่นได้อย่างไร

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


คุณเรียกคำขอ ajax ดั้งเดิมของคุณอย่างไร?
NakedBrunch

2
คุณทำในสิ่งที่หมายถึง? ฉันเข้าใจว่าเป็น "คำขอทั้งหมดเสร็จสมบูรณ์หรือไม่" (แก้ไขหรือปฏิเสธ) แต่คุณอาจหมายถึง "คำขอทั้งหมดเสร็จสมบูรณ์" (แก้ไขแล้ว) ดูรูปแบบทั้งหมดในapi.jquery.com/category/deferred-object
Adrien เป็น

คำตอบ:


911

jQuery ตอนนี้กำหนดฟังก์ชั่นเมื่อเพื่อวัตถุประสงค์นี้

มันรับจำนวนวัตถุที่รอการตัดบัญชีเป็นข้อโต้แย้งและดำเนินการฟังก์ชั่นเมื่อพวกเขาทั้งหมดแก้ไข

ซึ่งหมายความว่าหากคุณต้องการเริ่มต้น (ตัวอย่าง) คำขอ ajax สี่คำขอจากนั้นดำเนินการเมื่อเสร็จแล้วคุณสามารถทำสิ่งนี้ได้:

$.when(ajax1(), ajax2(), ajax3(), ajax4()).done(function(a1, a2, a3, a4){
    // the code here will be executed when all four ajax requests resolve.
    // a1, a2, a3 and a4 are lists of length 3 containing the response text,
    // status, and jqXHR object for each of the four ajax calls respectively.
});

function ajax1() {
    // NOTE:  This function must return the value 
    //        from calling the $.ajax() method.
    return $.ajax({
        url: "someUrl",
        dataType: "json",
        data:  yourJsonData,            
        ...
    });
}

ในความคิดของฉันมันทำให้ไวยากรณ์ที่สะอาดและชัดเจนและหลีกเลี่ยงการเกี่ยวข้องกับตัวแปรทั่วโลกเช่น ajaxStart และ ajaxStop ซึ่งอาจมีผลข้างเคียงที่ไม่พึงประสงค์ในขณะที่หน้าของคุณพัฒนา

หากคุณไม่ทราบล่วงหน้าว่าจะต้องมีอาร์กิวเมนต์อาแจ็กซ์จำนวนเท่าใด (เช่นคุณต้องการใช้จำนวนตัวแปรที่มีข้อโต้แย้ง) ก็ยังสามารถทำได้ แต่ก็ยากกว่านิดหน่อย ดูPass ในอาร์เรย์ Deferreds เป็น $. เมื่อ () (และอาจจะjQuery. เมื่อการแก้ไขปัญหาด้วยจำนวนอาร์กิวเมนต์ที่เปลี่ยนแปลง )

หากคุณต้องการควบคุมโหมดความล้มเหลวของสคริปต์ ajax ให้ลึกซึ้งยิ่งขึ้นคุณสามารถบันทึกวัตถุที่ส่งคืนโดย.when()- เป็นวัตถุสัญญา jQuery ซึ่งครอบคลุมคำค้นหา ajax ดั้งเดิมทั้งหมด คุณสามารถโทร.then()หรือ.fail()เพิ่มรายละเอียดตัวจัดการความสำเร็จ / ล้มเหลวได้


46
ควรทำเครื่องหมายเป็นคำตอบที่ถูกต้องเพราะง่ายมีประสิทธิภาพและใช้งานได้ดี นอกจากนี้ก็ควรจะตั้งข้อสังเกตว่า$.whenจะส่งคืนวัตถุซึ่งมีวิธีการที่เป็นประโยชน์มากขึ้นไม่เพียงPromise .doneตัวอย่างเช่นด้วย.then(onSuccess, onFailure)วิธีการที่คุณสามารถตอบสนองเมื่อคำขอทั้งสองประสบความสำเร็จหรืออย่างน้อยหนึ่งข้อล้มเหลว
skalee

2
เป็นไปได้หรือไม่ที่จะรวมคำขอ ajax1..4 ไว้ในอาร์เรย์และส่งต่อไป
andig

33
ระมัดระวังกับfailกรณี ซึ่งแตกต่างจากdone, failไฟทันทีในครั้งแรกล้มเหลวและสภาพแวดล้อม deferreds เหลือ
Ryan Mohr

1
@Skalee ขอบคุณสำหรับการเน้นความจริงที่ว่าonFailureฟังก์ชั่นสามารถแนบ ในขณะที่ฉันชี้ให้เห็นในการแสดงความคิดเห็นกับคำถามของ OP: เขาอาจต้องการระบุอย่างแม่นยำมากขึ้นว่า "เสร็จสิ้น" "ไรอันมอร์" ยังไม่มีจุดดีมากเกี่ยวกับความจริงที่ว่าfailทำงานแตกต่างกันเป็นdoneบางส่วนอ่านต่อไปที่จะทำเกี่ยวกับPromisesฉันเดาhtml5rocks.com/en/tutorials/es6/promises
Adrien เป็น

1
เป็นเรื่องดีที่จะให้ผู้คนได้สัมผัสกับวิธีการเมื่อถึงเวลาและสัญญาโดยทั่วไป แต่ฉันคิดว่านี่ไม่ใช่คำตอบที่ดีที่สุด หาก ajax เหล่านี้ทำงานที่ใดก็ได้ในบรรทัดให้สร้างคำขอ ajax อีกครั้งและจากนั้นไม่รวมสัญญาใหม่เข้ากับเชนอย่างถูกต้อง ... คำขอเหล่านั้นจะหลบหนีเทคนิคนี้ ตัวอย่างเช่นฉันไม่สามารถใช้เทคนิคนี้ได้โดยไม่ต้องแก้ไขไลบรารี Shopify ที่ฉันใช้สำหรับพฤติกรรมการสั่งซื้อ ajax เนื่องจากไม่ได้เขียนในลักษณะ 'พรวดพราด' และไม่ส่งคืนวัตถุ xhr ที่สร้างขึ้น มันสมเหตุสมผลหรือไม่ ยังเป็นคำตอบที่ยอดเยี่ยม!
Ziggy

292

หากคุณต้องการทราบว่าเมื่อ ajaxคำขอทั้งหมดเสร็จสิ้นในเอกสารของคุณไม่ว่าจะมีคำขอจำนวนเท่าใดให้ใช้เหตุการณ์$ .ajaxStopด้วยวิธีนี้:

$(document).ajaxStop(function () {
  // 0 === $.active
});

ในกรณีนี้คุณไม่จำเป็นต้องคาดเดาว่ามีคำขอเกิดขึ้นจำนวนเท่าใดในแอปพลิเคชันซึ่งอาจเสร็จสิ้นในอนาคตหรือขุดเป็นฟังก์ชันตรรกะที่ซับซ้อนหรือค้นหาฟังก์ชันที่ทำหน้าที่HTTP(S)ร้องขอ

$.ajaxStopที่นี่ยังสามารถผูกกับHTMLโหนดใด ๆที่คุณคิดว่าอาจถูกแก้ไขโดย requst


อัปเดต:
หากคุณต้องการติดกับESไวยากรณ์คุณสามารถใช้Promise.allสำหรับajaxวิธีการที่เป็นที่รู้จัก:

Promise.all([ajax1(), ajax2()]).then(() => {
  // all requests finished successfully
}).catch(() => {
  // all requests finished but one or more failed
})

จุดที่น่าสนใจที่นี่เป็นที่ทำงานทั้งที่มีPromisesและ$.ajaxการร้องขอ

นี่คือการสาธิตjsFiddle


อัปเดต 2:
ยังมีเวอร์ชันที่ใหม่กว่าโดยใช้ไวยากรณ์async / await :

try {
  const results = await Promise.all([ajax1(), ajax2()])
  // do other actions
} catch(ex) { }

16
+1 ดีกว่าคำตอบอื่น ๆในกรณีที่คุณต้องจัดการกับสคริปต์บุคคลที่สามด้วยการโทรกลับ / ปิดที่ไม่ระบุชื่อ
ไกเซอร์

5
@kaiser จุดที่ถูกต้อง แต่ไม่ใช่คำถามที่ถาม มันไม่ดีมากถ้าคุณไม่ต้องการรอให้ AJAX โทรกลับ คำถามเฉพาะเกี่ยวกับการรอการโทร AJAX ที่คุณทำด้วยตัวเอง (เรียกว่าภายในฟังก์ชั่นอื่นตามที่ OP เขียน) บางรหัสอื่นอาจทำการโทร AJAX อีกครั้งที่คุณไม่ต้องการรอ
Juan Mendes

6
เปรียบเทียบกับโซลูชัน when () มันมีข้อดีในการทำงานแม้ว่าจะไม่ทราบจำนวนการโทร ajax
Alexis Dufrenoy

5
เมื่อเทียบกับโซลูชัน when () โซลูชันนี้มีข้อเสียอย่างมากที่จะไม่ทำงานร่วมกับส่วนประกอบอื่น ๆ ได้ดีเนื่องจากเป็นสถานะโกลบอลของเอกสาร หากมีการเลือกตั้งนานดำเนินต่อเนื่องมันอาจจะไม่ยิงเลย
Bergi

3
คุณไม่ถูกต้อง @AdrienBe, ajaxStop จัดการคำขอ ajax ทั้งหมดไม่ว่าพวกเขาจะประสบความสำเร็จหรือไม่เช่นเดียวกับข้อพิสูจน์คำพูดของฉันดูjsfiddle.net/36votxba/2
Arsen Khachaturyan

32

ผมพบว่าคำตอบที่ดีโดยgnarfตัวเองของฉันซึ่งเป็นสิ่งที่ผมกำลังมองหา :)

jQuery ajaxQueue

//This handles the queues    
(function($) {

  var ajaxQueue = $({});

  $.ajaxQueue = function(ajaxOpts) {

    var oldComplete = ajaxOpts.complete;

    ajaxQueue.queue(function(next) {

      ajaxOpts.complete = function() {
        if (oldComplete) oldComplete.apply(this, arguments);

        next();
      };

      $.ajax(ajaxOpts);
    });
  };

})(jQuery);

จากนั้นคุณสามารถเพิ่มคำขอ ajax ในคิวดังนี้:

$.ajaxQueue({
        url: 'page.php',
        data: {id: 1},
        type: 'POST',
        success: function(data) {
            $('#status').html(data);
        }
    });

37
ดูเหมือนว่าคุณลืมที่จะระบุแหล่งที่มาที่เหมาะสมให้กับคำตอบนี้ฉันได้เพิ่มไว้แล้ว
Tim Post

21

ใช้ajaxStopเหตุการณ์

ตัวอย่างเช่นสมมติว่าคุณมีข้อความกำลังโหลด ...ขณะดึงข้อมูลคำขอ ajax 100 รายการและคุณต้องการซ่อนข้อความนั้นเมื่อโหลด

จากเอกสาร jQuery :

$("#loading").ajaxStop(function() {
  $(this).hide();
});

โปรดทราบว่ามันจะรอคำขอ ajax ทั้งหมดที่ทำในหน้านั้น


5
สิ่งนี้ถือว่าคุณรู้ว่าจะไม่มีคำขอ AJAX อื่น ๆ บนหน้านี้ไม่ใช่ข้อสันนิษฐานที่ดีมาก
Juan Mendes

ตั้งแต่ jQuery 1.8 ควรแนบเมธอด. jaxStop () กับเอกสารเท่านั้น
Geomorillo

1
แก้ไขให้ถูกต้องหากฉันทำผิด แต่จะไม่ทำให้โครงการของคุณกลายเป็นไซต์ "เว็บฟอร์มโรงเรียนเก่า" หรือไม่ ฉันหมายความว่าถ้าคุณหน้าทั้งหมดของคุณต้องรอการร้องขอก่อนที่จะสามารถดำเนินการต่อไปแล้วจุดของการร้องขอ ajax ในสถานที่แรกคืออะไร?
BillRuhl

@BillRuhl ในกรณีของเราฉันกำลังวนผ่านคอลเลกชัน jquery เพื่อสร้างสิ่งใหม่และจำเป็นต้องรู้เกี่ยวกับคอลเลกชันทั้งหมดเมื่อเสร็จแล้วก่อนที่จะทำการปรับเปลี่ยนเลย์เอาต์ ดูเหมือนจะเป็นกรณีที่ผิดปกติอย่างยิ่ง จะไม่ดีหากมีสิ่งอาแจ็กซ์อื่น ๆ อยู่ในกระบวนการ แต่มันจะไม่เกิดขึ้นที่นี่
กัป

21

หมายเหตุ:คำตอบข้างต้นใช้ฟังก์ชั่นที่ไม่มีอยู่ในขณะที่เขียนคำตอบนี้ ฉันแนะนำให้ใช้jQuery.when()แทนวิธีการเหล่านี้ แต่ฉันทิ้งคำตอบไว้เพื่อจุดประสงค์ทางประวัติศาสตร์

-

คุณอาจได้รับโดยการนับสัญญาณง่าย ๆ แม้ว่าวิธีที่คุณใช้มันจะขึ้นอยู่กับรหัสของคุณ ตัวอย่างง่ายๆจะเป็นสิ่งที่ชอบ ...

var semaphore  = 0,     // counting semaphore for ajax requests
    all_queued = false; // bool indicator to account for instances where the first request might finish before the second even starts

semaphore++;
$.get('ajax/test1.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test2.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test3.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test4.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

// now that all ajax requests are queued up, switch the bool to indicate it
all_queued = true;

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

var $queue = $("<div/>");
$queue.queue(function(){
    $.get('ajax/test1.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test2.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test3.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test4.html', function(data) {
        $queue.dequeue();
    });
});

10
ดูเหมือนว่ามันจะมีปัญหายุ่งยากเล็กน้อยมากเกินไป
Chris

2
มันไม่ซับซ้อนจริงๆ การนับเซมาฟอร์เป็นกลไกทั่วไปใน CS หากคุณต้องการตัวอย่างของการใช้คิว jQuery ก็ใช้ได้เช่นกันโดยไม่ต้องใช้เซมาฟอร์ด้วยตัวเอง
BBonifield

1
ฉันไม่เห็นปัญหากับตัวนับสัญญาณอย่างไรก็ตามฉันเห็นปัญหาเกี่ยวกับแนวคิดของการมีฟังก์ชั่นสี่เพื่อจัดการกับการเรียกกลับที่เกิดขึ้น .get()คุณควรที่จะกำหนดฟังก์ชั่นเป็นครั้งแรกแล้วอ้างอิงฟังก์ชั่นว่าในแต่ละ ด้วยวิธีนี้อย่างน้อยที่สุดคุณไม่ต้องทำซ้ำรหัสนั้น ไม่เพียงแค่นั้น แต่การประกาศfunction(){}แต่ละครั้งจะจัดสรรหน่วยความจำในแต่ละครั้ง! ค่อนข้างจะเป็นการปฏิบัติที่ไม่ดีถ้าคุณสามารถเรียกใช้ฟังก์ชันที่กำหนดแบบคงที่
Alexis Wilke

1
@AlexisWilke นี่เป็นคำตอบอายุ 4.5 ปีและมันก็หมายถึงเป็นตัวอย่างของ semaphores และคิวทำงานอย่างไร คุณกำลังคิดมากเกินไปเกี่ยวกับเรื่องนี้และฉันไม่คิดว่าการใช้ตัวพิมพ์ใหญ่เพื่อสร้างแต้มเป็นสิ่งจำเป็น
BBonifield

2
อืม ... ฉันไม่ใช่คนที่ให้ -1 กับคุณ ... และฉันเข้าใจว่าคำตอบมีแนวโน้มที่จะอายุมากขึ้น ถึงกระนั้นผู้คนก็พบพวกเขาเรื่อย ๆ และเท่าที่ฉันรู้ว่ามันเป็นสิ่งต้องห้ามที่จะให้ข้อมูลกับคนที่อาจจะใช้มันในวันนี้
Alexis Wilke

8

javascript เป็นไปตามเหตุการณ์ดังนั้นคุณไม่ควรรอให้ตั้ง hooks / callbacks แทน

คุณสามารถใช้วิธีการสำเร็จ / วิธีการแบบสมบูรณ์ของjquery.ajax

หรือคุณสามารถใช้. jaxComplete :

$('.log').ajaxComplete(function(e, xhr, settings) {
  if (settings.url == 'ajax/test.html') {
    $(this).text('Triggered ajaxComplete handler.');
    //and you can do whatever other processing here, including calling another function...
  }
});

แม้ว่าคุณควรโพสต์ pseudocode ว่าคำขอ ajax ของคุณถูกเรียกว่าแม่นยำมากกว่านี้อย่างไร


8

วิธีแก้ไขเล็กน้อยคืออะไรเช่นนี้:

// Define how many Ajax calls must be done
var ajaxCalls = 3;
var counter = 0;
var ajaxCallComplete = function() {
    counter++;
    if( counter >= ajaxCalls ) {
            // When all ajax calls has been done
        // Do something like hide waiting images, or any else function call
        $('*').css('cursor', 'auto');
    }
};

var loadPersons = function() {
        // Show waiting image, or something else
    $('*').css('cursor', 'wait');

    var url = global.ctx + '/loadPersons';
    $.getJSON(url, function(data) {
            // Fun things
    })
    .complete(function() { **ajaxCallComplete();** });
};

var loadCountries = function() {
    // Do things
    var url = global.ctx + '/loadCountries';
    $.getJSON(url, function(data) {
            // Travels
    })
    .complete(function() { **ajaxCallComplete();** });
};

var loadCities = function() {
    // Do things
    var url = global.ctx + '/loadCities';
    $.getJSON(url, function(data) {
            // Travels
    })
    .complete(function() { **ajaxCallComplete();** });
};

$(document).ready(function(){
    loadPersons();
    loadCountries();
    loadCities();
});

หวังว่าจะมีประโยชน์ ...


ในขณะที่คำตอบอื่น ๆ นั้นดีกว่าในทางเทคนิคเนื่องจากเป็นวิธีที่เข้าใจง่ายกว่า แต่ฉันชอบคำนี้มาก ดี!
Jay

4

jQuery อนุญาตให้คุณระบุว่าคุณต้องการให้ ajax ร้องขอแบบอะซิงโครนัสหรือไม่ คุณสามารถทำการร้องขอ ajax แบบซิงโครนัสแล้วส่วนที่เหลือของรหัสจะไม่ทำงานจนกว่าพวกเขาจะกลับมา

ตัวอย่างเช่น:

jQuery.ajax({ 
    async: false,
    //code
});

42
สิ่งหนึ่งที่ควรทราบคือการใช้ {async: false} สามารถล็อคเบราว์เซอร์ได้ชั่วคราว api.jquery.com/jQuery.ajax
BBonifield

30
สิ่งนี้จะตรงกันข้ามกับการปฏิบัติ jQuery / Javascript มาตรฐาน AJAX ควรจะไม่ตรงกันเสมอ คุณควรใช้ jQuery.when () แทน
SystemParadox

43
มันเป็นความคิดที่แย่มาก ๆ ! ไม่เคยทำอย่างนั้น! การบล็อก = ไม่ตอบสนองต่อการกระทำของผู้ใช้เลยแม้แต่การเลื่อนหรืออะไรก็ตาม! (เช่น async: false จะเลิกใช้ใน jQuery 1.8)
skalee

5
โดยเฉพาะอย่างยิ่งหากคำขอล้มเหลวหรือใช้เวลานานด้วยเหตุผลที่คาดเดาไม่ได้ (ซึ่งตามกฎของ Murphy นั้นต้องเกิดขึ้น!) นี่เป็นความคิดที่ผิดปกติสำหรับรหัสการผลิตเนื่องจากการล็อกเบราว์เซอร์ตามที่ระบุไว้ข้างต้น
อเล็กซ์

27
นี่เป็นความคิดที่แย่มาก อย่าใช้คำตอบนี้
Tauren

2

หากคุณต้องการอะไรที่เรียบง่าย โทรกลับครั้งเดียวแล้วเสร็จ

        //multiple ajax calls above
        var callback = function () {
            if ($.active !== 0) {
                setTimeout(callback, '500');
                return;
            }
            //whatever you need to do here
            //...
        };
        callback();

4
มันสามารถสร้างวงวนไม่รู้จบ!
Diego Favero

2
นี่คือการวนซ้ำไม่รู้จบ? เมื่อไหร่? เมื่อ AJAX ไม่กลับมา?
Jonathan

2

นอกจากนี้คุณสามารถใช้async.js

ฉันคิดว่ามันดีกว่า $. เมื่อคุณสามารถรวมการโทรแบบอะซิงโครนัสทุกชนิดที่ไม่รองรับสัญญานอกกรอบเช่นหมดเวลาโทร SqlLite ฯลฯ และไม่ใช่แค่การขออาแจ็กซ์


2

บนพื้นฐานของคำตอบ @ BBonifield ฉันเขียนฟังก์ชันยูทิลิตี้เพื่อให้สัญญาณเซมาฟอร์ไม่ได้แพร่กระจายในการโทร ajax ทั้งหมด

untilAjax เป็นฟังก์ชั่นยูทิลิตี้ที่เรียกใช้ฟังก์ชั่นการโทรกลับเมื่อ ajaxCalls ทั้งหมดเสร็จสมบูรณ์

ajaxObjs[http://api.jquery.com/jQuery.ajax/]เป็นอาร์เรย์ของวัตถุการตั้งค่าอาแจ็กซ์

fn เป็นฟังก์ชั่นการโทรกลับ

function untilAjax(ajaxObjs, fn) {
  if (!ajaxObjs || !fn) {
    return;
  }
  var ajaxCount = ajaxObjs.length,
    succ = null;

  for (var i = 0; i < ajaxObjs.length; i++) { //append logic to invoke callback function once all the ajax calls are completed, in success handler.
    succ = ajaxObjs[i]['success'];
    ajaxObjs[i]['success'] = function(data) { //modified success handler
      if (succ) {
        succ(data);
      }
      ajaxCount--;
      if (ajaxCount == 0) {
        fn(); //modify statement suitably if you want 'this' keyword to refer to another object
      }
    };
    $.ajax(ajaxObjs[i]); //make ajax call
    succ = null;
  };

: ตัวอย่างการใช้งานฟังก์ชั่น doSomethinguntilAjax

function doSomething() {
  // variable declarations
  untilAjax([{
    url: 'url2',
    dataType: 'json',
    success: function(data) {
      //do something with success data
    }
  }, {
    url: 'url1',
    dataType: 'json',
    success: function(data) {
      //do something with success data
    }
  }, {
    url: 'url2',
    dataType: 'json',
    success: function(response) {
      //do something with success data
    }
  }], function() {
    // logic after all the calls are completed.
  });
}

2

ฉันขอแนะนำให้ใช้$. เมื่อ ()ถ้าคุณเริ่มต้นจากศูนย์

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

เราสามารถใช้ประโยชน์จาก jQuery .data, .onและ.triggerฟังก์ชั่นที่ได้เป็นส่วนหนึ่งของ jQuery ตั้งแต่ตลอดไป

Codepen

สิ่งที่ดีเกี่ยวกับโซลูชันของฉันคือ:

  • เห็นได้ชัดว่าการติดต่อกลับขึ้นอยู่กับอะไร

  • ฟังก์ชั่นtriggerNowOrOnLoadedไม่สนใจว่าข้อมูลถูกโหลดไปแล้วหรือเรายังรออยู่

  • มันง่ายมากที่จะเสียบเข้ากับโค้ดที่มีอยู่

$(function() {

  // wait for posts to be loaded
  triggerNowOrOnLoaded("posts", function() {
    var $body = $("body");
    var posts = $body.data("posts");

    $body.append("<div>Posts: " + posts.length + "</div>");
  });


  // some ajax requests
  $.getJSON("https://jsonplaceholder.typicode.com/posts", function(data) {
    $("body").data("posts", data).trigger("posts");
  });

  // doesn't matter if the `triggerNowOrOnLoaded` is called after or before the actual requests 
  $.getJSON("https://jsonplaceholder.typicode.com/users", function(data) {
    $("body").data("users", data).trigger("users");
  });


  // wait for both types
  triggerNowOrOnLoaded(["posts", "users"], function() {
    var $body = $("body");
    var posts = $body.data("posts");
    var users = $body.data("users");

    $body.append("<div>Posts: " + posts.length + " and Users: " + users.length + "</div>");
  });

  // works even if everything has already loaded!
  setTimeout(function() {

    // triggers immediately since users have been already loaded
    triggerNowOrOnLoaded("users", function() {
      var $body = $("body");
      var users = $body.data("users");

      $body.append("<div>Delayed Users: " + users.length + "</div>");
    });

  }, 2000); // 2 seconds

});

// helper function
function triggerNowOrOnLoaded(types, callback) {
  types = $.isArray(types) ? types : [types];

  var $body = $("body");

  var waitForTypes = [];
  $.each(types, function(i, type) {

    if (typeof $body.data(type) === 'undefined') {
      waitForTypes.push(type);
    }
  });

  var isDataReady = waitForTypes.length === 0;
  if (isDataReady) {
    callback();
    return;
  }

  // wait for the last type and run this function again for the rest of the types
  var waitFor = waitForTypes.pop();
  $body.on(waitFor, function() {
    // remove event handler - we only want the stuff triggered once
    $body.off(waitFor);

    triggerNowOrOnLoaded(waitForTypes, callback);
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>Hi!</body>


2

ฉันใช้การตรวจสอบขนาดเมื่อโหลด ajax ทั้งหมดเสร็จสิ้น

function get_ajax(link, data, callback) {
    $.ajax({
        url: link,
        type: "GET",
        data: data,
        dataType: "json",
        success: function (data, status, jqXHR) {
            callback(jqXHR.status, data)
        },
        error: function (jqXHR, status, err) {
            callback(jqXHR.status, jqXHR);
        },
        complete: function (jqXHR, status) {
        }
    })
}

function run_list_ajax(callback){
    var size=0;
    var max= 10;
    for (let index = 0; index < max; index++) {
        var link = 'http://api.jquery.com/ajaxStop/';
        var data={i:index}
        get_ajax(link,data,function(status, data){
            console.log(index)
            if(size>max-2){
                callback('done')
            }
            size++
            
        })
    }
}

run_list_ajax(function(info){
    console.log(info)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>


ยกนิ้วให้กับตัวอย่างของคุณ
MarwaAhmad

2

เพื่อขยายคำตอบของอเล็กซ์ฉันมีตัวอย่างที่มีข้อโต้แย้งและสัญญา ฉันต้องการโหลดภาพผ่าน ajax และแสดงภาพบนหน้าเว็บหลังจากโหลดเสร็จแล้ว

ในการทำเช่นนั้นฉันใช้สิ่งต่อไปนี้:

let urlCreator = window.URL || window.webkitURL;

// Helper function for making ajax requests
let fetch = function(url) {
    return $.ajax({
        type: "get",
        xhrFields: {
            responseType: "blob"
        },
        url: url,
    });
};

// Map the array of urls to an array of ajax requests
let urls = ["https://placekitten.com/200/250", "https://placekitten.com/300/250"];
let files = urls.map(url => fetch(url));

// Use the spread operator to wait for all requests
$.when(...files).then(function() {
    // If we have multiple urls, then loop through
    if(urls.length > 1) {
        // Create image urls and tags for each result
        Array.from(arguments).forEach(data => {
            let imageUrl = urlCreator.createObjectURL(data[0]);
            let img = `<img src=${imageUrl}>`;
            $("#image_container").append(img);
        });
    }
    else {
        // Create image source and tag for result
        let imageUrl = urlCreator.createObjectURL(arguments[0]);
        let img = `<img src=${imageUrl}>`;
        $("#image_container").append(img);
    }
});

อัปเดตเพื่อใช้งาน URL เดียวหรือหลาย URL: https://jsfiddle.net/euypj5w9/


2

ตามคำตอบอื่น ๆ ที่กล่าวถึงคุณสามารถใช้ajaxStop()เพื่อรอจนกว่าคำขอ ajax ทั้งหมดจะเสร็จสมบูรณ์

$(document).ajaxStop(function() {
     // This function will be triggered every time any ajax request is requested and completed
});

หากคุณต้องการทำajax()ตามคำขอเฉพาะสิ่งที่ดีที่สุดที่คุณสามารถทำได้คือใช้complete()วิธีการภายในคำขอ ajax ที่แน่นอน:

$.ajax({
    type: "POST",
    url: "someUrl",
    success: function(data) {
        // This function will be triggered when ajax returns a 200 status code (success)
    },
    complete: function() {
        // This function will be triggered always, when ajax request is completed, even it fails/returns other status code
    },
    error: function() {
        // This will be triggered when ajax request fail.
    }
});


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

// Note:
// resolve() is used to mark the promise as resolved
// reject() is used to mark the promise as rejected

$(document).ready(function() {
    $("button").on("click", function() {

        var ajax1 = new Promise((resolve, reject) => {
            $.ajax({
                type: "GET",
                url: "https://miro.medium.com/max/1200/0*UEtwA2ask7vQYW06.png",
                xhrFields: { responseType: 'blob'},
                success: function(data) {
                    setTimeout(function() {
                        $('#image1').attr("src", window.URL.createObjectURL(data));
                        resolve(" Promise ajax1 resolved");
                    }, 1000);
                },
                error: function() {
                    reject(" Promise ajax1 rejected");
                },
            });
        });

        var ajax2 = new Promise((resolve, reject) => {
            $.ajax({
                type: "GET",
                url: "https://cdn1.iconfinder.com/data/icons/social-media-vol-1-1/24/_github-512.png",
                xhrFields: { responseType: 'blob' },
                success: function(data) {
                    setTimeout(function() {
                         $('#image2').attr("src", window.URL.createObjectURL(data));
                         resolve(" Promise ajax2 resolved");
                    }, 1500);
                },
                error: function() {
                    reject(" Promise ajax2 rejected");
                },
            });
        });

        var ajax3 = new Promise((resolve, reject) => {
            $.ajax({
                type: "GET",
                url: "https://miro.medium.com/max/632/1*LUfpOf7teWvPdIPTBmYciA.png",
                xhrFields: { responseType: 'blob' },
                success: function(data) {
                    setTimeout(function() {
                         $('#image3').attr("src", window.URL.createObjectURL(data));
                         resolve(" Promise ajax3 resolved");
                    }, 2000);
                },
                error: function() {
                    reject(" Promise ajax3 rejected");
                },
            });
        });
        
        Promise.all([ajax1, ajax2, ajax3]).then(values => {
            console.log("We waited until ajax ended: " + values);
            console.log("My few ajax ended, lets do some things!!")
        }, reason => {
            console.log("Promises failed: " + reason);
        });
        
        // Or if you want wait for them individually do it like this
        // ajax1.then(values => {
        //    console.log("Promise 1 resolved: " + values)
        // }, reason => {
        //     console.log("Promise 1 failed: " + reason)
        // });
    });

});
img {
  max-width: 200px;
  max-height: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Make AJAX request</button>
<div id="newContent">
    <img id="image1" src="">
    <img id="image2" src="">
    <img id="image3" src="">
</div>


0

ฉันพบวิธีที่ง่ายมันใช้ shift()

function waitReq(id)
{
  jQuery.ajax(
  {
    type: 'POST',
    url: ajaxurl,
    data:
    {
      "page": id
    },
    success: function(resp)
    {
      ...........
      // check array length if not "0" continue to use next array value
      if(ids.length)
      {
        waitReq(ids.shift()); // 2
      )
    },
    error: function(resp)
    {
      ....................
      if(ids.length)
      {
        waitReq(ids.shift());
      )
    }
  });
}

var ids = [1, 2, 3, 4, 5];    
// shift() = delete first array value (then print)
waitReq(ids.shift()); // print 1

0

ทางออกของฉันมีดังนี้

var request;
...
'services': {
  'GetAddressBookData': function() {
    //This is the primary service that loads all addressbook records 
    request = $.ajax({
      type: "POST",
      url: "Default.aspx/GetAddressBook",
      contentType: "application/json;",
      dataType: "json"
    });
  },

  ...

  'apps': {
    'AddressBook': {
      'data': "",
      'Start': function() {
          ...services.GetAddressBookData();
          request.done(function(response) {
            trace("ajax successful");
            ..apps.AddressBook.data = response['d'];
            ...apps.AddressBook.Filter();
          });
          request.fail(function(xhr, textStatus, errorThrown) {
            trace("ajax failed - " + errorThrown);
          });

ทำงานค่อนข้างดี ฉันพยายามทำสิ่งต่าง ๆ มากมาย แต่ฉันคิดว่านี่เป็นวิธีที่ง่ายที่สุดและใช้ซ้ำได้มากที่สุด หวังว่ามันจะช่วย


0

ดูวิธีแก้ปัญหาของฉัน:

1. ใส่ฟังก์ชั่นนี้ (และตัวแปร) ลงในไฟล์จาวาสคริปต์ของคุณ:

var runFunctionQueue_callback;

function runFunctionQueue(f, index, callback) {

  var next_index = index + 1

  if (callback !== undefined) runFunctionQueue_callback = callback;

  if (f[next_index] !== undefined) {
    console.log(index + ' Next function avalaible -> ' + next_index);
    $.ajax({
      type: 'GET',
      url: f[index].file,
      data: (f[index].data),
      complete: function() {
        runFunctionQueue(f, next_index);
      }
    });
  } else {
    console.log(index + ' Last function');
    $.ajax({
      type: 'GET',
      url: f[index].file,
      data: (f[index].data),
      async: false,
      complete: runFunctionQueue_callback
    });
  }
}

2. สร้างอาร์เรย์ด้วยคำขอของคุณเช่นนี้:

var f = [
           {file: 'file_path', data: {action: 'action', data: 'any_data}},
           {file: 'file_path', data: {action: 'action', data: 'any_data}},
           {file: 'file_path', data: {action: 'action', data: 'any_data}},
           {file: 'file_path', data: {action: 'action', data: 'any_data}}
        ];

3. สร้างฟังก์ชั่นการโทรกลับ:

function Function_callback() {
  alert('done');
}

4. เรียกใช้ฟังก์ชัน runFunctionQueue พร้อมพารามิเตอร์:

runFunctionQueue(f, 0, QuestionInsert_callback);
// first parameter: array with requests data
// second parameter: start from first request
// third parameter: the callback function


-4

ลองด้วยวิธีนี้ สร้าง loop ภายในฟังก์ชันจาวาสคริปต์เพื่อรอจนกระทั่งการโทร ajax เสร็จสิ้น

function getLabelById(id)
{
    var label = '';
    var done = false;
    $.ajax({
       cache: false,
       url: "YourMvcActionUrl",
       type: "GET",
       dataType: "json",
       async: false,
       error: function (result) {
         label='undefined';
         done = true;
        },
       success: function (result) {
            label = result.Message;
            done = true;
        }
     });

   //A loop to check done if ajax call is done.
   while (!done)
   {
      setTimeout(function(){ },500); // take a sleep.
   }

    return label;
}

1
คุณไม่ได้setTimeout() take a sleepในกรณีนี้คุณเพียงปิดกั้นแท็บทั้งหมดจนกว่าdoneจะเป็นจริง
Alexis Wilke

1
ผมคิดว่าเป็นเรื่องนี้ขอให้ "รอจนกระทั่งคำขอ jQuery Ajax จะทำ"
ChinaHelloWorld

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