2011-01-24 24 views
44

Sto usando jQuery.queue() per la prima volta e non l'ho afferrato del tutto. Qualcuno potrebbe per favore indicare cosa sto facendo male?Richieste code ajax utilizzando jQuery.queue()

Guardando in firebug sto ancora vedendo sparare allo stesso tempo le mie richieste POST, quindi mi chiedo se sto chiamando dequeue() nel posto sbagliato.

Inoltre, come posso ottenere la lunghezza della coda?

Il motivo per cui ho bisogno di accodare queste richieste è che viene attivato al clic di un pulsante. E 'possibile che l'utente faccia clic su più pulsanti in rapida successione.

provato per togliere la struttura di base del mio codice:

$("a.button").click(function(){ 
    $(this).doAjax(params); 
}); 

// method 
doAjax:function(params){ 

    $(document).queue("myQueueName", function(){ 
    $.ajax({ 
     type: 'POST', 
     url: 'whatever.html', 
     params: params, 
     success: function(data){ 
     doStuff; 

     $(document).dequeue("myQueueName"); 
     } 
    }); 
    }); 

} 
+3

Questo [risposta] (http: // StackOverflow.it/questions/1058158/can-somebody-explain-jquery-queue-to-me/3314877 # 3314877), anch'esso su StackOverflow, offre una grande serie di esempi, incluso il suo uso con le chiamate ajax. – jmbucknall

+0

Ho effettivamente provato questo approccio, ma non ho potuto farlo funzionare. Vedo che non usa un dequeue() e mi chiedo se questo potrebbe essere stato il mio problema? – MBax

+0

Immagino che next() stia facendo la stessa cosa di dequeue? – MBax

risposta

77

problema qui è, che .ajax() incendi un asincroni in esecuzione richiesta Ajax. Ciò significa che .ajax() restituisce immediatamente, non bloccante. Quindi la tua coda le funzioni ma spareranno quasi contemporaneamente come hai descritto tu.

Non penso che lo .queue() sia un buon posto per richiedere richieste Ajax, è più destinato all'uso di fx methods. Hai bisogno di un semplice manager.

var ajaxManager = (function() { 
    var requests = []; 

    return { 
     addReq: function(opt) { 
      requests.push(opt); 
     }, 
     removeReq: function(opt) { 
      if($.inArray(opt, requests) > -1) 
       requests.splice($.inArray(opt, requests), 1); 
     }, 
     run: function() { 
      var self = this, 
       oriSuc; 

      if(requests.length) { 
       oriSuc = requests[0].complete; 

       requests[0].complete = function() { 
        if(typeof(oriSuc) === 'function') oriSuc(); 
        requests.shift(); 
        self.run.apply(self, []); 
       }; 

       $.ajax(requests[0]); 
      } else { 
       self.tid = setTimeout(function() { 
       self.run.apply(self, []); 
       }, 1000); 
      } 
     }, 
     stop: function() { 
      requests = []; 
      clearTimeout(this.tid); 
     } 
    }; 
}()); 

Questo è lontano dall'essere perfetto, voglio solo dimostrare la strada da percorrere. L'esempio di cui sopra potrebbe essere utilizzato in un modo come

$(function() { 
    ajaxManager.run(); 

    $("a.button").click(function(){ 
     ajaxManager.addReq({ 
      type: 'POST', 
      url: 'whatever.html', 
      data: params, 
      success: function(data){ 
       // do stuff 
      } 
     }); 
    }); 
}); 
+4

+1 per la corretta diagnosi. –

+0

ha, mi sono appena reso conto che hai nominato la tua funzione come il plugin che sto suggerendo. –

+0

@nathan: grazie, oh davvero - non sapevo del tuo post, avevo 4 minuti di anticipo :) – jAndy

6

ho trovato la soluzione sopra un po 'complicato, più ho bisogno di modificare la richiesta poco prima dell'invio (per aggiornare un gettone di dati freschi).

Quindi ho messo questo insieme. Fonte: https://gist.github.com/2470554

