unload.js 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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. // Parts of this module were taken from narwhal:
  5. //
  6. // http://narwhaljs.org
  7. module.metadata = {
  8. "stability": "experimental"
  9. };
  10. const { on, off } = require('./events');
  11. const unloadSubject = require('@loader/unload');
  12. const observers = [];
  13. const unloaders = [];
  14. var when = exports.when = function when(observer) {
  15. if (observers.indexOf(observer) != -1)
  16. return;
  17. observers.unshift(observer);
  18. };
  19. var ensure = exports.ensure = function ensure(obj, destructorName) {
  20. if (!destructorName)
  21. destructorName = "unload";
  22. if (!(destructorName in obj))
  23. throw new Error("object has no '" + destructorName + "' property");
  24. let called = false;
  25. let originalDestructor = obj[destructorName];
  26. function unloadWrapper(reason) {
  27. if (!called) {
  28. called = true;
  29. let index = unloaders.indexOf(unloadWrapper);
  30. if (index == -1)
  31. throw new Error("internal error: unloader not found");
  32. unloaders.splice(index, 1);
  33. originalDestructor.call(obj, reason);
  34. originalDestructor = null;
  35. destructorName = null;
  36. obj = null;
  37. }
  38. };
  39. // TODO: Find out why the order is inverted here. It seems that
  40. // it may be causing issues!
  41. unloaders.push(unloadWrapper);
  42. obj[destructorName] = unloadWrapper;
  43. };
  44. function unload(reason) {
  45. observers.forEach(function(observer) {
  46. try {
  47. observer(reason);
  48. }
  49. catch (error) {
  50. console.exception(error);
  51. }
  52. });
  53. }
  54. when(function(reason) {
  55. unloaders.slice().forEach(function(unloadWrapper) {
  56. unloadWrapper(reason);
  57. });
  58. });
  59. on('sdk:loader:destroy', function onunload({ subject, data: reason }) {
  60. // If this loader is unload then `subject.wrappedJSObject` will be
  61. // `destructor`.
  62. if (subject.wrappedJSObject === unloadSubject) {
  63. off('sdk:loader:destroy', onunload);
  64. unload(reason);
  65. }
  66. // Note that we use strong reference to listener here to make sure it's not
  67. // GC-ed, which may happen otherwise since nothing keeps reference to `onunolad`
  68. // function.
  69. }, true);