首先,任务:我需要在服务器上为每次击键进行一系列验证。 这是通过AJAX实现的。因此,出现的问题是如果服务器在最终(有效)之后发送倒数第二(无效)响应。我们的Javascript代码看起来就像我们刚发送了无效的回复。所以我试图想要实现一些会使先前的ajax请求失效的队列管理器,这样如果他们从服务器返回它们就不会被处理。这是代码(抱歉,它在Typescript中)
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
相反,这就是问题,我得到的输出似乎表明这些承诺是在不同的线程上处理的(我删除了一些条目)
修剪vancouve
处理vancouve,指数:0
在索引0处中止并修剪,正在处理 vancouve at index 8
处理vancouve,指数:1
在指数1处中止和修剪v,目前正在处理vancouve 指数8
处理vancouve,指数:2
在指数2处中止并修剪了va,目前正在处理vancouve 指数8
处理vancouve,指数:3
在指数3处中止并修剪了面包车,目前正在处理vancouve 指数8
处理vancouve,指数:4
在指数4处流产并修剪了vanc,目前正在处理vancouve 指数8
处理vancouve,指数:5
在指数5处流产并修剪了vanco,目前正在处理vancouve 指数8
处理vancouve,指数:6
在指数6处流产并修剪了vancou,目前正在处理vancouve 指数8
修剪vancou
处理vancou,指数:0
在索引0处中止并修剪,正在处理 vancou在指数6
处理vancou,指数:1
在指数1处中止并修剪v,目前正在索引处理vancou 6
处理vancou,指数:2
在指数2处中止并修剪了va,目前正在处理指数的vancou 6
处理vancou,指数:3
在指数3处中止并修剪了面包车,目前正在处理vancou 指数6
处理vancou,指数:4
在指数4处中止并修剪了vanc,目前正在处理vancou 指数6
处理vancou,指数:5
在指数5中止并修剪了vanco,目前正在处理vancou 指数6
处理vancou,指数:6
在指数6处修剪了vancou,目前处理指数6的vancou
处理vancouve,指数:7
在指数7流产和修剪vancouv,目前处理vancouve 在索引8
修剪vancouv
处理vancouv,指数:0
在索引0处中止并修剪,正在处理 vancouv指数7
处理vancouv,指数:1
在索引1处中止并修剪v,目前正在索引处理vancouv 7
处理vancouv,指数:2
在指数2处中止和修剪va,目前处理vancouv at 指数7
处理vancouv,指数:3
在指数3处中止并修剪了面包车,目前正在处理vancouv 指数7
处理vancouv,指数:4
在指数4处流产并修剪了vanc,目前正在处理vancouv 指数7
处理vancouv,指数:5
在指数5处流产并修剪了vanco,目前正在处理vancouv 指数7
处理vancouv,指数:6
在指数6处流产并修剪了vancou,目前正在处理vancouv 指数7
处理vancouv,指数:7
指数7修剪vancouv,目前处理指数7的vancouv
处理vancouve,指数:8
在指数8处修剪了vancouve,目前处理指数8的vancouve
完全令我惊讶的是,在索引8(vancouve)处理响应的过程中,它处理了索引6和索引7的响应。现在,我预计8将在6和7之前到达,但我假设在6和7的处理开始之前,处理将完全完成8。那么我的问题是,为什么会发生这种情况,我如何确保每个响应的处理完全完成?
我考虑过这是否只是console.log的属性,但是处理顺序实际上影响了逻辑(有时后来的请求会被先前的请求取消)。
感谢您的帮助。
答案 0 :(得分:0)
经过测试,似乎.abort
导致.always
回调被同步调用,这导致在处理原始循环的过程中开始新的循环。对此的快速解决方法是执行任何可以将该调用推送到.abort
,或者调用pruneAbortedRequests
到回调队列的任何操作,以便在上一个函数完成之前不会调用它运行
例如,将其包装在setTimeout中。
request.always((data) => {
setTimeout(() => this.pruneEarlierRequests(aO), 0);
});
我没有立即看到比这样的更好的解决方案,除了不中止请求和使用不同的技术来减少请求的数量。