- Motivation and Trade-offs
- Detecting a “Shutdown” Event
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Inject a Function With Arguments
What if you want to inject a pre-defined function in your extension into your target page? Take the above codeblock one step further and pass in a “stringified” function. Concatenation coerces the function into a string, and you can pass in an args array via JSON.stringify(). In the example below, you’ll still need the tab id, and permission as declared in your manifest.json.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Motivation and Trade-offs
The External Stereopaw Code
Clicking the marklet adds the external “stereopaw code” to the DOM, and launches a setInterval() loop that repeatedly renders track data and an updated timestamp. When the page overlay is closed, the event kills the loop.
NB: Implementing an observer pattern is likely even better, but in the interest of “keeping it simple,” I decided to go with a loop.
Detecting a Shutdown Event
Chrome Extension components can cross-communicate via message passing. With stereopaw, the injected code’s setInterval() repeatedly sends a message containing track data and an updated timestamp. Upon closing the browser extension, the injected loop will waste resources, and continously send messages to nobody in particular. The problem compounds when the user runs the extension again, as another loop activates, and messages are now sent twice as often. The solution is two-fold: detect when the extension is closed, and then send a shutdown message / inject some “shutdown code” – or both.
We mimic a shutdown event – the popup / content script closing – by doing the following:
- Establish an extension connection
- Listen for a port.onDisconnect event, which fires when the popup is no longer active
- Inject a shutdown function, or pass a shutdown message
Establishing a connection is straightforward. Simply stick the following in a content script:
And the latter block in a background page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
When the content script is opened, chrome.extension.connect() establishes a connection. This event triggers the connection listener (1) in the background script, which adds a listener for the port.OnDisconnect event (2). Now you’re notified when the extension shuts down.
In this example, when the port.onDisconnect event fires, a message listener (3) is added that sends a shutdown response to the injected code, which is continuously messaging track information to a separate listener in the extension. It’s important to note that various messages may be passed at any given time, so the if-statement acts as a filter for the particular message source that can handle a shutdown response. One could additionally initiate a message through the shared DOM via port.postMessage, but opting for simplicity, I chose to keep the shutdown logic solely in the extension code, as opposed to adding an additional listener in the external “stereopaw code”. Lastly, one can inject shutdown code – the kill() function, as done above.
More detailed examples regarding extension message passing can be found in Google’s documentation.