/* 

Allows for ajax requests to be run synchronously in a queue 

Usage:: 

var queue = new $.AjaxQueue(); 

queue.add({ 
    url: 'url', 
    complete: function() { 
    console.log('ajax completed'); 
    }, 
    _run: function(req) { 
    //special pre-processor to alter the request just before it is finally executed in the queue 
    req.url = 'changed_url' 
    } 
}); 

*/ 

$.AjaxQueue = function() { 
    this.reqs = []; 
    this.requesting = false; 
}; 
$.AjaxQueue.prototype = { 
    add: function(req) { 
    this.reqs.push(req); 
    this.next(); 
    }, 
    next: function() { 
    if (this.reqs.length == 0) 
     return; 

    if (this.requesting == true) 
     return; 

    var req = this.reqs.splice(0, 1)[0]; 
    var complete = req.complete; 
    var self = this; 
    if (req._run) 
     req._run(req); 
    req.complete = function() { 
     if (complete) 
     complete.apply(this, arguments); 
     self.requesting = false; 
     self.next(); 
    } 

    this.requesting = true; 
    $.ajax(req); 
    } 
}; 
+6

Si prega di inserire il codice (o almeno parte rilevante di esso) anche qui. Per quanto ne sappiamo, Github potrebbe essere giù domani per non tornare più e questo post diventerà privo di significato. –

10

avevo bisogno di fare una cosa simile così ho pensato di postare la mia soluzione qui.

Fondamentalmente quello che ho è una pagina che elenca i progetti sugli scaffali che hanno tutti criteri distintivi. Volevo caricare gli scaffali uno per uno piuttosto che del tutto per rendere più veloce all'utente il contenuto che potevano guardare mentre il resto caricava.

Fondamentalmente ho archiviato l'ID di ogni scaffale in un array JS che uso quando li chiamo da PHP.

Ho quindi creato una funzione ricorsiva che farà scoppiare il primo indice fuori dall'array ogni volta che viene richiamato e richiede lo shelf per l'id visualizzato. Una volta ricevuta la risposta dallo $.get() o $.post(), quale preferisco usare, chiamo la funzione ricorsiva dall'interno del callback.

Ecco un'elaborazione in codice:

// array of shelf IDs 
var shelves = new Array(1,2,3,4); 

// the recursive function 
function getShelfRecursive() { 

    // terminate if array exhausted 
    if (shelves.length === 0) 
     return; 

    // pop top value 
    var id = shelves[0]; 
    shelves.shift(); 

    // ajax request 
    $.get('/get/shelf/' + id, function(){ 
     // call completed - so start next request 
     getShelfRecursive(); 
    }); 
} 

// fires off the first call 
getShelfRecursive(); 
+0

Per inserire il valore più alto, potresti aver usato 'var id = shelves.pop();'. Quindi non avresti bisogno di seguire con un esplicito '.shift()'; – AntonChanning

+0

Oppure, se si volesse la fine '.shift()', si sarebbe potuto usare 'var id = shelves.shift();' – AntonChanning

0

ho avuto anche a che fare questo all'interno di una soluzione che ho avuto e ho trovato che potrei fare in questo modo:

//A variable for making sure to wait for multiple clicks before emptying. 
var waitingTimeout; 

$("a.button").click(function(){ 
    $(this).doAjax(params); 
    clearTimeout(waitingTimeout); 
    waitingTimeout = setTimeout(function(){noMoreClicks();},1000); 
}); 

// method 
doAjax:function(params){ 

    $(document).queue("myQueueName", function(next){ 
    $.ajax({ 
     type: 'POST', 
     url: 'whatever.html', 
     data: params, 
     contentType: "application/json; charset=utf-8", 
     dataType: "json", 
     success: function(data){ 
     doStuff; 
     next(); 
     }, 
     failure: function(data){ 
     next(); 
     }, 
     error: function(data){ 
     next(); 
     } 
    }); 
    }); 

} 

function noMoreClicks(){ 
    $(document).dequeue("myQueueName"); 
} 

utilizzando il next() callback che viene passato nella funzione della coda è possibile deselezionare la prossima operazione.Quindi, inserendo il prossimo nei gestori per l'ajax, si fa in modo efficace che le chiamate ajax siano asincrone per il browser e il rendering o il thread di disegno del browser, ma rendendole sincrone o serializzate l'una con l'altra.

