当 $.each 和 array.splice(i) 放在一起时,JQuery 处理数组超出索引错误

Sar*_*J S 2 javascript arrays each jquery

最近我在互联网上搜索一些可以处理废弃的 ajax/xhr 调用的代码。

这就是我发现的

$.xhrPool = [];

$.ajaxSetup({
    beforeSend: function (jqXHR) {
        $.xhrPool.push(jqXHR);
    },
    complete: function (jqXHR) {
        var i = $.xhrPool.indexOf(jqXHR);
        if (i > -1)
            $.xhrPool.splice(i, 1);
    }
});

$.xhrPool.abortAll = function () {
    $(this).each(function (i, jqXHR) {
        jqXHR.abort();
        $.xhrPool.splice(i, 1);// This is the line which makes me confused.
    });
};
Run Code Online (Sandbox Code Playgroud)

这段代码工作正常,但其中的一行让我感到困惑,我怀疑存在一些逻辑错误,但不知何故工作完美。

下面是让我困惑的部分,

$(this).each(function (i, jqXHR) {
        $.xhrPool.splice(i, 1);
});
Run Code Online (Sandbox Code Playgroud)

迭代 for 循环并获取第 i 个元素并将其从数组中删除。

现在,数组的总长度减少了,元素的索引也减少了,因为第一个成员被删除了。

Then in the next iteration, value of i is increased, so the element which is getting cought will be different (or not as expected).

For example consider array = [1,2,3,4,5,6,7,8,9,10];

迭代1

array = [1,2,3,4,5,6,7,8,9,10]
i=0
removes 1
new array is [2,3,4,5,6,7,8,9,10]
Run Code Online (Sandbox Code Playgroud)

迭代2

array = [2,3,4,5,6,7,8,9,10]
i=1
removes 3
new array is [2,4,5,6,7,8,9,10]
Run Code Online (Sandbox Code Playgroud)

迭代3

array = [2,4,5,6,7,8,9,10]
i=2
removes 5
new array is [2,4,6,7,8,9,10]
Run Code Online (Sandbox Code Playgroud)

迭代4

array = [2,4,6,7,8,9,10]
i=3
removes 7
new array is [2,4,6,8,9,10]
Run Code Online (Sandbox Code Playgroud)

迭代5

array = [2,4,6,8,9,10]
i=4
removes 9
new array is [2,4,6,8,10]
Run Code Online (Sandbox Code Playgroud)

迭代6

array = [2,4,6,8,10]
i=5
Run Code Online (Sandbox Code Playgroud)

** Here comes the trouble.

注意:我的计算机能够理解这段代码并正确执行它,但问题出在我的大脑上,我还没有准备好接受这部分:-(

我相信 $.each 是正确完成这项工作的人,但我仍然无法弄清楚它是如何实现的。

tri*_*cot 5

代码“有效”,但没有做它应该做的事情。调用该方法abortAll,它确实中止所有 XHR,但只清除数组的一半。它确实应该删除它中止的所有项目,但事实并非如此。

jQueryeach将获取数组的副本并对其进行迭代,因此即使元素已从原始数组中删除,我仍将从 0 到(复制的)数组中的最后一个索引。

但它仍然会出错,因为它splice作用于原始数组,它将元素移动到该数组中的前面的索引。但另一方面,isplice不断增加,因此二分之一的元素将在 中幸存下来。

可以abortAll 更正为:

$.xhrPool.abortAll = function () {
    $(this).each(function (i, jqXHR) {
        jqXHR.abort();
        // the element to be deleted will always be at index 0 in the original array:
        $.xhrPool.splice(0, 1); 
    });
});
Run Code Online (Sandbox Code Playgroud)

...但实际上,可以这样简单地完成:

$.xhrPool.abortAll = function () {
    $(this).each(function (i, jqXHR) {
        jqXHR.abort();
    });
    $.xhrPool.length = 0;
});
Run Code Online (Sandbox Code Playgroud)