首先,任务:我需要针对每个击键在服务器上进行一系列验证。
这是通过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);
});


除了不中止请求并使用其他技术减少请求数量之外,我没有立即看到比这种更好的解决方案。

09-11 17:21