Here is a very basic example. Nell'esempio di violino. Fare clic sul pulsante una volta e attendere un secondo. Vedrai che il timeout si innesca e si verifica la singola operazione. Quindi fai clic sul pulsante il più velocemente possibile (o più veloce di un secondo) e vedrai che tutte le volte che fai clic sul pulsante, le operazioni vengono messe in coda e solo dopo aver atteso un secondo colpiscono la pagina e si dissolvono in una dopo l'altro.

Il bello è che se la coda si sta già svuotando, tutte le operazioni che si aggiungono mentre si sta svuotando vengono posizionate alla fine e quindi elaborate solo quando arriva il momento.

6

Avevo bisogno di farlo per un numero sconosciuto di chiamate Ajax. La risposta è stata di spingere ciascuno in una matrice e quindi utilizzare:

$.when.apply($, arrayOfDeferreds).done(function() { 
    alert("All done"); 
}); 
+0

non le chiamate di ajax si attivano immediatamente quando vengono spinte sull'array. Ad esempio, 'var arr = []; arr.push ($. get (...)); 'emetterebbe immediatamente la chiamata GET? –

+0

potresti fare un esempio più completo? – brauliobo

-1

ho avuto un problema simile,

se non che l'importazione a voi che il ajax-chiamata è asincrona (anche se questo è il "a" di ajax) puoi semplicemente dire a jQuery di fare la richiesta ajax non asincrona. questo ha funzionato per me e non porta la necessità di una soluzione più grande.

$.ajax({ 
     ... 
     async: false 
    }); 

Devo dire che questo è deprecato dal jQuery 1.8 e non funzionerà con dataType: 'jsonp'.

+4

utilizzando async: false non è buono ... – msqar

+0

Questo blocca il browser – brauliobo

2

Il sito learn.jquery.com have a good example too:

// jQuery on an empty object, we are going to use this as our queue 
var ajaxQueue = $({}); 

$.ajaxQueue = function(ajaxOpts) { 
    // Hold the original complete function 
    var oldComplete = ajaxOpts.complete; 

    // Queue our ajax request 
    ajaxQueue.queue(function(next) { 
    // Create a complete callback to invoke the next event in the queue 
    ajaxOpts.complete = function() { 
     // Invoke the original complete if it was there 
     if (oldComplete) { 
     oldComplete.apply(this, arguments); 
     } 

     // Run the next query in the queue 
     next(); 
    }; 

    // Run the query 
    $.ajax(ajaxOpts); 
    }); 
}; 

// Get each item we want to copy 
$("#items li").each(function(idx) { 
    // Queue up an ajax request 
    $.ajaxQueue({ 
    url: "/ajax_html_echo/", 
    data: { 
     html: "[" + idx + "] " + $(this).html() 
    }, 
    type: "POST", 
    success: function(data) { 
     // Write to #output 
     $("#output").append($("<li>", { 
     html: data 
     })); 
    } 
    }); 
}); 
3

si potrebbe estendere jQuery:

(function($) { 
    // Empty object, we are going to use this as our Queue 
    var ajaxQueue = $({}); 

    $.ajaxQueue = function(ajaxOpts) { 
    // hold the original complete function 
    var oldComplete = ajaxOpts.complete; 

    // queue our ajax request 
    ajaxQueue.queue(function(next) {  

     // create a complete callback to fire the next event in the queue 
     ajaxOpts.complete = function() { 
     // fire the original complete if it was there 
     if (oldComplete) oldComplete.apply(this, arguments);  
     next(); // run the next query in the queue 
     }; 

     // run the query 
     $.ajax(ajaxOpts); 
    }); 
    }; 

})(jQuery); 

poi utilizzarlo come:

$.ajaxQueue({ 
    url: 'doThisFirst.php', 
    async: true, 
    success: function (data) { 
     //success handler 
    }, 
    error: function (jqXHR,textStatus,errorThrown) { 
     //error Handler 
    }  
}); 
$.ajaxQueue({ 
    url: 'doThisSecond.php', 
    async: true, 
    success: function (data) { 
     //success handler 
    }, 
    error: function (jqXHR,textStatus,errorThrown) { 
     //error Handler 
    }  
}); 

