ejemplo - jquery set value input
jQuery leyĆ³ la secuencia AJAX de forma incremental? (5)
He leído esta pregunta pero no responde exactamente mi pregunta. Desafortunadamente, parece que las cosas han cambiado en el objeto XHR desde la última vez que miré a AJAX, por lo que ya no es posible acceder directamente a responseText
antes de que termine de completarse.
Tengo que escribir una página que utiliza AJAX (preferiblemente jQuery, pero estoy abierto a sugerencias) para recuperar datos CSV a través de HTTP desde un servidor que no tengo control. Los datos de respuesta podrían ser bastante grandes; un megabyte de texto no es raro.
El servidor es amigable para la transmisión. ¿Todavía hay alguna manera de obtener acceso a una secuencia de datos a medida que se devuelve, directamente desde JavaScript?
Tengo la opción de escribir algún código PHP que viva en el medio y use algún tipo de tecnología "Comet" (larga encuesta, EventSource, etc.), pero preferiría evitar eso si es posible.
En caso de que sea relevante, asuma para esta pregunta que los usuarios tienen la última versión de Firefox / Chrome / Opera y que la compatibilidad con el viejo navegador no es un problema.
Aquí hay una manera directa de lograr esto usando JQuery (según lo solicitado por el OP):
Primero, amplíe el objeto ajax para que admita onreadystatechange ejecutando el siguiente código desde https://gist.github.com/chrishow/3023092 (se agrega al final de esta respuesta). Luego simplemente llame a ajax usando una función onreadystatechange que verificará texto nuevo en xhr.responseText.
Si quieres ser aún más elegante, puedes borrar los datos del texto de respuesta cada vez que lo leas, como se describe here ).
Por ejemplo, consulte https://jsfiddle.net/g1jmwcmw/1/ , que descargará la respuesta de https://code.jquery.com/jquery-1.5.js y la publicará en fragmentos dentro de la ventana de la consola, utilizando el código a continuación (que puede copiar en una página html y luego abrir en su navegador):
<!-- jquery >= 1.5. maybe earlier too but not sure -->
<script src=https://code.jquery.com/jquery-1.5.min.js></script>
<script>
/* One-time setup (run once before other code)
* adds onreadystatechange to $.ajax options
* from https://gist.github.com/chrishow/3023092)
* success etc will still fire if provided
*/
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
if ( options.onreadystatechange ) {
var xhrFactory = options.xhr;
options.xhr = function() {
var xhr = xhrFactory.apply( this, arguments );
function handler() {
options.onreadystatechange( xhr, jqXHR );
}
if ( xhr.addEventListener ) {
xhr.addEventListener( "readystatechange", handler, false );
} else {
setTimeout( function() {
var internal = xhr.onreadystatechange;
if ( internal ) {
xhr.onreadystatechange = function() {
handler();
internal.apply( this, arguments );
};
}
}, 0 );
}
return xhr;
};
}
});
// ----- myReadyStateChange(): this will do my incremental processing -----
var last_start = 0; // using global var for over-simplified example
function myReadyStateChange(xhr /*, jqxhr */) {
if(xhr.readyState >= 3 && xhr.responseText.length > last_start) {
var chunk = xhr.responseText.slice(last_start);
alert(''Got chunk: '' + chunk);
console.log(''Got chunk: '', chunk);
last_start += chunk.length;
}
}
// ----- call my url and process response incrementally -----
last_start = 0;
$.ajax({
url: "https://code.jquery.com/jquery-1.5.js", // whatever your target url is goes here
onreadystatechange: myReadyStateChange
});
</script>
Como dice que su servidor es compatible con la transmisión (asíncrono) y estaba buscando una solución de jquery, ¿ha revisado el jQuery Stream Plugin ?
Es realmente fácil de usar y le permite no preocuparse realmente por nada. También tiene una documentation bastante buena .
Esto es bastante sencillo cuando se envía texto o HTML . A continuación hay un ejemplo.
(Sin embargo, te encontrarás con problemas si tratas de generar JSON , que abordaré más adelante).
ARCHIVO PHP
header(''Content-type: text/html; charset=utf-8'');
function output($val)
{
echo $val;
flush();
ob_flush();
usleep(500000);
}
output(''Begin... (counting to 10)'');
for( $i = 0 ; $i < 10 ; $i++ )
{
output($i+1);
}
output(''End...'');
ARCHIVO HTML
<!DOCTYPE>
<html>
<head>
<title>Flushed ajax test</title>
<meta charset="UTF-8" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript">
var last_response_len = false;
$.ajax(''./flushed-ajax.php'', {
xhrFields: {
onprogress: function(e)
{
var this_response, response = e.currentTarget.response;
if(last_response_len === false)
{
this_response = response;
last_response_len = response.length;
}
else
{
this_response = response.substring(last_response_len);
last_response_len = response.length;
}
console.log(this_response);
}
}
})
.done(function(data)
{
console.log(''Complete response = '' + data);
})
.fail(function(data)
{
console.log(''Error: '', data);
});
console.log(''Request Sent'');
</script>
</body>
</html>
¿Qué pasa si necesito hacer esto con JSON?
En realidad, no es posible cargar un solo objeto JSON de forma incremental (antes de que esté completamente cargado) porque hasta que tenga el objeto completo, la sintaxis siempre será inválida.
Pero si su respuesta tiene múltiples objetos JSON, uno tras otro, entonces es posible cargar uno a la vez, a medida que descienden por la tubería.
Así que modifiqué mi código de arriba por ...
Cambiando PHP FILE línea 4 de
echo $val;
paraecho ''{"name":"''.$val.''"};''
. Esto produce una serie de objetos JSON.Cambiar la línea 24 de ARCHIVOS HTML desde
console.log(this_response);
athis_response = JSON.parse(this_response); console.log(this_response.name);
Tenga en cuenta que este código rudimentario supone que cada "fragmento" que llega al navegador es un objeto JSON válido. Esto no siempre será así porque no puede predecir cómo llegarán los paquetes; es posible que deba dividir la cadena en puntos y coma (o crear otro carácter separador).
No use la application/json
NO para cambiar los encabezados a la application/json
- Hice esto y me hizo buscar en Google durante 3 días. Cuando el tipo de respuesta es application/json
, el navegador espera hasta que se complete la respuesta, ya que está completo. La respuesta completa es luego analizada para verificar si de hecho es JSON. Sin embargo, nuestra respuesta COMPLETA es {...};{...};{...};
que NO es válido JSON. El método jqXHR.done
supone que hubo un error porque la respuesta completa no se puede analizar como JSON.
Como se mencionó en los comentarios, puede desactivar esta verificación en el lado del cliente usando:
$.ajax(..., {dataType: "text"})
Espero que algunas personas lo encuentren útil.
Use XMLHttpRequest.js
https://github.com/ilinsky/xmlhttprequest
http://code.google.com/p/xmlhttprequest
- Ofrece una implementación discreta y discreta compatible con estándares (W3C) entre navegadores del objeto XMLHttpRequest 1.0
- Corrige TODAS las peculiaridades de los navegadores observadas en sus implementaciones nativas de objetos XMLHttpRequest
- Permite el registro transparente de la actividad del objeto XMLHttpRequest
Para usar encuestas largas con PHP:
output.php:
<?php
header(''Content-type: application/octet-stream'');
// Turn off output buffering
ini_set(''output_buffering'', ''off'');
// Turn off PHP output compression
ini_set(''zlib.output_compression'', false);
// Implicitly flush the buffer(s)
ini_set(''implicit_flush'', true);
ob_implicit_flush(true);
// Clear, and turn off output buffering
while (ob_get_level() > 0) {
// Get the curent level
$level = ob_get_level();
// End the buffering
ob_end_clean();
// If the current level has not changed, abort
if (ob_get_level() == $level) break;
}
// Disable apache output buffering/compression
if (function_exists(''apache_setenv'')) {
apache_setenv(''no-gzip'', ''1'');
apache_setenv(''dont-vary'', ''1'');
}
// Count to 20, outputting each second
for ($i = 0;$i < 20; $i++) {
echo $i.str_repeat('' '', 2048).PHP_EOL;
flush();
sleep(1);
}
run.php:
<script src="http://code.jquery.com/jquery-1.6.4.js"></script>
<script src="https://raw.github.com/ilinsky/xmlhttprequest/master/XMLHttpRequest.js"></script>
<script>
$(function() {
var xhr = new XMLHttpRequest();
xhr.open(''GET'', ''/longpoll/'', true);
xhr.send(null);
var timer;
timer = window.setInterval(function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
window.clearTimeout(timer);
$(''body'').append(''done <br />'');
}
$(''body'').append(''state: '' + xhr.readyState + ''<br />'');
console.log(xhr.responseText);
$(''body'').append(''data: '' + xhr.responseText + ''<br />'');
}, 1000);
});
</script>
Esto debería dar como resultado:
state: 3
data: 0
state: 3
data: 0 1
state: 3
data: 0 1 2
state: 3
data: 0 1 2 3
state: 3
data: 0 1 2 3 4
...
...
...
state: 3
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
state: 3
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
state: 3
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
done
state: 4
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Para IE, debes buscar en XDomainRequest
http://msdn.microsoft.com/en-us/library/cc288060(VS.85).aspx
Vas a querer utilizar Javascript para esto. La razón es que vas a querer sondear continuamente y no esperar a que se activen las devoluciones de llamada. No necesitas jQuery para esto, es bastante simple. Tienen un buen código fuente para esto en el sitio web Ajax Patterns .
Esencialmente, solo querrá hacer un seguimiento de su última posición en la respuesta y sondear periódicamente para obtener más texto después de esa ubicación. La diferencia en su caso es que puede suscribirse al evento completo y detener su votación.