2009-07-20 42 views
21

Uso jQuery. Y no quiero llamadas AJAX paralelas en mi aplicación, cada llamada debe esperar la anterior antes de comenzar. ¿Cómo implementarlo? Hay algún ayudante?¿Cómo hacer todas las llamadas AJAX secuencialmente?

ACTUALIZACIÓN Si hay alguna versión síncrona de XMLHttpRequest o jQuery.post me gustaría saber. Pero secuencial! = Sincrónico, y me gustaría una solución asíncrona y secuencial.

+4

Usted sabe cuál es la "a" en AJAX significa, a la derecha :-) –

+2

Esto definitivamente i no es una respuesta, pero es un signo interesante de un marco bien diseñado cuando * esta * es la pregunta confusa en lugar de cómo hacerla concurrente. :) –

+8

@Ed Swangren, sí, pero AJAX no tiene que ser asíncrona, JavaScript o XML. :-) – Nosredna

Respuesta

14

Hay una mejor manera de hacer esto que el uso de las llamadas ajax síncronos. Jquery ajax devuelve un diferido por lo que puede utilizar el encadenamiento de tuberías para asegurarse de que cada llamada ajax finaliza antes de las siguientes ejecuciones. Aquí hay un ejemplo de trabajo con un ejemplo más en profundidad que puede play with on jsfiddle.

// How to force async functions to execute sequentially 
// by using deferred pipe chaining. 

// The master deferred. 
var dfd = $.Deferred(), // Master deferred 
    dfdNext = dfd; // Next deferred in the chain 
    x = 0, // Loop index 
    values = [], 

    // Simulates $.ajax, but with predictable behaviour. 
    // You only need to understand that higher 'value' param 
    // will finish earlier. 
    simulateAjax = function (value) { 
     var dfdAjax = $.Deferred(); 

     setTimeout(
      function() { 
       dfdAjax.resolve(value); 
      }, 
      1000 - (value * 100) 
     ); 

     return dfdAjax.promise(); 
    }, 

    // This would be a user function that makes an ajax request. 
    // In normal code you'd be using $.ajax instead of simulateAjax. 
    requestAjax = function (value) { 
     return simulateAjax(value); 
    }; 

// Start the pipe chain. You should be able to do 
// this anywhere in the program, even 
// at the end,and it should still give the same results. 
dfd.resolve(); 

// Deferred pipe chaining. 
// What you want to note here is that an new 
// ajax call will not start until the previous 
// ajax call is completely finished. 
for (x = 1; x <= 4; x++) { 

    values.push(x); 

    dfdNext = dfdNext.pipe(function() { 
     var value = values.shift(); 
     return requestAjax(value). 
      done(function(response) { 
       // Process the response here. 

      }); 

    }); 

} 

Algunas personas han comentado que no tienen idea de lo que hace el código. Para entenderlo, primero necesita comprender las promesas javascript. Estoy bastante seguro de que pronto las promesas serán una característica nativa del lenguaje javascript, por lo que debería darle un buen incentivo para aprender.

+0

Oye, esto es un poco tarde, pero de todos modos: la gran respuesta me ayudó y funciona como un encanto. Pero realmente no entiendo cómo funciona. Traté de entender y leer los documentos, pero esto es un misterio para mí. –

+0

@DanLee Parece que no eres el único. –

+0

Complicaciones de javascript difíciles de entender y la forma en que jquery implementa el concepto sin aprenderlo ;-) Hay muchos documentos por ahí. –

6

Tiene dos opciones que se me ocurren. Una es encadenarlos a través de devoluciones de llamadas. La otra es hacer que las llamadas sean sincrónicas en lugar de asincrónicas.

¿Hay alguna razón por la que desee que sean secuenciales? Eso ralentizará las cosas.

Para sincronizar la llamada, establecerá la opción asincrónica en la llamada Ajax a falso. Consulte la documentación en http://docs.jquery.com/Ajax/jQuery.ajax#options (haga clic en la pestaña de opciones para verlas).

+0

¿Cómo hacerlos sincrónicos? –

+0

O una tercera opción: una clase que gestionaría una cola de solicitudes y las procesaría secuencialmente. –

+0

Edité mi respuesta para señalar las opciones de Ajax. Establezca la opción asíncrona en falso. – Nosredna

1

Mira esto: http://docs.jquery.com/Ajax/jQuery.ajax (haz clic en la pestaña "opciones").

Pero recuerde que una llamada síncrona congelará la página hasta que se reciba la respuesta, por lo que no se puede usar en un sitio de producción, porque los usuarios se enojarán si por alguna razón tienen que esperar 30 segundos con su navegador congelado .

EDIT: OK, con su actualización es más claro lo que quiere lograr;)

Así, el código puede tener este aspecto:

$.getJSON("http://example.com/jsoncall", function(data) { 
     process(data); 
     $.getJSON("http://example.com/jsoncall2", function (data) { 
      processAgain(data); 
      $.getJSON("http://example.com/anotherjsoncall", function(data) { 
       processAgainAndAgain(data); 
      }); 
     }); 
    }); 

