Subscription.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. "use strict";
  2. exports.__esModule = true;
  3. exports.createSubscription = createSubscription;
  4. var _batch = require("./batch");
  5. function createListenerCollection() {
  6. const batch = (0, _batch.getBatch)();
  7. let first = null;
  8. let last = null;
  9. return {
  10. clear() {
  11. first = null;
  12. last = null;
  13. },
  14. notify() {
  15. batch(() => {
  16. let listener = first;
  17. while (listener) {
  18. listener.callback();
  19. listener = listener.next;
  20. }
  21. });
  22. },
  23. get() {
  24. let listeners = [];
  25. let listener = first;
  26. while (listener) {
  27. listeners.push(listener);
  28. listener = listener.next;
  29. }
  30. return listeners;
  31. },
  32. subscribe(callback) {
  33. let isSubscribed = true;
  34. let listener = last = {
  35. callback,
  36. next: null,
  37. prev: last
  38. };
  39. if (listener.prev) {
  40. listener.prev.next = listener;
  41. } else {
  42. first = listener;
  43. }
  44. return function unsubscribe() {
  45. if (!isSubscribed || first === null) return;
  46. isSubscribed = false;
  47. if (listener.next) {
  48. listener.next.prev = listener.prev;
  49. } else {
  50. last = listener.prev;
  51. }
  52. if (listener.prev) {
  53. listener.prev.next = listener.next;
  54. } else {
  55. first = listener.next;
  56. }
  57. };
  58. }
  59. };
  60. }
  61. const nullListeners = {
  62. notify() {},
  63. get: () => []
  64. };
  65. function createSubscription(store, parentSub) {
  66. let unsubscribe;
  67. let listeners = nullListeners; // Reasons to keep the subscription active
  68. let subscriptionsAmount = 0; // Is this specific subscription subscribed (or only nested ones?)
  69. let selfSubscribed = false;
  70. function addNestedSub(listener) {
  71. trySubscribe();
  72. const cleanupListener = listeners.subscribe(listener); // cleanup nested sub
  73. let removed = false;
  74. return () => {
  75. if (!removed) {
  76. removed = true;
  77. cleanupListener();
  78. tryUnsubscribe();
  79. }
  80. };
  81. }
  82. function notifyNestedSubs() {
  83. listeners.notify();
  84. }
  85. function handleChangeWrapper() {
  86. if (subscription.onStateChange) {
  87. subscription.onStateChange();
  88. }
  89. }
  90. function isSubscribed() {
  91. return selfSubscribed;
  92. }
  93. function trySubscribe() {
  94. subscriptionsAmount++;
  95. if (!unsubscribe) {
  96. unsubscribe = parentSub ? parentSub.addNestedSub(handleChangeWrapper) : store.subscribe(handleChangeWrapper);
  97. listeners = createListenerCollection();
  98. }
  99. }
  100. function tryUnsubscribe() {
  101. subscriptionsAmount--;
  102. if (unsubscribe && subscriptionsAmount === 0) {
  103. unsubscribe();
  104. unsubscribe = undefined;
  105. listeners.clear();
  106. listeners = nullListeners;
  107. }
  108. }
  109. function trySubscribeSelf() {
  110. if (!selfSubscribed) {
  111. selfSubscribed = true;
  112. trySubscribe();
  113. }
  114. }
  115. function tryUnsubscribeSelf() {
  116. if (selfSubscribed) {
  117. selfSubscribed = false;
  118. tryUnsubscribe();
  119. }
  120. }
  121. const subscription = {
  122. addNestedSub,
  123. notifyNestedSubs,
  124. handleChangeWrapper,
  125. isSubscribed,
  126. trySubscribe: trySubscribeSelf,
  127. tryUnsubscribe: tryUnsubscribeSelf,
  128. getListeners: () => listeners
  129. };
  130. return subscription;
  131. }