mobx 7.0.3 → 7.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -822,6 +822,19 @@
822
822
  extend_
823
823
  };
824
824
  }
825
+ // The auto annotation only depends on `deep` and `autoBind`, so share one instance per combination
826
+ // instead of allocating one for every object created with options
827
+ const autoAnnotations = [autoAnnotation];
828
+ function getAutoAnnotation(options) {
829
+ var _autoAnnotations$idx;
830
+ const deep = options.deep !== false;
831
+ const autoBind = !!options.autoBind;
832
+ const idx = (deep ? 0 : 1) | (autoBind ? 2 : 0);
833
+ return (_autoAnnotations$idx = autoAnnotations[idx]) != null ? _autoAnnotations$idx : autoAnnotations[idx] = createAutoAnnotation({
834
+ deep,
835
+ autoBind
836
+ });
837
+ }
825
838
  function make_$1(adm, key, descriptor, source) {
826
839
  var _this$options_3, _this$options_4;
827
840
  // getter -> computed
@@ -938,7 +951,7 @@
938
951
  }
939
952
  function getAnnotationFromOptions(options) {
940
953
  var _options$defaultDecor;
941
- return options ? (_options$defaultDecor = options.defaultDecorator) != null ? _options$defaultDecor : createAutoAnnotation(options) : undefined;
954
+ return options ? (_options$defaultDecor = options.defaultDecorator) != null ? _options$defaultDecor : getAutoAnnotation(options) : undefined;
942
955
  }
943
956
  function getEnhancerFromAnnotation(annotation) {
944
957
  var _annotation$options_$, _annotation$options_;
@@ -1390,7 +1403,10 @@
1390
1403
  reportObserved(this);
1391
1404
  if (shouldCompute(this)) {
1392
1405
  let prevTrackingContext = globalState.trackingContext;
1393
- if (this.keepAlive_ && !prevTrackingContext) {
1406
+ if (!prevTrackingContext && (this.keepAlive_ || this.isBeingObserved)) {
1407
+ // An observed or keep-alive computed can be recomputed by an untracked
1408
+ // read, for example from inside an action. Its dependencies are still
1409
+ // transitively observed and must fire their lifecycle hooks
1394
1410
  globalState.trackingContext = this;
1395
1411
  }
1396
1412
  if (this.trackAndCompute()) {
@@ -1987,34 +2003,41 @@
1987
2003
  // the nested call instead of recursing; the outer loop re-reads list.length on
1988
2004
  // every iteration, so it picks up anything the nested dispose() pushes onto the
1989
2005
  // same pendingUnobservations array.
1990
- if (!globalState.isRunningUnobservations) {
1991
- globalState.isRunningUnobservations = true;
1992
- try {
1993
- const list = globalState.pendingUnobservations;
1994
- for (let i = 0; i < list.length; i++) {
1995
- const observable = list[i];
1996
- observable.isPendingUnobservation = false;
1997
- if (!observable.observers_ || observable.observers_.size === 0) {
1998
- if (observable.isBeingObserved) {
1999
- // if this observable had reactive observers, trigger the hooks
2000
- observable.isBeingObserved = false;
2001
- observable.onBUO();
2002
- }
2003
- if (observable instanceof ComputedValue) {
2004
- // computed values are automatically teared down when the last observer leaves
2005
- // this process happens recursively, this computed might be the last observabe of another, etc..
2006
- observable.suspend_();
2007
- }
2008
- }
2006
+ if (!globalState.isRunningUnobservations && globalState.pendingUnobservations.length > 0) {
2007
+ runPendingUnobservations();
2008
+ }
2009
+ }
2010
+ }
2011
+ // Only called when there is something to unobserve, so the common endBatch() skips the
2012
+ // try/finally and the pendingUnobservations reallocation entirely
2013
+ function runPendingUnobservations() {
2014
+ globalState.isRunningUnobservations = true;
2015
+ try {
2016
+ const list = globalState.pendingUnobservations;
2017
+ for (let i = 0; i < list.length; i++) {
2018
+ const observable = list[i];
2019
+ observable.isPendingUnobservation = false;
2020
+ if (!observable.observers_ || observable.observers_.size === 0) {
2021
+ // release the empty Set so unobserved atoms don't keep paying for it
2022
+ observable.observers_ = null;
2023
+ if (observable.isBeingObserved) {
2024
+ // if this observable had reactive observers, trigger the hooks
2025
+ observable.isBeingObserved = false;
2026
+ observable.onBUO();
2027
+ }
2028
+ if (observable instanceof ComputedValue) {
2029
+ // computed values are automatically teared down when the last observer leaves
2030
+ // this process happens recursively, this computed might be the last observabe of another, etc..
2031
+ observable.suspend_();
2009
2032
  }
2010
- globalState.pendingUnobservations = [];
2011
- } finally {
2012
- // Always release the guard, even if an onBUO handler (user code) threw,
2013
- // otherwise every future endBatch() would see isRunningUnobservations
2014
- // stuck true and silently stop draining pendingUnobservations forever.
2015
- globalState.isRunningUnobservations = false;
2016
2033
  }
2017
2034
  }
2035
+ globalState.pendingUnobservations = [];
2036
+ } finally {
2037
+ // Always release the guard, even if an onBUO handler (user code) threw,
2038
+ // otherwise every future endBatch() would see isRunningUnobservations
2039
+ // stuck true and silently stop draining pendingUnobservations forever.
2040
+ globalState.isRunningUnobservations = false;
2018
2041
  }
2019
2042
  }
2020
2043
  /**
@@ -3293,8 +3316,13 @@
3293
3316
  return interceptable.interceptors_ !== undefined && interceptable.interceptors_.length > 0;
3294
3317
  }
3295
3318
  function registerInterceptor(interceptable, handler) {
3296
- const interceptors = interceptable.interceptors_ || (interceptable.interceptors_ = []);
3297
- interceptors.push(handler);
3319
+ let interceptors = interceptable.interceptors_;
3320
+ if (interceptors) {
3321
+ interceptors.push(handler);
3322
+ } else {
3323
+ // Allocate at the exact size: pushing onto an empty array over-allocates its backing store
3324
+ interceptors = interceptable.interceptors_ = [handler];
3325
+ }
3298
3326
  return once(() => {
3299
3327
  const idx = interceptors.indexOf(handler);
3300
3328
  if (idx !== -1) {
@@ -3326,8 +3354,13 @@
3326
3354
  return listenable.changeListeners_ !== undefined && listenable.changeListeners_.length > 0;
3327
3355
  }
3328
3356
  function registerListener(listenable, handler) {
3329
- const listeners = listenable.changeListeners_ || (listenable.changeListeners_ = []);
3330
- listeners.push(handler);
3357
+ let listeners = listenable.changeListeners_;
3358
+ if (listeners) {
3359
+ listeners.push(handler);
3360
+ } else {
3361
+ // Allocate at the exact size: pushing onto an empty array over-allocates its backing store
3362
+ listeners = listenable.changeListeners_ = [handler];
3363
+ }
3331
3364
  return once(() => {
3332
3365
  const idx = listeners.indexOf(handler);
3333
3366
  if (idx !== -1) {