首先,任务:我需要针对每个击键在服务器上进行一系列验证。
这是通过AJAX实现的。因此,如果服务器在最终(有效)响应之后发送了倒数第二(无效)响应,将会出现问题。我们的Javascript代码看起来像我们刚发送了无效的响应。因此,我尝试幻想并实现某种队列管理器,该队列管理器将使先前的ajax请求到期,因此,如果它们从服务器返回,则不会对其进行处理。这是代码(很抱歉,它在打字稿中)
class AjaxManager {
constructor(private options: AjaxOptions) {
}
_requests : Array<AjaxObject> = new Array<AjaxObject>();
send(settings: JQueryAjaxSettings, block : boolean) {
let request = $.ajax(settings);
var aO = new AjaxObject(request, settings, block);
request.always((data) => {
this.pruneEarlierRequests(aO);
});
this._requests.push(aO);
}
private pruneEarlierRequests(ajaxObject: AjaxObject) {
var requestedIndex = this._requests.findIndex((search) => { return search.id === ajaxObject.id; });
if ( requestedIndex === -1)
return; //don't prune if this request doesn't even exist here, probably an error.
if (this._requests[requestedIndex] == undefined)
return;
var data = this._requests[requestedIndex].settings.data.text;
console.log("pruning " + data);
for (var index = 0; index < this._requests.length; index++) {
console.log("processing " + data + ", index: " + index);
if (this._requests[index].id !== ajaxObject.id) {
console.log("aborted and pruned " + this._requests[index].settings.data.text + " at index " + index + ", currently processing " + data + " at index " + requestedIndex);
this._requests[index].request.abort();
} else {
console.log("pruned " + this._requests[index].settings.data.text + " at index " + index + ", currently processing " + data + " at index " + requestedIndex);
break;
}
}
}
}
class AjaxObject {
id: string;
constructor(public request: JQueryXHR, public settings : JQueryAjaxSettings, public block : boolean) {
this.id = this.guid();
}
guid() {
let _p8 = (s = false) : string=> {
var p = (Math.random().toString(16) + "000000000").substr(2, 8);
return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p;
}
return "{" + _p8() + _p8(true) + _p8(true) + _p8() + "}";
}
}
基本思想是,因为JS是单线程的,所以我们将始终按照用户键入请求的顺序启动发送请求。然后,当我们收到来自ajax调用的响应时,我们将中止所有先前的条目。
现在,由于我假设(并且我可能是错的),给定输入123,所以我假设类似以下内容
我们的请求中有5个元素,对应于1,12,123
然后:
修剪12(在1之前到达)
中止和修剪1
修剪12
修剪1
修剪1
修剪123
中止和修剪1
中止和修剪12
修剪123
相反,这就是问题所在,我得到的输出似乎表明这些承诺是在不同的线程上处理的(我删除了一些条目)
修剪温哥华
加工温哥华,指数:0
在索引0处中止并修剪,当前正在处理
温哥华指数8
加工温哥华,指数:1
在索引1处终止v和修剪v,当前在处处理vancouve
索引8
加工温哥华,指数:2
在索引2处终止并修剪了va,当前在处理vancouve
索引8
加工温哥华,指数:3
在索引3处终止并修剪面包车,目前在处理温哥华
索引8
加工温哥华,指数:4
在索引4处终止并修剪了Vanc,目前在
索引8
加工温哥华,指数:5
在索引5处对vanco进行了中止和修剪,目前在
索引8
加工温哥华,指数:6
在索引6处终止了温哥华的修剪和修剪,目前在
索引8
修剪温哥华
加工面包,指数:0
在索引0处中止并修剪,当前正在处理
温哥华6
加工面包,指数:1
在索引1处终止v和修剪v,当前在索引处处理vancou
6
加工面包,指数:2
索引2处的va终止和修剪,目前正在索引处处理vancou
6
加工面包,指数:3
在索引3处终止并修剪面包车,目前在
索引6
加工面包,指数:4
在索引4处终止并修剪了Vanc,目前在
索引6
加工面包,指数:5
在索引5处对vanco进行了中止和修剪,目前在
索引6
加工面包,指数:6
指数为6的修剪过的Vancou,目前指数为6的正在处理Vancou
加工温哥华,指数:7
在索引7处对vancouv进行了中止和修剪,目前正在处理vancouve
在索引8
修剪温哥华
加工温哥华,指数:0
在索引0处中止并修剪,当前正在处理
温哥华7指数
加工温哥华,指数:1
在索引1处终止v和修剪v,当前在索引处处理vancouv
7
加工温哥华,指数:2
在索引2处终止并修剪了va,目前在处理vancouv
索引7
加工温哥华,指数:3
在索引3处对vancouv进行了中止和修剪,目前在
索引7
加工温哥华,指数:4
在索引4处对vanc进行了中止和修剪,目前正在处理vancouv
索引7
加工温哥华,指数:5
在索引5处对vanco进行了中止和修剪,目前正在处理vancouv
索引7
加工温哥华,指数:6
在索引6处对vancouv进行了中止和修剪,目前在
索引7
加工温哥华,指数:7
在索引7处修剪vancouv,目前在索引7处处理vancouv
加工温哥华,指数:8
在索引8处修剪温哥华,目前在索引8处加工温哥华
完全让我感到惊讶的是,在处理索引8(vancouve)的响应时,它处理并处理了索引6和索引7的响应。现在,我希望8会在6和7之前到达。在开始6和7的处理之前,将完成8的处理。那么我的问题是,为什么会发生这种情况,以及如何确保每个响应的处理都完全完成?
我考虑了这是否仅是console.log的属性,但是处理顺序实际上正在影响逻辑(有时,较晚的请求会被较早的请求取消)。
感谢您的任何帮助。
最佳答案
经过测试,似乎.abort
导致.always
回调被同步调用,这导致新循环在处理原始循环的中间开始。一个快速的解决方法是执行将对cc的调用或对cc的调用推入回调队列的任何操作,以使该调用直到上一个函数运行完毕后才被调用。
例如,将其包装在setTimeout中。
request.always((data) => {
setTimeout(() => this.pruneEarlierRequests(aO), 0);
});
除了不中止请求并使用其他技术减少请求数量之外,我没有立即看到比这种更好的解决方案。