在单线程环境中,这种Jquery行为是如何实现的?

时间:2018-01-30 22:23:24

标签: javascript jquery ajax multithreading typescript

首先,任务:我需要在服务器上为每次击键进行一系列验证。 这是通过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的属性,但是处理顺序实际上影响了逻辑(有时后来的请求会被先前的请求取消)。

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

经过测试,似乎.abort导致.always回调被同步调用,这导致在处理原始循环的过程中开始新的循环。对此的快速解决方法是执行任何可以将该调用推送到.abort,或者调用pruneAbortedRequests到回调队列的任何操作,以便在上一个函数完成之前不会调用它运行

例如,将其包装在setTimeout中。

request.always((data) => {
    setTimeout(() => this.pruneEarlierRequests(aO), 0);
});

我没有立即看到比这样的更好的解决方案,除了不中止请求和使用不同的技术来减少请求的数量。