2011-07-13 8 views
8

Esta es mi Ajax:Ajax enviado en "keyup" duplica los resultados al escribir rápidamente!

$("form[0] :text").live("keyup", function(event) { 

    event.preventDefault(); 
    $('.result').remove(); 
    var serchval = $("form[0] :text").val(); 

    if(serchval){ 

     $.ajax({ 

      type: "POST", 
      url: "<?= site_url('pages/ajax_search') ?>", 
      data: {company : serchval}, 
      success: function(data) { 

       var results = (JSON.parse(data)); 
       console.log(results); 

       if(results[0]){ 
        $.each(results, function(index) { 
         console.log(results[index].name); 
         $("#sresults").append("<div class='result'>" + results[index].name + "</div>"); 
        }); 
       } 
       else { 
        $("#sresults").append("<div class='result'>לא נמצאו חברות</div>"); 
       } 
      } 
     }); 
    } 
}); 

Cuando escribo lentamente (más lento que una carta por segundo) que obtener los resultados correctos, cuando escribo más rápido llego 2 veces los mismos resultados

ejemplo:
escribiendo lenta: res1 res2 res3
escribir rápido: res1 res2 res3 res1 res2 res3

Además, cualquier asesoramiento para mejorar el código sería bienvenido!

+0

¡He (ve) d el mismo problema! +1 – genesis

+0

No debe llamar a .append() en un bucle. Cree una cadena y llame a .append() una vez, por motivos de rendimiento. Cada vez que llamas a .append(), el analizador de HTML tiene que funcionar y el navegador tiene que hacer un redibujado de partición.Es más rápido hacer esto una vez con un gran trozo que hacer esto muy a menudo con trozos más pequeños. – ckruse

+0

@ckruse thanx, cambié a $ .each y sigue teniendo el mismo problema, aunque ahora puedo escribir un poco más rápido para no tenerlo ... :) – ilyo

Respuesta

7

eso es lo que está sucediendo (pseudocódigo):

Cuando se está escribiendo lenta:

.keyup1 
.remove1 
//asynchronous ajax1 request takes some time here... 
.append1 
.keyup2 
.remove2 
//asynchronous ajax2 request takes some time here... 
.append2 

Cuando se está escribiendo rápido:

.keyup1 
.remove1 
//asynchronous ajax1 request takes some time here... 
//and keyup2 happens before ajax1 is complete 
.keyup2 
.remove2 
.append1 
//asynchronous ajax2 request takes some time here... 
.append2 
//two results were appended _in a row_ - therefore duplicates 

Para resolver un problema duplicados , deseará hacer que sus resultados eliminen/añadan una operación atómica - usando .replaceWith.

resultados se basan en bloque HTML primero como cadena y luego hacer la .replaceWith en lugar de .remove/.append:

var result = ''; 
for (i in results) { 
    result += "<div class='result'>" + results[i].name + "</div>"; 
} 

$("#sresults").replaceWith('<div id="sresults">' + result + '</div>'); 

Otro problema (no relacionado con duplicados) puede ser ese resultado mayores sobrescribe nuevo que llegó antes de (porque AJAX es asíncrono y el servidor puede emitir respuestas no en el mismo orden en que recibe las solicitudes).

Un enfoque para evitar este marcador es unir ida y vuelta (clase de "número de serie") a cada solicitud, y la comprobación de que en respuesta:

//this is global counter, you should initialize it on page load, global scope 
//it contains latest request "serial number" 
var latestRequestNumber = 0; 

$.ajax({ 
    type: "POST", 
    url: "<?= site_url('pages/ajax_search') ?>", 
    //now we're incrementing latestRequestNumber and sending it along with request 
    data: {company : serchval, requestNumber: ++latestRequestNumber}, 
    success: function(data) { 
     var results = (JSON.parse(data)); 
     //server should've put "serial number" from our request to the response (see PHP example below) 
     //if response is not latest (i.e. other requests were issued already) - drop it 
     if (results.requestNumber < latestRequestNumber) return; 
     // ... otherwise, display results from this response ... 
    } 
}); 

En el lado del servidor:

function ajax_search() { 
    $response = array(); 

    //... fill your response with searh results here ... 

    //and copy request "serial number" into it 
    $response['requestNumber'] = $_REQUEST['requestNumber']; 

    echo json_encode($response); 
} 

Otro El enfoque consistiría en hacer .ajax() solicitudes sincrónicas, configurando la opción async en false. Sin embargo, esto puede bloquear temporalmente el navegador mientras solicitud está activa (ver docs)

Y también sin duda debe introducir el tiempo de espera como algiecas sugiere para reducir la carga en el servidor (este es el tercer problema, no relacionado con duplicados ni a la solicitud/orden de respuesta).

+0

¿Por qué hay una diferencia entre 'replace' y' remove/append'? Además, ¿tiene algún ejemplo de trabajo de un marcador de ida y vuelta? No entiendo completamente cómo funciona. – ilyo

+0

porque 2 bloques 'remove' /' append' con tiempos ajustados pueden dar como resultado 'remove1remove2' /' append1append2' (que causa los problemas con los duplicados), mientras que 'replaceWith' cambia atómicamente al nodo DOM, por lo que obtendría result1 o result1 , pero no ambos – lxa

+0

Con respecto al marcador de ida y vuelta: agregaré algunos comentarios en respuesta en unos minutos. – lxa

1

Debe incluir un tiempo de espera antes de llamar a ajax. Algo como esto debería funcionar:

var timeoutID; 

$("form[0] :text").live("keyup", function(event) { 

    clearTimeout(timeoutID); 

    timeoutID = setTimeout(function() 
    { 
     $('.result').remove(); 
     var serchval = $("form[0] :text").val(); 

     if(serchval){ 

      $.ajax({ 

       type: "POST", 
       url: "<?= site_url('pages/ajax_search') ?>", 
       data: {company : serchval}, 
       success: function(data) { 

        var results = (JSON.parse(data)); 
        console.log(results); 

        for (i in results) 
        { 
         console.log(results[i].id); 
         $("#sresults").append("<div class='result'>" + results[i].name + "</div>"); 
        } 
       } 
      }); 
     } 
    }, 1000); //timeout in miliseconds 
}); 

Espero que esto ayude.

+0

Gracias pero no, obtengo exactamente el mismo resultado solo con un tiempo de espera :) – ilyo

Cuestiones relacionadas