gBrowser.getBrowserAtIndex(i)有时会在removeTab()上失败

时间:2014-10-06 06:59:57

标签: firefox-addon firefox-addon-restartless

考虑以下(简化)示例可以正常工作:

var tabs = window.gBrowser.tabs;
for (var i = 2, len = tabs.length; i < len; i++) {
  var uri = window.gBrowser.getBrowserAtIndex(i).currentURI.spec;
}

以下有时最后标签上失败并显示消息 window.gBrowser.getBrowserAtIndex(...)未定义

var tabs = window.gBrowser.tabs;
for (var i = 2, len = tabs.length; i < len; i++) {
  var uri = window.gBrowser.getBrowserAtIndex(i).currentURI.spec;
  window.gBrowser.removeTab(window.gBrowser.tabContainer.childNodes[i]);
}

我不明白为什么它会失败,为什么它有时会失败而不是一直都失败。

是否可以使用其他方法代替gBrowser.getBrowserAtIndex(i)来获取标签的网址?

2 个答案:

答案 0 :(得分:2)

根本问题是tabs不是数组而是NodeList,即实时集合。当您致电removeTab()时,更改会反映在NodeList(长度,索引)中。

为避免这些副作用,请将其转换为真正的数组

var tabsArr = [].slice.call(gBrowser.tabs);

答案 1 :(得分:1)

您似乎正在关闭一个循环内的标签页,其中您已存储了标签len = tabs.length的初始数量,然后在现有标签数量可能因您的操作而发生变化时与标签的原始数量进行比较。

构造:
for (let i = 2, len = tabs.length; i < len; i++) {...}
tabs的长度不会改变的条件下更有效。但是,在这种情况下,您要更改选项卡的数量,并且每次检查此循环的终止条件时都需要与tabs.length进行比较。所以:
for (let i = 2, len = tabs.length; i < len; i++) {...}
实际上,当前循环总是失败的唯一原因是window.gBrowser.removeTab()在实际删除选项卡之前返回。您正在竞争中查看是否在实际删除任何选项卡之前完成循环。

但是,这不是唯一的问题。您正在删除当前编入索引的选项卡。在大多数情况下,如果删除选项卡(如大多数数组),则剩余的较高索引选项卡将向下移动到您正在处理的索引处。当前循环不会定期跳过其他每个选项卡的唯一原因是window.gBrowser.removeTab()在实际删除当前已编入索引的选项卡之前返回。实际上,只有在您看到undefined错误的情况下才跳过选项卡。

你的循环应该是这样的:
for (let i = tabs.length - 1; i >=2; i--) {...}
这样,您从列表的末尾开始,然后从那里删除。通过消除在实际删除任何标签之前需要完成整个过程的竞争条件,这可以防止undefined问题和跳过标签的可能性。