{"id":153,"date":"2013-05-29T15:55:16","date_gmt":"2013-05-29T13:55:16","guid":{"rendered":"http:\/\/www.gijsk.com\/blog\/?p=153"},"modified":"2013-05-29T17:28:04","modified_gmt":"2013-05-29T15:28:04","slug":"you-dont-know-what-youve-got-till-its-gone-or-tab-load-detection-gone-wrong","status":"publish","type":"post","link":"https:\/\/www.gijsk.com\/blog\/2013\/05\/you-dont-know-what-youve-got-till-its-gone-or-tab-load-detection-gone-wrong\/","title":{"rendered":"You don&#8217;t know what you&#8217;ve got &#8217;till it&#8217;s gone &#8211; or, tab load detection gone wrong"},"content":{"rendered":"<p><strong>TL;DR: if you own\/wrote code that adds an event listener for the <code>\"load\"<\/code> event on a tab, doublecheck that you&#8217;re listening for that event on a tab&#8217;s <code>&lt;browser&gt;<\/code> element, and not on the <code>&lt;tab&gt;<\/code> (eg. the value returned by <code>gBrowser<\/code>&#8216;s <code>selectedTab<\/code> property).<\/strong><\/p>\n<p>In the past two weeks some of us on the Firefox front-end team have been working to get the UX tinderbox builds green again. When we initially started work on Australis, we broke a couple of tests and in the interests of moving forward those were not immediately fixed &#8211; we were on a branch, out of the way of everyone else, and it wasn&#8217;t our number one priority. Over time this resulted in pretty orange trees, and so we recently moved to fix all the tests we&#8217;d broken and return the tree to a functioning, green state.<\/p>\n<p>Although some tests did catch bugs on our side, in general we found subtle bugs in existing tests, which we have (helped) fix both on mozilla-central and the UX branch. One of those that I figured deserved a blogpost of its own was a pattern that tended to look roughly like this:<\/p>\n<pre lang=\"js\">let tab = targetBrowser.selectedTab;\r\nlet win = tab.linkedBrowser.contentWindow;\r\nlet expectedReadyState = aURL == \"about:blank\" ? [\"interactive\", \"complete\"] : [\"complete\"];\r\n\r\nif (aOnload) {\r\n  let handler = function() {\r\n    if (tab.linkedBrowser.currentURI.spec != aURL ||\r\n        expectedReadyState.indexOf((win.document || {}).readyState) == -1) {\r\n      return;\r\n    }\r\n    tab.removeEventListener(\"load\", handler, false);\r\n    executeSoon(aOnload);\r\n  }\r\n  tab.addEventListener(\"load\", handler, false);\r\n}<\/pre>\n<p>Unfortunately this code broke with the Australis changes, which <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=685059\">include removing the empty favicon for pages which don&#8217;t have one<\/a>. The bug in the code may not be immediately obvious, but what the code was doing was adding an event listener on a tabbed browser&#8217;s <code>&lt;tab&gt;<\/code> element (the leaf in the tabstrip at the top), rather than the corresponding <code>&lt;browser&gt;<\/code> (containing the actual page). Why did that work at all? Well, the tab element contains an image: the page&#8217;s favicon. When that loaded, a load event bubbled up. As we&#8217;re removing the favicon\u00a0if the page doesn&#8217;t have one, rather than replacing it with an empty placeholder as we do on current versions of Firefox, no such event fires for pages without a favicon, and the relevant tests\/code broke completely in Australis (for some of these tests, it is quite possible they caused occasional random orange before).<\/p>\n<p>The manual checking of the page&#8217;s <code>readyState<\/code> is a clue that this isn&#8217;t the best way to detect when the page has loaded. Instead of using <code>tab.addEventListener<\/code>, use <code>tab.linkedBrowser.addEventListener<\/code> (and the same for <code>removeEventListener<\/code>, of course).<\/p>\n<p>I&#8217;ve attempted to audit the mozilla-central tree for this kind of code, but I may not have been thorough enough by just grepping for things like <code>tab.addEventListener<\/code>. If you have written code depending on tab loads, be it in tests, or add-ons, or elsewhere, doublecheck how you detect these events!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR: if you own\/wrote code that adds an event listener for the &#8220;load&#8221; event on a tab, doublecheck that you&#8217;re listening for that event on a tab&#8217;s &lt;browser&gt; element, and not on the &lt;tab&gt; (eg. the value returned by gBrowser&#8216;s &hellip; <a href=\"https:\/\/www.gijsk.com\/blog\/2013\/05\/you-dont-know-what-youve-got-till-its-gone-or-tab-load-detection-gone-wrong\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-153","post","type-post","status-publish","format-standard","hentry","category-mozilla"],"_links":{"self":[{"href":"https:\/\/www.gijsk.com\/blog\/wp-json\/wp\/v2\/posts\/153"}],"collection":[{"href":"https:\/\/www.gijsk.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gijsk.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gijsk.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gijsk.com\/blog\/wp-json\/wp\/v2\/comments?post=153"}],"version-history":[{"count":5,"href":"https:\/\/www.gijsk.com\/blog\/wp-json\/wp\/v2\/posts\/153\/revisions"}],"predecessor-version":[{"id":157,"href":"https:\/\/www.gijsk.com\/blog\/wp-json\/wp\/v2\/posts\/153\/revisions\/157"}],"wp:attachment":[{"href":"https:\/\/www.gijsk.com\/blog\/wp-json\/wp\/v2\/media?parent=153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gijsk.com\/blog\/wp-json\/wp\/v2\/categories?post=153"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gijsk.com\/blog\/wp-json\/wp\/v2\/tags?post=153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}