2011-07-13 10 views
8

To mój Ajax:Ajax wysłany na "keyup" duplikuje wyniki, gdy szybkie pisanie!

$("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>"); 
       } 
      } 
     }); 
    } 
}); 

Po wpisaniu powoli (wolniej następnie pismem na sekundę) uzyskać wyniki prawidłowe, kiedy wpisać szybciej uzyskać 2 razy te same wyniki

przykład:
powolny wpisując: res1 res2 res3
szybko wpisując: res1 res2 res3 res1 res2 res3

również wszelkie porady na poprawę kodu byłoby mile widziane!

+0

Ja ha (ve) d ten sam problem! +1 – genesis

+0

Nie powinieneś wywoływać metody .append() w pętli. Utwórz łańcuch i wywołaj funkcję .append() raz, ze względu na wydajność. Za każdym razem, gdy wywołuje się metodę .append(), parser HTML musi działać, a przeglądarka musi wykonać fragmentaryczne odświeżanie.Szybciej zrobić to raz z dużą porcją niż zrobić to często z mniejszymi porcjami. – ckruse

+0

@ckruse thanx, zmieniłem na $ .each i wciąż ten sam problem, chociaż teraz mogę pisać trochę szybciej, nie mając go ... :) – ilyo

Odpowiedz

7

To jest to co się dzieje (Pseudokod):

Kiedy piszesz powoli:

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

Kiedy piszesz szybko:

.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 

Aby rozwiązać duplikaty problemu , chciałbyś, aby twoje wyniki usuwały/dołączały operację atomową - używając .replaceWith.

wyniki budowanie bloków HTML najpierw jako ciąg znaków, a następnie wykonaj .replaceWith zamiast .remove/.append:

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

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

Innym problemem (nie związane z duplikatami) może być tak, że starszy wynik nadpisuje nowszej który przybył wcześniej (ponieważ AJAX jest asynchroniczny, a serwer może wysyłać odpowiedzi nie w tej samej kolejności, w jakiej otrzymuje żądania).

Jednym ze sposobów uniknięcia tego przywiązuje udostępnia gościom Marker (rodzaj „numer seryjny”) na każde żądanie i sprawdzenie go w odpowiedzi:

//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 ... 
    } 
}); 

Po stronie serwera:

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); 
} 

Another podejście polegałoby na zsynchronizowaniu żądań .ajax(), ustawiając opcję async na false. Jednak to może tymczasowo zamknąć przeglądarkę, gdy żądanie jest aktywny (patrz docs)

A także powinno się wprowadzić limit czasu jak algiecas sugeruje, aby zmniejszyć obciążenie serwera (to trzecia kwestia, nie związane z duplikatów ani na żądanie/kolejność odpowiedzi).

+0

Dlaczego występuje różnica między 'replace' i' remove/append'? Czy masz jakiś przykład działania znacznika roundtrip? Nie do końca rozumiem, jak to działa. – ilyo

+0

ponieważ 2 'remove' /' append' blocks z napiętym timingiem może spowodować 'remove1remove2' /' append1append2' (co powoduje twoje problemy z duplikatami), podczas gdy 'replaceWith' przełącza atomowo węzeł DOM, więc otrzymasz albo wynik1 albo wynik1 , ale nie oba. – lxa

+0

Odnośnie znacznika roundtrip: dodam kilka komentarzy do odpowiedzi w ciągu kilku minut. – lxa

1

Powinieneś poświęcić trochę czasu przed wywołaniem ajax. Coś takiego powinno zadziałać:

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 
}); 

Mam nadzieję, że to pomoże.

+0

thanx ale nie, otrzymuję dokładnie taki sam wynik tylko z czasem oczekiwania :) – ilyo

Powiązane problemy