disposable.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. module.metadata = {
  6. "stability": "experimental"
  7. };
  8. let { Class } = require("./heritage");
  9. let { on, off } = require('../system/events');
  10. let unloadSubject = require('@loader/unload');
  11. let disposables = WeakMap();
  12. function initialize(instance) {
  13. // Create an event handler that will dispose instance on unload.
  14. function handler(event) {
  15. if (event.subject.wrappedJSObject === unloadSubject) {
  16. instance.destroy();
  17. }
  18. }
  19. // Form weak reference between disposable instance and an unload event
  20. // handler associated with it. This will make sure that event handler can't
  21. // be garbage collected as long as instance is referenced. Also note that
  22. // system events intentionally hold weak reference to an event handler, this
  23. // will let GC claim both instance and an unload handler before actual add-on
  24. // unload if instance contains no other references.
  25. disposables.set(instance, handler);
  26. on("sdk:loader:destroy", handler);
  27. }
  28. exports.initialize = initialize;
  29. function dispose(instance) {
  30. // Disposes given instance by removing it from weak map so that handler can
  31. // be GC-ed even if references to instance are kept. Also unregister unload
  32. // handler.
  33. let handler = disposables.get(instance);
  34. if (handler) off("sdk:loader:destroy", handler);
  35. disposables.delete(instance);
  36. }
  37. exports.dispose = dispose;
  38. // Base type that takes care of disposing it's instances on add-on unload.
  39. // Also makes sure to remove unload listener if it's already being disposed.
  40. let Disposable = Class({
  41. initialize: function setupDisposable() {
  42. // First setup instance before initializing it's disposal. If instance
  43. // fails to initialize then there is no instance to be disposed at the
  44. // unload.
  45. this.setup.apply(this, arguments);
  46. initialize(this);
  47. },
  48. setup: function setup() {
  49. // Implement your initialize logic here.
  50. },
  51. dispose: function dispose() {
  52. // Implement your cleanup logic here.
  53. },
  54. destroy: function destroy() {
  55. // Destroying disposable removes unload handler so that attempt to dispose
  56. // won't be made at unload & delegates to dispose.
  57. if (disposables.has(this)) {
  58. dispose(this);
  59. this.dispose();
  60. }
  61. }
  62. });
  63. exports.Disposable = Disposable;