Skip to content

Commit

Permalink
Don't try/catch errors when globalstate.disableErrorBoundaries is on.
Browse files Browse the repository at this point in the history
  • Loading branch information
NaridaL committed Dec 4, 2017
1 parent 44eedf3 commit 80decea
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 27 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 3.5.0
* Added extras.disableErrorBoundaries()

# 3.4.0

* Improve Flow support support by exposing typings regularly. Flow will automatically include them now. In your `.flowconfig` will have to remove the import in the `[libs]` section (as it's done [here](https://github.com/mobxjs/mobx/pull/1254#issuecomment-348926416)). Fixes [#1232](https://github.com/mobxjs/mobx/issues/1232).
Expand Down
22 changes: 13 additions & 9 deletions src/core/computedvalue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,14 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
if (track) {
res = trackDerivedFunction(this, this.derivation, this.scope)
} else {
try {
if (globalState.disableErrorBoundaries) {
res = this.derivation.call(this.scope)
} catch (e) {
res = new CaughtException(e)
} else {
try {
res = this.derivation.call(this.scope)
} catch (e) {
res = new CaughtException(e)
}
}
}
globalState.computationDepth--
Expand Down Expand Up @@ -242,18 +246,18 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
`
WhyRun? computation '${this.name}':
* Running because: ${isTracking
? "[active] the value of this computation is needed by a reaction"
: this.isComputing
? "[get] The value of this computed was requested outside a reaction"
: "[idle] not running at the moment"}
? "[active] the value of this computation is needed by a reaction"
: this.isComputing
? "[get] The value of this computed was requested outside a reaction"
: "[idle] not running at the moment"}
` +
(this.dependenciesState === IDerivationState.NOT_TRACKING
? getMessage("m032")
: ` * This computation will re-run if any of the following observables changes:
${joinStrings(observing)}
${this.isComputing && isTracking
? " (... or any observable accessed during the remainder of the current run)"
: ""}
? " (... or any observable accessed during the remainder of the current run)"
: ""}
${getMessage("m038")}
* If the outcome of this computation changes, the following observers will be re-run:
Expand Down
36 changes: 22 additions & 14 deletions src/core/derivation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,16 @@ export function shouldCompute(derivation: IDerivation): boolean {
for (let i = 0; i < l; i++) {
const obj = obs[i]
if (isComputedValue(obj)) {
try {
if (globalState.disableErrorBoundaries) {
obj.get()
} catch (e) {
// we are not interested in the value *or* exception at this moment, but if there is one, notify all
untrackedEnd(prevUntracked)
return true
} else {
try {
obj.get()
} catch (e) {
// we are not interested in the value *or* exception at this moment, but if there is one, notify all
untrackedEnd(prevUntracked)
return true
}
}
// if ComputedValue `obj` actually changed it will be computed and propagated to its observers.
// and `derivation` is an observer of `obj`
Expand Down Expand Up @@ -131,10 +135,14 @@ export function trackDerivedFunction<T>(derivation: IDerivation, f: () => T, con
const prevTracking = globalState.trackingDerivation
globalState.trackingDerivation = derivation
let result
try {
if (globalState.disableErrorBoundaries) {
result = f.call(context)
} catch (e) {
result = new CaughtException(e)
} else {
try {
result = f.call(context)
} catch (e) {
result = new CaughtException(e)
}
}
globalState.trackingDerivation = prevTracking
bindDependencies(derivation)
Expand All @@ -158,24 +166,24 @@ function bindDependencies(derivation: IDerivation) {
// 0: first occurrence, change to 1 and keep it
// 1: extra occurrence, drop it
let i0 = 0,
l = derivation.unboundDepsCount
l = derivation.unboundDepsCount
for (let i = 0; i < l; i++) {
const dep = observing[i]
const dep = observing[i]
if (dep.diffValue === 0) {
dep.diffValue = 1
dep.diffValue = 1
if (i0 !== i) observing[i0] = dep
i0++
i0++
}

// Upcast is 'safe' here, because if dep is IObservable, `dependenciesState` will be undefined,
// not hitting the condition
if (((dep as any) as IDerivation).dependenciesState > lowestNewObservingDerivationState) {
lowestNewObservingDerivationState = ((dep as any) as IDerivation).dependenciesState
lowestNewObservingDerivationState = ((dep as any) as IDerivation).dependenciesState
}
}
observing.length = i0

derivation.newObserving = null // newObserving shouldn't be needed outside tracking (statement moved down to work around FF bug, see #614)
derivation.newObserving = null // newObserving shouldn't be needed outside tracking (statement moved down to work around FF bug, see #614)

// Go through all old observables and check diffValue: (it is unique after last bindDependencies)
// 0: it's not in new observables, unobserve it
Expand Down
22 changes: 22 additions & 0 deletions src/core/globalstate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ export class MobXGlobals {
* Globally attached error handlers that react specifically to errors in reactions
*/
globalReactionErrorHandlers: ((error: any, derivation: IDerivation) => void)[] = []

/**
* Don't catch and rethrow exceptions. This is useful for inspecting the state of
* the stack when an exception occurs while debugging.
*/
disableErrorBoundaries = false
}

export let globalState: MobXGlobals = new MobXGlobals()
Expand Down Expand Up @@ -153,3 +159,19 @@ export function resetGlobalState() {
if (persistentKeys.indexOf(key) === -1) globalState[key] = defaultGlobals[key]
globalState.allowStateChanges = !globalState.strictMode
}

/**
* Don't catch and rethrow exceptions. This is useful for inspecting the state of
* the stack when an exception occurs while debugging.
*/
export function disableErrorBoundaries() {
console.warn("WARNING: Debug feature only. MobX will NOT recover from errors if this is on.")
globalState.disableErrorBoundaries = true
}

/**
* Opposite of disableErrorBoundaries
*/
export function enableErrorBoundaries() {
globalState.disableErrorBoundaries = false
}
12 changes: 8 additions & 4 deletions src/mobx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ import {
resetGlobalState,
shareGlobalState,
getGlobalState,
isolateGlobalState
isolateGlobalState,
disableErrorBoundaries,
enableErrorBoundaries
} from "./core/globalstate"
import { IDerivation } from "./core/derivation"
import { IDepTreeNode } from "./core/observable"
Expand Down Expand Up @@ -139,7 +141,9 @@ export const extras = {
spyReport,
spyReportEnd,
spyReportStart,
setReactionScheduler
setReactionScheduler,
disableErrorBoundaries,
enableErrorBoundaries,
}

// Deprecated default export (will be removed in 4.0)
Expand Down Expand Up @@ -260,8 +264,8 @@ for (let p in everything) {
warnedAboutDefaultExport = true
console.warn(
"Using default export (`import mobx from 'mobx'`) is deprecated " +
"and won’t work in [email protected]\n" +
"Use `import * as mobx from 'mobx'` instead"
"and won’t work in [email protected]\n" +
"Use `import * as mobx from 'mobx'` instead"
)
}
return val
Expand Down

0 comments on commit 80decea

Please sign in to comment.