Subscription.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import { getBatch } from './batch'; // encapsulates the subscription logic for connecting a component to the redux store, as
  2. // well as nesting subscriptions of descendant components, so that we can ensure the
  3. // ancestor components re-render before descendants
  4. function createListenerCollection() {
  5. var batch = getBatch();
  6. var first = null;
  7. var last = null;
  8. return {
  9. clear: function clear() {
  10. first = null;
  11. last = null;
  12. },
  13. notify: function notify() {
  14. batch(function () {
  15. var listener = first;
  16. while (listener) {
  17. listener.callback();
  18. listener = listener.next;
  19. }
  20. });
  21. },
  22. get: function get() {
  23. var listeners = [];
  24. var listener = first;
  25. while (listener) {
  26. listeners.push(listener);
  27. listener = listener.next;
  28. }
  29. return listeners;
  30. },
  31. subscribe: function subscribe(callback) {
  32. var isSubscribed = true;
  33. var listener = last = {
  34. callback: callback,
  35. next: null,
  36. prev: last
  37. };
  38. if (listener.prev) {
  39. listener.prev.next = listener;
  40. } else {
  41. first = listener;
  42. }
  43. return function unsubscribe() {
  44. if (!isSubscribed || first === null) return;
  45. isSubscribed = false;
  46. if (listener.next) {
  47. listener.next.prev = listener.prev;
  48. } else {
  49. last = listener.prev;
  50. }
  51. if (listener.prev) {
  52. listener.prev.next = listener.next;
  53. } else {
  54. first = listener.next;
  55. }
  56. };
  57. }
  58. };
  59. }
  60. var nullListeners = {
  61. notify: function notify() {},
  62. get: function get() {
  63. return [];
  64. }
  65. };
  66. export function createSubscription(store, parentSub) {
  67. var unsubscribe;
  68. var listeners = nullListeners;
  69. function addNestedSub(listener) {
  70. trySubscribe();
  71. return listeners.subscribe(listener);
  72. }
  73. function notifyNestedSubs() {
  74. listeners.notify();
  75. }
  76. function handleChangeWrapper() {
  77. if (subscription.onStateChange) {
  78. subscription.onStateChange();
  79. }
  80. }
  81. function isSubscribed() {
  82. return Boolean(unsubscribe);
  83. }
  84. function trySubscribe() {
  85. if (!unsubscribe) {
  86. unsubscribe = parentSub ? parentSub.addNestedSub(handleChangeWrapper) : store.subscribe(handleChangeWrapper);
  87. listeners = createListenerCollection();
  88. }
  89. }
  90. function tryUnsubscribe() {
  91. if (unsubscribe) {
  92. unsubscribe();
  93. unsubscribe = undefined;
  94. listeners.clear();
  95. listeners = nullListeners;
  96. }
  97. }
  98. var subscription = {
  99. addNestedSub: addNestedSub,
  100. notifyNestedSubs: notifyNestedSubs,
  101. handleChangeWrapper: handleChangeWrapper,
  102. isSubscribed: isSubscribed,
  103. trySubscribe: trySubscribe,
  104. tryUnsubscribe: tryUnsubscribe,
  105. getListeners: function getListeners() {
  106. return listeners;
  107. }
  108. };
  109. return subscription;
  110. }