/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; module.metadata = { "stability": "experimental" }; let { Class } = require("./heritage"); let { on, off } = require('../system/events'); let unloadSubject = require('@loader/unload'); let disposables = WeakMap(); function initialize(instance) { // Create an event handler that will dispose instance on unload. function handler(event) { if (event.subject.wrappedJSObject === unloadSubject) { instance.destroy(); } } // Form weak reference between disposable instance and an unload event // handler associated with it. This will make sure that event handler can't // be garbage collected as long as instance is referenced. Also note that // system events intentionally hold weak reference to an event handler, this // will let GC claim both instance and an unload handler before actual add-on // unload if instance contains no other references. disposables.set(instance, handler); on("sdk:loader:destroy", handler); } exports.initialize = initialize; function dispose(instance) { // Disposes given instance by removing it from weak map so that handler can // be GC-ed even if references to instance are kept. Also unregister unload // handler. let handler = disposables.get(instance); if (handler) off("sdk:loader:destroy", handler); disposables.delete(instance); } exports.dispose = dispose; // Base type that takes care of disposing it's instances on add-on unload. // Also makes sure to remove unload listener if it's already being disposed. let Disposable = Class({ initialize: function setupDisposable() { // First setup instance before initializing it's disposal. If instance // fails to initialize then there is no instance to be disposed at the // unload. this.setup.apply(this, arguments); initialize(this); }, setup: function setup() { // Implement your initialize logic here. }, dispose: function dispose() { // Implement your cleanup logic here. }, destroy: function destroy() { // Destroying disposable removes unload handler so that attempt to dispose // won't be made at unload & delegates to dispose. if (disposables.has(this)) { dispose(this); this.dispose(); } } }); exports.Disposable = Disposable;