Chrome扩展程序,JavaScript:为什么会触发两次?

19

我有一个非常简单的代码块在我的(测试)Chrome扩展中:

    function test()
    {
    alert("In test!");
    }

   chrome.tabs.onUpdated.addListener(function(tabid, changeinfo, tab) {
    var url = tab.url;
        if (url !== undefined) {

        test();
    }
   });

我的问题是,为什么test()会触发两次?更重要的是,我该如何使它只触发一次?


我猜测可能有两个选项卡更新,导致事件处理程序触发两次。 - Rob Sobers
我只有那一段代码...那第二段从哪里来的? - Ryan
看起来你的代码好像只会调用一次test(),但实际上它可能会调用任意次数。 - Rob Sobers
很好的发现,Rob。为了更准确地描述“任意次数”,并回答第二个调用来自哪里的问题:每次初始标签加载都会将标签的状态更新为“正在加载”-> 调用#1。当它完成加载时,它的状态将被更新为“完成”-> 调用#2。因此,对于每个页面加载,标签对象都会更新两次。 - eyecatchUp
7个回答

39

看看事件被派发时的不同状态。我推测,它在状态为"loading"或"complete"时被派发一次。如果是这样的话,你的问题将会得到解决:

 function test()
    {
    alert("In test!");
    }

   chrome.tabs.onUpdated.addListener(function(tabid, changeinfo, tab) {
    var url = tab.url;
        if (url !== undefined && changeinfo.status == "complete") {

        test();
    }
   });

3
不,它只是忘记重新加载扩展程序了:)) 我需要等待3分钟才能接受你的答案... 谢谢 - Ryan
2
很遗憾,我和@Nikklas一样也遇到了同样的问题,而且两次状态都显示为“完成”。Chrome怎么回事? - Jonathan Dumaine
1
哦,我很高兴找到了这个页面。我一直在想为什么它会触发两次。现在,我明白了! - crzyonez777
2
为了澄清,它会在任何更新时触发,而且有不同类型的更新。更新可以是URL更改、网站图标、状态等。因此,您需要查看changeinfo对象以查看它是哪种类型的更改。对于我来说,我首先检查changeinfo是否表示更新是“状态”更改,然后如果选项卡状态为“完成” if (changeinfo && changinfo.status && tab && tab.status == 'complete') 在将所有参数打印到控制台后,我发现了这一点。 - Joseph Shih

11

我也被这个问题困扰过,并试图找到答案。只有经过一些试验,我才弄清楚为什么我会收到多个“完成”更新事件,而我认为只是一个单页“更新”。

如果你的页面有iframes,则每个iframe都会触发一个“完成”事件,并冒泡到父级内容脚本。因此,更复杂的页面如果有iframes,将触发一系列onUpdated事件。


我的页面中没有iframes。 - Ryan
是的,那就是我的情况。它发生在复杂页面上,所以我至少收到了7个“完成”事件,现在我必须处理这个问题 :) - Artiom

2
当你编写以下代码时:
chrome.tabs.onUpdated.addListener(function(tabid, changeinfo, tab) {
    var url = tab.url;
        if (url !== undefined) {

        test();
    }
});

您正在调用addListener,并告诉它在标签页更新时而不是立即立即调用test()。 Chrome浏览器本身广播标签页更新事件,从而导致您的test()代码运行。

2
我知道这已经过时了,但是无论如何...我也遇到了这个问题,也许这可以帮助某些人。查看处理程序函数接收到的Tab对象,我发现favIconUrl属性在两次调用中不同,所以我猜它与此有关,尽管我不知道背后的原因。
我认为这是一个错误,但经过第二次思考和一些测试,我排除了错误的理论。
到目前为止,我所知道的是,如果更改了两个属性,则使用changeInfo对象触发两次事件,每次包含一个属性。换句话说,例如如果更改的属性是状态和favIconUrl,则会触发两次事件。
changeInfo = {status:"complete"};

然后在下一次调用中

changeInfo = {favIconuUrl : ".... whatever ..."};

1

虽然我不确定我们的代码为什么会触发两次,但我遇到了类似的问题,这个答案对我帮助很大。

https://dev59.com/Im025IYBdhLWcg3wLitX#49307437 Vaibhav的答案非常聪明地将验证作为请求的details对象的一部分。 当记录details对象时,我注意到原始触发具有0的frameId,而第二次触发总是其他东西。因此,我喜欢使用if语句来返回并退出,而不是积极验证您是否在URL的正确提交中使用重复条目。 我在这里使用onCompleted,但对于onUpdated也应该有效。

chrome.webNavigation.onCompleted.addListener(details => {
    //need to make sure that this only triggers once per navigation
    console.log(details);
    if (details.frameId !== 0) return;
});

0
我通过检查更新时选项卡的标题来解决了这个问题:
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {

var title = changeInfo.title;
    if (title !== undefined) {
       doSomething();
    }
});

-1

Twice 是因为状态一次是 loading,一次是 completed。 如果你不关心状态,也可以尝试 onCreated 事件。它只会触发一次!


如上所述,当状态为“complete”(多个完成)时它可以触发不止一次。在打印参数后,您可以看到它是由于网站图标触发更新而激活的。因此,检查changeInfo对象以确定它是否是“status”更改,然后检查选项卡的状态是否为“complete”,这样可以确保您只能在页面加载完成时看到它。 - Joseph Shih
现在使用 onCreated,它根本不会触发! - Shayan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接