mobx 7.0.4 → 7.0.6

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.
package/dist/mobx.esm.js CHANGED
@@ -819,6 +819,19 @@ function createAutoAnnotation(options) {
819
819
  extend_
820
820
  };
821
821
  }
822
+ // The auto annotation only depends on `deep` and `autoBind`, so share one instance per combination
823
+ // instead of allocating one for every object created with options
824
+ const autoAnnotations = [autoAnnotation];
825
+ function getAutoAnnotation(options) {
826
+ var _autoAnnotations$idx;
827
+ const deep = options.deep !== false;
828
+ const autoBind = !!options.autoBind;
829
+ const idx = (deep ? 0 : 1) | (autoBind ? 2 : 0);
830
+ return (_autoAnnotations$idx = autoAnnotations[idx]) != null ? _autoAnnotations$idx : autoAnnotations[idx] = createAutoAnnotation({
831
+ deep,
832
+ autoBind
833
+ });
834
+ }
822
835
  function make_$1(adm, key, descriptor, source) {
823
836
  var _this$options_3, _this$options_4;
824
837
  // getter -> computed
@@ -935,7 +948,7 @@ function getEnhancerFromOptions(options) {
935
948
  }
936
949
  function getAnnotationFromOptions(options) {
937
950
  var _options$defaultDecor;
938
- return options ? (_options$defaultDecor = options.defaultDecorator) != null ? _options$defaultDecor : createAutoAnnotation(options) : undefined;
951
+ return options ? (_options$defaultDecor = options.defaultDecorator) != null ? _options$defaultDecor : getAutoAnnotation(options) : undefined;
939
952
  }
940
953
  function getEnhancerFromAnnotation(annotation) {
941
954
  var _annotation$options_$, _annotation$options_;
@@ -1181,14 +1194,13 @@ class ObservableValue extends Atom {
1181
1194
  this.equals_ = equals_;
1182
1195
  this.value_ = enhancer_(value, undefined, name_);
1183
1196
  if (__MOBX_DEV__ && notifySpy && isSpyEnabled()) {
1184
- var _this$value_;
1185
1197
  // only notify spy if this is a stand-alone observable
1186
1198
  spyReport({
1187
1199
  type: CREATE,
1188
1200
  object: this,
1189
1201
  observableKind: "value",
1190
1202
  debugObjectName: this.name_,
1191
- newValue: "" + ((_this$value_ = this.value_) == null ? void 0 : _this$value_.toString())
1203
+ newValue: this.value_
1192
1204
  });
1193
1205
  }
1194
1206
  }
@@ -1996,34 +2008,41 @@ function endBatch() {
1996
2008
  // the nested call instead of recursing; the outer loop re-reads list.length on
1997
2009
  // every iteration, so it picks up anything the nested dispose() pushes onto the
1998
2010
  // same pendingUnobservations array.
1999
- if (!globalState.isRunningUnobservations) {
2000
- globalState.isRunningUnobservations = true;
2001
- try {
2002
- const list = globalState.pendingUnobservations;
2003
- for (let i = 0; i < list.length; i++) {
2004
- const observable = list[i];
2005
- observable.isPendingUnobservation = false;
2006
- if (!observable.observers_ || observable.observers_.size === 0) {
2007
- if (observable.isBeingObserved) {
2008
- // if this observable had reactive observers, trigger the hooks
2009
- observable.isBeingObserved = false;
2010
- observable.onBUO();
2011
- }
2012
- if (observable instanceof ComputedValue) {
2013
- // computed values are automatically teared down when the last observer leaves
2014
- // this process happens recursively, this computed might be the last observabe of another, etc..
2015
- observable.suspend_();
2016
- }
2017
- }
2011
+ if (!globalState.isRunningUnobservations && globalState.pendingUnobservations.length > 0) {
2012
+ runPendingUnobservations();
2013
+ }
2014
+ }
2015
+ }
2016
+ // Only called when there is something to unobserve, so the common endBatch() skips the
2017
+ // try/finally and the pendingUnobservations reallocation entirely
2018
+ function runPendingUnobservations() {
2019
+ globalState.isRunningUnobservations = true;
2020
+ try {
2021
+ const list = globalState.pendingUnobservations;
2022
+ for (let i = 0; i < list.length; i++) {
2023
+ const observable = list[i];
2024
+ observable.isPendingUnobservation = false;
2025
+ if (!observable.observers_ || observable.observers_.size === 0) {
2026
+ // release the empty Set so unobserved atoms don't keep paying for it
2027
+ observable.observers_ = null;
2028
+ if (observable.isBeingObserved) {
2029
+ // if this observable had reactive observers, trigger the hooks
2030
+ observable.isBeingObserved = false;
2031
+ observable.onBUO();
2032
+ }
2033
+ if (observable instanceof ComputedValue) {
2034
+ // computed values are automatically teared down when the last observer leaves
2035
+ // this process happens recursively, this computed might be the last observabe of another, etc..
2036
+ observable.suspend_();
2018
2037
  }
2019
- globalState.pendingUnobservations = [];
2020
- } finally {
2021
- // Always release the guard, even if an onBUO handler (user code) threw,
2022
- // otherwise every future endBatch() would see isRunningUnobservations
2023
- // stuck true and silently stop draining pendingUnobservations forever.
2024
- globalState.isRunningUnobservations = false;
2025
2038
  }
2026
2039
  }
2040
+ globalState.pendingUnobservations = [];
2041
+ } finally {
2042
+ // Always release the guard, even if an onBUO handler (user code) threw,
2043
+ // otherwise every future endBatch() would see isRunningUnobservations
2044
+ // stuck true and silently stop draining pendingUnobservations forever.
2045
+ globalState.isRunningUnobservations = false;
2027
2046
  }
2028
2047
  }
2029
2048
  /**
@@ -2153,6 +2172,7 @@ class Reaction {
2153
2172
  this.runId_ = 0;
2154
2173
  this.unboundDepsCount_ = 0;
2155
2174
  this.flags_ = 0b00000;
2175
+ this.removeAbortListener_ = undefined;
2156
2176
  this.name_ = name_;
2157
2177
  this.onInvalidate_ = onInvalidate_;
2158
2178
  this.errorHandler_ = errorHandler_;
@@ -2289,7 +2309,10 @@ class Reaction {
2289
2309
  }
2290
2310
  dispose() {
2291
2311
  if (!this.isDisposed) {
2312
+ var _this$removeAbortList;
2292
2313
  this.isDisposed = true;
2314
+ // also covers self-disposal (`r.dispose()`, `when`), which bypasses the disposer
2315
+ (_this$removeAbortList = this.removeAbortListener_) == null || _this$removeAbortList.call(this);
2293
2316
  if (!this.isRunning) {
2294
2317
  // if disposed while running, clean up later. Maybe not optimal, but rare case
2295
2318
  startBatch();
@@ -2299,11 +2322,11 @@ class Reaction {
2299
2322
  }
2300
2323
  }
2301
2324
  getDisposer_(abortSignal) {
2302
- const dispose = () => {
2303
- this.dispose();
2304
- abortSignal == null || abortSignal.removeEventListener == null || abortSignal.removeEventListener("abort", dispose);
2305
- };
2306
- abortSignal == null || abortSignal.addEventListener == null || abortSignal.addEventListener("abort", dispose);
2325
+ const dispose = () => this.dispose();
2326
+ if (abortSignal != null && abortSignal.addEventListener && !this.isDisposed) {
2327
+ abortSignal.addEventListener("abort", dispose);
2328
+ this.removeAbortListener_ = () => abortSignal.removeEventListener == null ? void 0 : abortSignal.removeEventListener("abort", dispose);
2329
+ }
2307
2330
  dispose[$mobx] = this;
2308
2331
  if ("dispose" in Symbol && typeof Symbol.dispose === "symbol") {
2309
2332
  dispose[Symbol.dispose] = dispose;
@@ -3314,8 +3337,13 @@ function hasInterceptors(interceptable) {
3314
3337
  return interceptable.interceptors_ !== undefined && interceptable.interceptors_.length > 0;
3315
3338
  }
3316
3339
  function registerInterceptor(interceptable, handler) {
3317
- const interceptors = interceptable.interceptors_ || (interceptable.interceptors_ = []);
3318
- interceptors.push(handler);
3340
+ let interceptors = interceptable.interceptors_;
3341
+ if (interceptors) {
3342
+ interceptors.push(handler);
3343
+ } else {
3344
+ // Allocate at the exact size: pushing onto an empty array over-allocates its backing store
3345
+ interceptors = interceptable.interceptors_ = [handler];
3346
+ }
3319
3347
  return once(() => {
3320
3348
  const idx = interceptors.indexOf(handler);
3321
3349
  if (idx !== -1) {
@@ -3347,8 +3375,13 @@ function hasListeners(listenable) {
3347
3375
  return listenable.changeListeners_ !== undefined && listenable.changeListeners_.length > 0;
3348
3376
  }
3349
3377
  function registerListener(listenable, handler) {
3350
- const listeners = listenable.changeListeners_ || (listenable.changeListeners_ = []);
3351
- listeners.push(handler);
3378
+ let listeners = listenable.changeListeners_;
3379
+ if (listeners) {
3380
+ listeners.push(handler);
3381
+ } else {
3382
+ // Allocate at the exact size: pushing onto an empty array over-allocates its backing store
3383
+ listeners = listenable.changeListeners_ = [handler];
3384
+ }
3352
3385
  return once(() => {
3353
3386
  const idx = listeners.indexOf(handler);
3354
3387
  if (idx !== -1) {
@@ -3462,8 +3495,7 @@ const arrayTraps = {
3462
3495
  const adm = target[$mobx];
3463
3496
  if (name === "length") {
3464
3497
  adm.setArrayLength_(value);
3465
- }
3466
- if (typeof name === "symbol" || isNaN(name)) {
3498
+ } else if (typeof name === "symbol" || isNaN(name)) {
3467
3499
  target[name] = value;
3468
3500
  } else {
3469
3501
  // numeric string
@@ -3508,7 +3540,7 @@ class ObservableArrayAdministration {
3508
3540
  return this.values_.length;
3509
3541
  }
3510
3542
  setArrayLength_(newLength) {
3511
- if (typeof newLength !== "number" || isNaN(newLength) || newLength < 0) {
3543
+ if (!Number.isInteger(newLength) || newLength < 0) {
3512
3544
  die(40, newLength);
3513
3545
  }
3514
3546
  let currentLength = this.values_.length;
@@ -4290,7 +4322,8 @@ class ObservableSet {
4290
4322
  }
4291
4323
  if (!this.has(value)) {
4292
4324
  transaction(() => {
4293
- this.data_.add(this.enhancer_(value, undefined));
4325
+ value = this.enhancer_(value, undefined); // report the stored value, like map and array
4326
+ this.data_.add(value);
4294
4327
  this.atom_.reportChanged();
4295
4328
  });
4296
4329
  const notifySpy = __MOBX_DEV__ && isSpyEnabled();