De esta manera, sólo se emitió la segunda llamada cuando la respuesta a la primera llamada se ha recibido y procesado, y la tercera llamada solo se emitirá cuando se haya recibido y procesado la respuesta a la segunda llamada. Este código es para getJSON pero se puede adaptar a $ .ajax.

+0

Soy consciente de su solución, pero las solicitudes múltiples no son generadas por el mismo par, por lo que no puedo encadenarlas como lo demostró.Mi solución sería más como un candado (AjaxObject global) en C# –

1

La mejor manera de hacerlo es mediante el encadenamiento de devoluciones de llamadas como dijo Nosredna. No recomendaría usar XMLHttpRequest sincrónico ya que bloquean toda la aplicación.

No hay mucha ayuda para esto hasta donde yo sé, pero podría hacer algo parecido a una devolución de llamada FIFO.

2

le podría dar una oportunidad narrativa Javascript http://www.neilmix.com/narrativejs/doc/

nunca he utilizado yo mismo sin embargo. Si quisiera hacer esto, configuraría algún tipo de abstracción para encadenar acciones asíncronas. Como han dicho otros, la versión sincrónica del objeto ajax impide que los eventos se procesen mientras espera una respuesta. Esto hace que el navegador parezca estar congelado hasta que reciba una respuesta.

+1

Eso parece genial. – Nosredna

+0

Gracias por la adición, pero no estoy seguro de si se trata de mi problema. Realiza llamadas asíncronas secuenciales si solo hubo un hilo generador, pero en mi caso muchos eventos generan solicitudes. –

+0

Como dije, no he usado NJS, pero su descripción dice que agrega un operador de rendimiento que simplemente detiene la ejecución de una función hasta que se dispara un evento. No me parece que eso impediría la concurrencia. Si lo hiciera, no sería una biblioteca muy útil para nadie. – Breton

3

Establecer la opción asíncrono a falso, por ejemplo,

$.ajax({ async: false /*, your_other_ajax_options_here */ }); 

Referencia: Ajax/jQuery.ajax

+0

La opción de sincronización se eliminará pronto de jQuery. –

+0

Esta es la mejor respuesta para la solicitud original de OP. Esta sugerencia garantiza IOE (ejecución en orden) con la menor complejidad. Nunca ha habido planes para eliminar el indicador asincrónico de jquery, al contrario de lo que implica @LS. – kamelkev

+1

Recuerde: "A partir de jQuery 1.8, el uso de async: falso con jqXHR ($ .Deferred) está en desuso, debe usar las opciones de éxito/error/devolución de llamada completa en lugar de los métodos correspondientes del objeto jqXHR como jqXHR.done(). " http://docs.jquery.com/Ajax/jQuery.ajax#options –

0

llamadas síncronas no son necesariamente más lento, si usted tiene una aplicación donde AJAX llama abierta, puestos a, luego cierra un socket, las múltiples llamadas al socket no tienen sentido ya que algunos sockets solo pueden manejar una sola conexión, en cuyo caso, los datos de cola solo se envían cuando la llamada AJAX anterior se ha completado significa un rendimiento de datos mucho más alto.

-1

¿Qué le parece usar los eventos de Node.js?

var EventEmitter = require('events').EventEmitter; 
var eventEmitter = new EventEmitter(); 
var $ = require('jquery'); 

var doSomething = function (responseData) { 
    var nextRequestData = {}; 
    // do something with responseData 
    return nextRequestData; 
}; 

// ajax requests 
var request1 = $.ajax; 
var request2 = $.ajax; 
var requests = [request1, request2]; 

eventEmitter.on('next', function (i, requestData) { 
    requests[i](requestData).then(
    function (responseData) { 
     console.log(i, 'request completed'); 
     if (i+1 < requests.length) { 
     var nextRequestData = doSomething(responseData); 
     eventEmitter.emit('next', i+1, nextRequestData); 
     } 
     else { 
     console.log('completed all requests'); 
     } 
    }, 
    function() { 
     console.log(i, 'request failed'); 
    } 
); 
}); 

var data = { 
    //data to send with request 1 
}; 
eventEmitter.emit('next', 0, data); 
0

secuencial! = Síncrono, y me gustaría un asíncrona y solución secuencial

ejecución síncrona generalmente significa "usando el mismo reloj", mientras que la ejecución secuencial significa "siguiente en orden o secuencia ".

Para su caso de uso específico, creo que se deben cumplir ambas condiciones, ya que la ejecución asincrónica implica la posibilidad de un resultado no secuencial.

0
(async() => { 
    for(f of ['1.json','2.json','3.json']){ 
    var json = await $.getJSON(f); 
    console.log(json) 
}; 
})() 
  1. peticiones 3 archivos JSON con jQuery llamadas Ajax
  2. proceso en secuencia (no en paralelo) con la espera
  3. obras en Chrome/Firefox/Edge (a partir del 01/30/2018)

más en MDN

Cuestiones relacionadas