naturalmente è possibile utilizzare qualsiasi delle altre opzioni $ .ajax come tipo, data, contentType, DataType da quando stiamo estendendo $ .ajax

+0

soluzione RAD. Per testare l'accodamento ho aggiunto un secondo di sonno nel mio codice PHP e ho accodato quante più richieste AJAX possibile. Ognuno ha finito come previsto. Prima che salisse e salta un paio risparmia. Molto bello – Jibran

3

Un'altra versione della risposta di jAndy, senza timer.

var ajaxManager = { 
    requests: [], 
    addReq: function(opt) { 
     this.requests.push(opt); 

     if (this.requests.length == 1) { 
      this.run(); 
     } 
    }, 
    removeReq: function(opt) { 
     if($.inArray(opt, requests) > -1) 
      this.requests.splice($.inArray(opt, requests), 1); 
    }, 
    run: function() { 
     // original complete callback 
     oricomplete = this.requests[0].complete; 

     // override complete callback 
     var ajxmgr = this; 
     ajxmgr.requests[0].complete = function() { 
      if (typeof oricomplete === 'function') 
       oricomplete(); 

      ajxmgr.requests.shift(); 
      if (ajxmgr.requests.length > 0) { 
       ajxmgr.run(); 
      } 
     }; 

     $.ajax(this.requests[0]); 
    }, 
    stop: function() { 
     this.requests = []; 
    }, 
} 

da usare:

$(function() { 
    $("a.button").click(function(){ 
     ajaxManager.addReq({ 
      type: 'POST', 
      url: 'whatever.html', 
      data: params, 
      success: function(data){ 
       // do stuff 
      } 
     }); 
    }); 
}); 
+0

Come fare la coda .getJSON invece di ajax? –

+0

Glbert, puoi aiutarmi con questo: http://stackoverflow.com/questions/35540856/jquery-many-functions-for-many-rows-how-to-manage? –

0

Qui è la mia soluzione, che io uso per la produzione di una coda di richieste di alcuni Browsergame. Se succede qualcosa, interrompo questa coda e finisco il lavoro con qualche ultima richiesta speciale o pulizia.

var get_array = ["first", "second", "third"]; 

var worker = $("<div />"); // to line up requests in queue 
$.queuedAjax = function(args){ // add up requests for me  
    worker.queue(
     function(next){ 
      $.ajax(args).always(next);    
     } 
    ); 
    }; 

$.queuedSomething = function(){ // add up something special for me 
    worker.queue(
     function(next){ 
      //worker.clearQueue(); 
      //worker = $("<div />"); //cleanup for next .each 
      //maybe another .each   
     } 
    ); 
    }; 

$.each(get_array , function(key , value) { 
    $.queuedAjax({ 
    type: 'GET', 
    url: '/some.php?get='+value, 
    dataType: 'text', 
    success: function(sourcecode){ 

     if (sourcecode.match(/stop your requests, idiot!/)) { 
      worker.clearQueue().queue($.queuedSomething); 
      alert(' the server told me to stop. i stopped all but not the last ´$.queuedSomething()´ '); 
     } 

    } 
    });   
}); 
$.queuedSomething(); 
5

Io uso questo codice molto semplice per mantenere le chiamate ajax da "sorpasso" a vicenda.

var dopostqueue = $({}); 
function doPost(string, callback) 
{ 
    dopostqueue.queue(function() 
    { 
     $.ajax(
     { 
      type: 'POST', 
      url: 'thephpfile.php', 
      datatype: 'json', 
      data: string, 
      success:function(result) 
      { 
       dopostqueue.dequeue(); 
       callback(JSON.parse(result)); 
      } 
     }) 
    }); 
} 

Se non si desidera la coda per gestire se stessa, si può semplicemente rimuovere il dequeue dalla funzione e chiamare da un'altra funzione. Come per ottenere la lunghezza della coda, per questo esempio sarebbe:

dopostqueue.queue().length 
Problemi correlati