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

Posted

技术标签:

【中文标题】当 $.each 和 array.splice(i) 保持在一起时,JQuery 处理数组超出索引错误【英文标题】:JQuery handles array out of index errors when $.each and array.splice(i) are kept together 【发布时间】:2018-01-12 00:25:39 【问题描述】:

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

And this is what I found:

$.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.
    );
;

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

下面是让我困惑的部分,

$(this).each(function (i, jqXHR) 
        $.xhrPool.splice(i, 1);
);

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

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

然后在下一次迭代中,i 的值增加,因此被咳嗽的元素会有所不同(或不符合预期)。

例如考虑数组 = [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]

迭代 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]

迭代 3

array = [2,4,5,6,7,8,9,10]
i=2
removes 5
new array is [2,4,6,7,8,9,10]

迭代 4

array = [2,4,6,7,8,9,10]
i=3
removes 7
new array is [2,4,6,8,9,10]

迭代 5

array = [2,4,6,8,9,10]
i=4
removes 9
new array is [2,4,6,8,10]

迭代 6

array = [2,4,6,8,10]
i=5

** 麻烦来了。

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

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

【问题讨论】:

【参考方案1】:

代码“有效”,但没有做它应该做的事情。该方法称为abortAll,它确实中止所有XHR,但只清除数组的一半。它应该真正删除它中止的所有项目,但它没有。

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

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

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); 
    );
);

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

$.xhrPool.abortAll = function () 
    $(this).each(function (i, jqXHR) 
        jqXHR.abort();
    );
    $.xhrPool.length = 0;
);

【讨论】:

感谢您的回复。您的第二种方法有一个小缺点,它会重新初始化数组,因此 abortAll 方法将从数组中删除,我们将不得不再次重新初始化它以将方法附加到数组中。 确实,我已经更新了答案以避免重新初始化。 现在完美了:)

以上是关于当 $.each 和 array.splice(i) 保持在一起时,JQuery 处理数组超出索引错误的主要内容,如果未能解决你的问题,请参考以下文章

Deleting array elements in JavaScript - delete vs splice

js去掉数组中的空字符串

array.splice = 是啥意思?

去除数组中的空值

js splice()

splice和slice的区别