jquery - 如何在打字时为实时搜索创建缓存系统
问题描述
我试图在键上创建一个搜索引擎以从数据库返回结果,但如果已键入短语以从对象而不是从数据库中提取结果
例如:当您输入“BMW 300”时,将从数据库中提取数据并将短语和结果保存在对象中,对象将如下所示
object {
b: (4) […]
0: Object { name: "BMW"}
1: Object { name: "BMW 300"}
2: Object { name: "BMW XS"}
3: Object { name: "BMW Z 500"}
bm: (4) […]
0: Object { name: "BMW"}
1: Object { name: "BMW 300"}
2: Object { name: "BMW XS"}
3: Object { name: "BMW Z 500"}
bmw: (4) […]
0: Object { name: "BMW"}
1: Object { name: "BMW 300"}
2: Object { name: "BMW XS"}
3: Object { name: "BMW Z 500"}
"bmw 3": (1) […]
0: Object { name: "BMW 300"}
"bmw 30": (1) […]
0: Object { name: "BMW 300"}
"bmw 300": (1) […]
0: Object { name: "BMW 300"}
}
如果您删除 300 个短语变成“BMW”,现在应该从对象中提取结果,因为短语“BMW”已被输入。
我对两个逻辑都进行了编码,它们工作得很好,但问题是如何交换何时从对象读取以及何时从数据库读取?
// create object
var hold_results = {};
$('input[name="search"]').on('keyup', function(){
var phrase = jQuery.trim($(this).val());
if (phrase.length > 0) {
$.ajax({
type: "POST",
url: 'index.php?route=product/newsearch',
data: 'phrase='+phrase,
success: function(data) {
if (data.length != 0) {
// push phrase and currect results in object
hold_results[phrase] = data;
$.each(data , function(key, value){
if (value != '') {
html = '<li><a href="'+value.href+'">'+value.name+'</a></li>';
$('#search-results').append(html);
}
});
}
}
});
}
// should pull results from object here if phrase exist
$.each(hold_results , function(key , value){
if (key == phrase) {
$.each(value, function(k , v){
html = '<li><a href="'+v.href+'">'+v.name+'</a></li>';
$('#search-results').append(html);
})
}
});
});
解决方案
有一种简单的方法可以实现这一点 - 但首先您需要知道您的实现会触发太多次并且可能无法按预期工作。我会考虑添加几件事:
- 在触发新搜索之前中止先前触发的异步 ajax 请求 - 在您的代码中,它将继续触发并接收许多可能不再相关的结果。
- 添加缓存机制- 您想要控制它将存储多少记录,并且您想要一种匹配所需搜索词的好方法(精确匹配或子集或两者)。
这是 JSfiddle 中的演示- 我将引导您完成
首先,我们创建一个变量来保存一个活动的 ajax 请求,否则将是null
:
//this is the variable that will store the ajax call
var request = null;
现在我们可以使用所有必需的方法创建一个对象,它将成为我们的缓存系统:
var cache = {
storageFIFO: [], // The array that will hold our results
maxResults: 20, // max enteries in the storedResultFifo array - will shift once when exceeded
pushResults: function(phrase, data) {
cache.storageFIFO.push({
term: phrase,
data: data
});
if (cache.storageFIFO.length > cache.maxResults) {
cache.storageFIFO.shift();
}
},
getCachedResults: function(phrase) {
//First try exact match against cached search terms:
for (var i = 0; i < cache.storageFIFO.length; i++)
if (cache.storageFIFO[i].term === phrase)
return cache.storageFIFO[i].data;
//try phrase as a substring of the terms stored in the cache
for (var i = 0; i < cache.storageFIFO.length; i++)
if (cache.storageFIFO[i].term.includes(phrase))
return cache.storageFIFO[i].data;
return false;
}
};
关于缓存的几点说明:
- FIFO(先进先出):当达到存储限制时,删除最旧的记录。
.shift();
将弹出第一个元素(最旧的索引 0)以实现类似 FIFO 的数据结构。getCachedResults
:此方法将尝试匹配短语两次 - 一次用于完全匹配(以获得更好的结果),否则将尝试将短语匹配为缓存术语的子集。string1.includes(string2)
这是我匹配子集的方式。
现在设置了缓存机制 - 我将逻辑放入keyup
事件中:
//Bind the event to search:
$('input[name="search"]').on('keyup', function() {
var phrase = jQuery.trim($(this).val());
if (phrase.length <= 1) return; // From length of two
//This is just for testing and generating random data:
var randomData = [];
for (var i = 0; i < Math.floor(Math.random() * (20 - 5 + 1)) + 5; i++)
randomData.push({
phrase: phrase,
href: "#",
name: Math.random().toString(36).substring(7)
});
//This will trigger an abort of previous unfinished ajax request
//When aborted the ajax `complete` will set it back to null
if (request != null) request.abort();
//try to load from Cache first:
var fromCache = cache.getCachedResults(phrase);
if (fromCache !== false) {
drawResults(fromCache, "Cached Results");
return;
}
//If we got here that means that the cache does not has matching phrases:
//Send a request to db:
request = $.ajax({
url: '/echo/json/', // A jsfiddle async request endpoint
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: { //the correct data structure for jsfiddle async requests
json: JSON.stringify(randomData),
delay: 0.15
},
success: function(data) {
if (data.length != 0) {
//Cache it:
cache.pushResults(phrase, data);
//Draw it:
drawResults(data, "DataBase");
}
},
complete: function() {
request = null;
}
});
});
在这里,您可以看到一些为创建的 jsfiddle 的附加内容(从虚拟异步请求服务器获取结果)。
关于 Logic 和 Ajax 请求的几点说明:
if (phrase.length <= 1) return;
: 将阻止不是 2 个字符或更长的查询。if (request != null) request.abort();
: 将中止先前运行的请求。正如您在 Ajaxcomplete
回调中看到的那样,它将在完成时将其设置回null
(成功、中止、错误等......)cache.getCachedResults(phrase);
:首先从缓存中尝试 -false
如果不匹配,将返回。- 在没有命中缓存后 - 然后触发 ajax(请注意,url 和数据被修改为所需的值以与 jsfiddle 一起使用)。
最终说明 绘制结果由您决定——我只是包含了一个小的快速函数来可视化结果并查看它们的来源。
推荐阅读
- file-upload - MOVEit.DMZ.API 9.0 抛出错误 - '无法访问已处置的对象。对象名称:'System.Net.HttpWebResponse
- numpy - Pycharmm的新项目不包括numpy!?!每个新项目每次都需要新的 pip 安装?
- reactjs - 使用 ag-grid-react- 时,目标容器不是 DOM 元素错误
- python - 如何在 tkinter 中使用带有 if-else 语句的 lambda 函数
- aem - 文件夹未包含在 AEM 包中
- c - C 程序到 POSIX 共享内存中的 mkdir 缺少权限
- reactjs - Microsoft Teams 选项卡 SSO getAuthToken 返回 resourceDisabled
- java - 如何将文件路径从 Azure 存储传递到 Azure 存储过程
- javascript - 如何使用 uuid 作为 postgres 的默认 ID?
- flutter - 带有 YouTube 视频链接的视频播放器,用于颤振应用