JQuery का उपयोग करके विफलता पर AJAX अनुरोध का पुनः प्रयास करने का सबसे अच्छा तरीका क्या है?


107

छद्म कोड:

$(document).ajaxError(function(e, xhr, options, error) {
  xhr.retry()
})

इससे भी बेहतर यह होगा कि किसी तरह का एक्सपोनेंशियल बैक-ऑफ हो


1
मुझे यकीन नहीं है कि यह सबसे अच्छा तरीका है, तो बस एक टिप्पणी है, लेकिन अगर आप अपने ajax को एक fucntion से बुलाते हैं, तो आप इसे एक पैरामीटर दे सकते हैं tries, और असफल होने पर आप अपने फ़ंक्शन को कॉल कर सकते हैं tries+1tries==3या किसी अन्य नंबर पर निष्पादन रोकें ।
41 पर नन्ने

संभव डुप्लिकेट के संभव डुप्लिकेट एक jquery ajax रिक्वेस्ट जिसमें उसके
डिफरेंट

जवाबों:


238

कुछ इस तरह:


$.ajax({
    url : 'someurl',
    type : 'POST',
    data :  ....,   
    tryCount : 0,
    retryLimit : 3,
    success : function(json) {
        //do something
    },
    error : function(xhr, textStatus, errorThrown ) {
        if (textStatus == 'timeout') {
            this.tryCount++;
            if (this.tryCount <= this.retryLimit) {
                //try again
                $.ajax(this);
                return;
            }            
            return;
        }
        if (xhr.status == 500) {
            //handle error
        } else {
            //handle error
        }
    }
});

12
मैंने @ सुधीर के समाधान को लिया है और यहाँ github पर $ .retryAjax प्लगइन बनाया है: github.com/mberkom/jQuery.retryAjax
माइकल बेरकोम्पास

2
यह मेरे लिए काम नहीं कर रहा है। सशर्त में यह.
tryCount

2
@MichaelBerkompas - क्या आपका प्लगइन अभी भी काम करता है? यह 2 साल में कमिट नहीं हुआ है।
हेंड्रिक

2
क्या यह काम करेगा यदि एक अन्य कॉलबैक हैंडलर .successइस ajax अनुरोध को वापस करने वाले फ़ंक्शन को कॉल करने से जुड़ा हुआ है?
समस्याएंऑफसिट

17
की जोड़ी tryCountऔर retryLimitअत्यधिक है। केवल 1 चर का उपयोग करने पर विचार करें:this.retryLimit--; if (this.retryLimit) { ... $.ajax(this) ... }
vladkras

15

रैपर फ़ंक्शन का उपयोग करने के लिए एक दृष्टिकोण है:

(function runAjax(retries, delay){
  delay = delay || 1000;
  $.ajax({
    type        : 'GET',
    url         : '',
    dataType    : 'json',
    contentType : 'application/json'
  })
  .fail(function(){
    console.log(retries); // prrint retry count
    retries > 0 && setTimeout(function(){
        runAjax(--retries);
    },delay);
  })
})(3, 100);

एक अन्य दृष्टिकोण के लिए एक retriesसंपत्ति का उपयोग करना होगा$.ajax

// define ajax settings
var ajaxSettings = {
  type        : 'GET',
  url         : '',
  dataType    : 'json',
  contentType : 'application/json',
  retries     : 3  //                 <-----------------------
};

// run initial ajax
$.ajax(ajaxSettings).fail(onFail)

// on fail, retry by creating a new Ajax deferred
function onFail(){
  if( ajaxSettings.retries-- > 0 )
    setTimeout(function(){
        $.ajax(ajaxSettings).fail(onFail);
    }, 1000);
}

दूसरा तरीका ( GIST ) - ओवरराइड मूल $.ajax(DRY के लिए बेहतर)

// enhance the original "$.ajax" with a retry mechanism 
$.ajax = (($oldAjax) => {
  // on fail, retry by creating a new Ajax deferred
  function check(a,b,c){
    var shouldRetry = b != 'success' && b != 'parsererror';
    if( shouldRetry && --this.retries > 0 )
      setTimeout(() => { $.ajax(this) }, this.retryInterval || 100);
  }

  return settings => $oldAjax(settings).always(check)
})($.ajax);



// now we can use the "retries" property if we need to retry on fail
$.ajax({
    type          : 'GET',
    url           : 'http://www.whatever123.gov',
    timeout       : 2000,
    retries       : 3,     //       <-------- Optional
    retryInterval : 2000   //       <-------- Optional
})
// Problem: "fail" will only be called once, and not for each retry
.fail(()=>{
  console.log('failed') 
});

एक बिंदु पर विचार करना सुनिश्चित कर रहा है कि$.ajax दो बार चल रहे समान कोड से बचने के लिए विधि पहले से ही लपेटी नहीं गई थी।


