Ajax отправил "keyup" дублирует результаты при быстрой печати! - PullRequest
9 голосов
/ 13 июля 2011

Это мой Аякс:

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

Когда я печатаю медленно (медленнее, чем буква в секунду), я получаю правильные результаты, когда я печатаю быстрее, я получаю в 2 раза те же результаты

пример:
медленный набор: res1 res2 res3
быстрый набор: res1 res2 res3 res1 res2 res3

Также, любые советы по улучшению кода приветствуются!

Ответы [ 2 ]

8 голосов
/ 13 июля 2011

Вот что происходит (псевдокод):

Когда вы печатаете медленно:

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

Когда вы печатаете быстро:

.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

Чтобы решить проблему с дубликатами , вы бы хотели, чтобы ваши результаты удаляли / добавляли элементарную операцию - используя .replaceWith.

Сначала создайте HTML-блок результатов в виде строки, а затем выполните .replaceWith вместо .remove / .append:

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

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

Другая проблема (не связанная с дубликатами) может заключаться в том, что более старый результат перезаписывает более новый, полученный ранее (поскольку AJAX асинхронный и сервер может выдавать ответы не в том же порядке, в котором он получает запросы).

Одним из подходов, позволяющих избежать этого, является прикрепление маркера туда и обратно (вид «серийного номера») к каждому запросу и проверка его в ответ:

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

На стороне сервера:

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

Другим подходом будет синхронизация запросов .ajax() с параметром async false. Однако это может временно заблокировать браузер, когда запрос активен (см. docs )

А также вам обязательно следует ввести тайм-аут, поскольку algiecas предлагает снизить нагрузку на сервер ( это третья проблема, не связанная с дублированием или порядком запросов / ответов ).

1 голос
/ 13 июля 2011

Вы должны задействовать некоторый таймаут перед вызовом ajax. Примерно так должно работать:

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

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...