这是我的Ajax:
$("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
此外,欢迎任何有关改进代码的建议!
答案 0 :(得分:8)
这就是正在发生的事情(伪代码):
当你打字慢时:
.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 :(得分:1)
在调用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
});
我希望这会有所帮助。