आप इन स्निपेट्स (जैसे-है) को कॉपी करके उन्हें जांचने के लिए कंसोल पर चिपका सकते हैं


स्क्रिप्ट के लिए धन्यवाद। क्या यह $ .ajaxSetup के साथ काम करता है?
सेवबन Sevटेचर्क

@ सेवबन ?टरकॉक - आपका क्या मतलब है? बस कोशिश करें :)
vsync

कैसे एक आवरण की संरचना करने के लिए मुझे सिखाने के लिए धन्यवाद! यह पुरानी पुनरावर्ती फ़ंक्शन डिज़ाइन को धड़कता है जिसे मैंने लागू करने के लिए उपयोग किया था।
डिकोडर 7283

7

मुझे इस कोड के साथ बहुत सी सफलता मिली है (उदाहरण: http://jsfiddle.net/uZSFK/ )

$.ajaxSetup({
    timeout: 3000, 
    retryAfter:7000
});

function func( param ){
    $.ajax( 'http://www.example.com/' )
        .success( function() {
            console.log( 'Ajax request worked' );
        })
        .error(function() {
            console.log( 'Ajax request failed...' );
            setTimeout ( function(){ func( param ) }, $.ajaxSetup().retryAfter );
        });
}

4
एकमात्र बदलाव जो मैं सुझाऊंगा वह है 'फंक ("+ + परम" "") को फंक्शन () {फंक (परम)} से बदलना। इस तरह, आप सीधे स्ट्रिंग और बैक में कनवर्ट किए बिना पैरामीटर पास कर सकते हैं। , जो बहुत आसानी से विफल हो सकता है!
fabspro

@fabspro किया। धन्यवाद!
नबील कादिमी

7
क्या यह अंतहीन लूप नहीं है? यह देखते हुए कि प्रश्न में पुनः प्रयास है और स्पष्ट रूप से सर्वर को वापस आने के लिए पूरा करने की इच्छा है ... मुझे लगता है कि यह वास्तव में होना है
पांडावुड

3
jQuery.ajaxSetup () विवरण: भविष्य के अजाक्स अनुरोधों के लिए डिफ़ॉल्ट मान सेट करें। इसके उपयोग की अनुशंसा नहीं की जाती है। api.jquery.com/jQuery.ajaxSetup
blub

2

इनमें से कोई भी उत्तर काम नहीं करता है यदि कोई व्यक्ति .done()अपने ajax कॉल के बाद कॉल करता है क्योंकि आपके पास भविष्य के कॉल बैक को संलग्न करने के लिए सफलता की विधि नहीं होगी। तो अगर कोई ऐसा करता है:

$.ajax({...someoptions...}).done(mySuccessFunc);

फिर mySuccessFuncरिट्रीट पर नहीं बुलाया जाएगा। यहाँ मेरा समाधान है, जो यहाँ @jpak के उत्तर से बहुत अधिक उधार लिया गया है । मेरे मामले में जब AWS का एपीआई गेटवे 502 त्रुटि के साथ प्रतिक्रिया करता है तो मैं फिर से प्रयास करना चाहता हूं।

const RETRY_WAIT = [10 * 1000, 5 * 1000, 2 * 1000];

// This is what tells JQuery to retry $.ajax requests
// Ideas for this borrowed from https://stackoverflow.com/a/12446363/491553
$.ajaxPrefilter(function(opts, originalOpts, jqXHR) {
  if(opts.retryCount === undefined) {
    opts.retryCount = 3;
  }

  // Our own deferred object to handle done/fail callbacks
  let dfd = $.Deferred();

  // If the request works, return normally
  jqXHR.done(dfd.resolve);

  // If the request fails, retry a few times, yet still resolve
  jqXHR.fail((xhr, textStatus, errorThrown) => {
    console.log("Caught error: " + JSON.stringify(xhr) + ", textStatus: " + textStatus + ", errorThrown: " + errorThrown);
    if (xhr && xhr.readyState === 0 && xhr.status === 0 && xhr.statusText === "error") {
      // API Gateway gave up.  Let's retry.
      if (opts.retryCount-- > 0) {
        let retryWait = RETRY_WAIT[opts.retryCount];
        console.log("Retrying after waiting " + retryWait + " ms...");
        setTimeout(() => {
          // Retry with a copied originalOpts with retryCount.
          let newOpts = $.extend({}, originalOpts, {
            retryCount: opts.retryCount
          });
          $.ajax(newOpts).done(dfd.resolve);
        }, retryWait);
      } else {
        alert("Cannot reach the server.  Please check your internet connection and then try again.");
      }
    } else {
      defaultFailFunction(xhr, textStatus, errorThrown); // or you could call dfd.reject if your users call $.ajax().fail()
    }
  });

  // NOW override the jqXHR's promise functions with our deferred
  return dfd.promise(jqXHR);
});

यह स्निपेट 2 सेकंड, फिर 5 सेकंड, फिर 10 सेकंड के बाद बैक-ऑफ और फिर से प्रयास करेगा, जिसे आप RETRY_WAIT स्थिरांक को संशोधित करके संपादित कर सकते हैं।

एडब्ल्यूएस समर्थन ने सुझाव दिया कि हम एक रिट्री को जोड़ते हैं, क्योंकि यह हमारे लिए केवल एक बार नीले चंद्रमा में होता है।


मुझे यह अब तक के सभी उत्तरों में सबसे अधिक उपयोगी लगा। हालाँकि, अंतिम पंक्ति टाइपस्क्रिप्ट में संकलन को रोकती है। मुझे नहीं लगता कि आपको इस फ़ंक्शन से कुछ भी वापस करना चाहिए।
फ्रेडी

0

यहाँ इसके लिए एक छोटा सा प्लगइन है:

https://github.com/execjosh/jquery-ajax-retry

ऑटो इंक्रीमेंटिंग टाइमआउट इसके लिए एक अच्छा अतिरिक्त होगा।

इसे विश्व स्तर पर उपयोग करने के लिए केवल $ .ajax हस्ताक्षर के साथ अपना स्वयं का फ़ंक्शन बनाएं, वहां पुनर्प्रयास एपि का उपयोग करें और अपने सभी $ .ajax कॉल को अपने नए फ़ंक्शन द्वारा प्रतिस्थापित करें।

इसके अलावा, आप सीधे $ .ajax की जगह ले सकते हैं, लेकिन आप बिना रिट्रीट के xhr कॉल नहीं कर पाएंगे।


0

यहाँ वह विधि है जो पुस्तकालयों के अतुल्यकालिक लोडिंग के लिए मेरे लिए काम करती है:

var jqOnError = function(xhr, textStatus, errorThrown ) {
    if (typeof this.tryCount !== "number") {
      this.tryCount = 1;
    }
    if (textStatus === 'timeout') {
      if (this.tryCount < 3) {  /* hardcoded number */
        this.tryCount++;
        //try again
        $.ajax(this);
        return;
      }
      return;
    }
    if (xhr.status === 500) {
        //handle error
    } else {
        //handle error
    }
};

jQuery.loadScript = function (name, url, callback) {
  if(jQuery[name]){
    callback;
  } else {
    jQuery.ajax({
      name: name,
      url: url,
      dataType: 'script',
      success: callback,
      async: true,
      timeout: 5000, /* hardcoded number (5 sec) */
      error : jqOnError
    });
  }
}

फिर बस .load_scriptअपने ऐप से कॉल करें और अपनी सफलता के कॉलबैक को घोंसला दें:

$.loadScript('maps', '//maps.google.com/maps/api/js?v=3.23&libraries=geometry&libraries=places&language=&hl=&region=', function(){
    initialize_map();
    loadListeners();
});

0

डेमो यूजर्स का जवाब Zepto के साथ काम नहीं करता है, क्योंकि यह एरर फंक्शन में विंडो की ओर इशारा करता है। (और 'इस' का उपयोग करने का यह तरीका पर्याप्त सुरक्षित नहीं है क्योंकि आप नहीं जानते हैं कि वे अजाक्स को कैसे लागू करते हैं या इसकी कोई आवश्यकता नहीं है)।

ज़ेप्टो के लिए, शायद आप नीचे की कोशिश कर सकते हैं, अब तक यह मेरे लिए अच्छा काम करता है:

var AjaxRetry = function(retryLimit) {
  this.retryLimit = typeof retryLimit === 'number' ? retryLimit : 0;
  this.tryCount = 0;
  this.params = null;
};
AjaxRetry.prototype.request = function(params, errorCallback) {
  this.tryCount = 0;
  var self = this;
  params.error = function(xhr, textStatus, error) {
    if (textStatus === 'timeout') {
      self.tryCount ++;
      if (self.tryCount <= self.retryLimit) {
        $.ajax(self.params)      
        return;
      }
    }
    errorCallback && errorCallback(xhr, textStatus, error);
  };
  this.params = params;
  $.ajax(this.params);
};
//send an ajax request
new AjaxRetry(2).request(params, function(){});

निश्‍चित अनुरोध करने के लिए निर्माणकर्ता का उपयोग करें।


0

आपका कोड लगभग पूर्ण है :)

const counter = 0;
$(document).ajaxSuccess(function ( event, xhr, settings ) {
    counter = 0;
}).ajaxError(function ( event, jqxhr, settings, thrownError ) {
    if (counter === 0 /*any thing else you want to check ie && jqxhr.status === 401*/) {
        ++counter;
        $.ajax(settings);
    }
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.