2014-05-06 13 views
6

Ho una casella di controllo che può attivare un determinato comportamento, tuttavia se qualcuno fa 100 clic consecutivi non voglio inviare 100 richieste al mio server.Come debellare correttamente le richieste Ajax

Questo è quello che ho ottenuto in atto finora (trovato questo frammento di codice):

deBouncer = function($,cf,of, interval){ 
    var debounce = function (func, threshold, execAsap) { 
     var timeout; 
     return function debounced() { 
      var obj = this, args = arguments; 
      function delayed() { 
      if (!execAsap) 
       func.apply(obj, args); 
      timeout = null; 
      } 
      if (timeout) 
      clearTimeout(timeout); 
      else if (execAsap) 
      func.apply(obj, args); 
      timeout = setTimeout(delayed, threshold || interval); 
     } 
    } 
    jQuery.fn[cf] = function(fn){ return fn ? this.bind(of, debounce(fn)) : this.trigger(cf); }; 
    }; 

Nel mio documento funzione pronta:

deBouncer(jQuery,'smartoggle', 'click', 1500); 

Poi l'evento stesso:

$(window).smartoggle(function(e){ 
    MyToggleFunction(); 
}); 

Funziona come ho messo 1500 ms per essere il periodo di debouncing, quindi se si fa clic su n volte con 1500 ms verrà inviato solo t è l'ultimo stato del server.

C'è comunque un effetto collaterale sull'uso di questo, ora il mio evento di click per altre cose è incasinato. Sto facendo qualcosa di sbagliato qui? C'è un modo migliore per rimbalzare?

+0

Sei decisamente sulla pista di scrittura qui .. Vorrei solo legare questo evento al segno di spunta in questione però. Ciò potrebbe consentire di semplificare alcune delle altre codifiche. –

+0

@JeremyJStarcher puoi per favore dare un esempio di cosa intendi? –

+0

Avrei bisogno di vedere il tuo markup ... o potrei darti un esempio inventato basato su come lo faccio. –

risposta

2

Non sicuro se ci può essere un modo "corretto" per farlo.

Detto questo sottolineatura ha un programma di utilità che consente di creare una versione della funzione adattato dal ...

var MyToggleDebounced = _.debounce(MyToggleFunction, 1500); 

quindi utilizzare MyToggleDebounced nel vostro gestore di clic.

Link to debounce docs on underscorejs

Date un'occhiata alla fonte commentato per come lo fanno.

8

Basta debounce la funzione che esegue il lavoro effettivo e non caricarei un'intera libreria per questo.

var debouncedSomeFunction = debounce(someFunction, 1500); 
 

 
debouncedSomeFunction(); 
 
debouncedSomeFunction(); 
 
debouncedSomeFunction(); 
 

 
setTimeout(debouncedSomeFunction, 2000); 
 

 

 
function debounce(fn, bufferInterval) { 
 
    var timeout; 
 

 
    return function() { 
 
    clearTimeout(timeout); 
 
    timeout = setTimeout(fn.apply.bind(fn, this, arguments), bufferInterval); 
 
    }; 
 

 
} 
 

 
function someFunction() { 
 
    log('someFunction executed'); 
 
} 
 

 
function log(text) { 
 
    document.body.appendChild(document.createTextNode(text)); 
 
    document.body.appendChild(document.createElement('br')); 
 
}

+0

So che questo è uno pseudo-codice, ma sono davvero confuso su cosa significhi l'ultima riga con la sua auto-referenza. Forse potresti aggiornare la tua risposta mostrando una semplice implementazione di * yourFunction *? Ho provato questo codice e non ho potuto farlo funzionare. – geoidesic

+0

Solo per chiarezza, nel caso in cui qualcun altro fosse confuso dall'ultima riga ... dovrebbe essere * var yourFunction = function() {}; yourFunction = debounce (yourFunction, 1500); – geoidesic

+0

@geoidesic Ho modificato il codice, si spera che sia più facile da capire. – plalx

0

Penso che questa domanda è meglio di quanto possa sembrare prima. C'è un avvertimento su come funzionano le richieste Ajax di Http. Se si imposta il ritardo su 1500 ms, è possibile garantire che ogni richiesta venga pubblicata in questo intervallo di tempo rispetto alle altre risposte. Tuttavia, se una richiesta dovesse rallentare in modo significativo, le richieste potrebbero venire fuori servizio. Se ciò accade, l'ultima richiesta elaborata è quella per cui verranno visualizzati i dati, non l'ultimo inviato.

Ho scritto questa classe per evitare questo avvertimento (a macchina, ma si dovrebbe essere in grado di leggerlo):

export class AjaxSync { 

    private isLoading: boolean = false; 
    private pendingCallback: Function; 
    private timeout; 

    public debounce(time: number, callback: Function): Function { 
    return this.wrapInTimeout(
     time, 
    () => { 
     if (this.isLoading) { 
      this.pendingCallback = callback; 
      return; 
     } 
     this.isLoading = true; 
     callback() 
      .then(() => { 
      this.isLoading = false; 
      if (this.pendingCallback) { 
       const pendingCallback = this.pendingCallback; 
       this.pendingCallback = null; 
       this.debounce(time, pendingCallback); 
      } 
      }); 
     } 
    ); 
    } 

    private wrapInTimeout(time, callback) { 
    return() => { 
     clearTimeout(this.timeout); 
     this.timeout = setTimeout(callback, time); 
    }; 
    } 
} 

Questo consentirà di evitare due AJAX richieste elaborate allo stesso tempo e questo invierà un altro chiedere se c'è uno in sospeso.

Problemi correlati