Initially, the task at hand is to conduct a series of validations on a server for every keystroke made. This process is carried out through AJAX. An issue arises when the penultimate (invalid) response is received from the server after the ultimate (valid) one. In such cases, our Javascript code can incorrectly appear as if an invalid response was sent. To address this concern, I attempted to create a sophisticated queue manager that would cancel out previous AJAX requests upon their return from the server. Below is the TypeScript code for this solution:
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;
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() + "}";
}
}
The fundamental concept behind this approach lies in the single-threaded nature of JavaScript which ensures that send requests are always initiated in the order of user input. Subsequently, upon receiving a response from an AJAX call, all preceding entries are aborted.
In my understanding, with an input like '123,' assuming we have 5 elements in requests corresponding to '1,' '12,' '123,' the eliminating sequence should look like this:
pruning 12 (arrived before 1) aborted and pruned 1 pruned 12
pruning 1 pruned 1
pruning 123 aborted and pruned 1 aborted and pruned 12 pruned 123
However, the problem surfaces when the output indicates that these promises are handled on different threads midway through the processing:
... (log messages indicating processing order)
To my surprise, while processing the response at index 8 ('vancouve'), it suddenly went ahead and started handling the responses for indexes 6 and 7. Although I expect 8 to arrive before 6 and 7, I anticipate that the processing for 8 should be completed before moving onto 6 and 7. The question here pertains to why this deviation occurs and how one can ensure that the processing for each response is entirely finished.
I did consider whether this was merely a quirk of console.log, but the processing order indeed affects the logic (leading to scenarios where later requests get canceled by earlier ones).
Your insights and assistance on this matter would be greatly appreciated.