Tweaks to error reporting in Tracker.

- Allow passing an onError callback to Tracker.autorun.
- Workaround the issue described in #3655 by logging parts of error message
  separately.
This commit is contained in:
Slava Kim
2015-02-26 01:14:27 -08:00
parent 9a29988016
commit d6af3605ca

View File

@@ -38,35 +38,30 @@ var setCurrentComputation = function (c) {
Tracker.active = !! c;
};
var _debugFunc = function () {
// We want this code to work without Meteor, and also without
// "console" (which is technically non-standard and may be missing
// on some browser we come across, like it was on IE 7).
//
// Lazy evaluation because `Meteor` does not exist right away.(??)
return (typeof Meteor !== "undefined" ? Meteor._debug :
((typeof console !== "undefined") && console.log ?
function () { console.log.apply(console, arguments); } :
function () {}));
};
var _throwOrLog = function (from, e) {
if (throwFirstError) {
throw e;
} else {
var messageAndStack;
if (e.stack && e.message) {
var printArgs = ["Exception from Tracker " + from + " function:"];
if (e.stack && e.message && e.name) {
var idx = e.stack.indexOf(e.message);
if (idx >= 0 && idx <= 10) // allow for "Error: " (at least 7)
messageAndStack = e.stack; // message is part of e.stack, as in Chrome
else
messageAndStack = e.message +
(e.stack.charAt(0) === '\n' ? '' : '\n') + e.stack; // e.g. Safari
} else {
messageAndStack = e.stack || e.message;
if (idx < 0 || idx > e.name.length + 2) { // check for "Error: "
// message is not part of the stack
var message = e.name + ": " + e.message;
printArgs.push(message);
}
}
printArgs.push(e.stack);
if (typeof console !== "undefined") {
for (var i = 0; i < printArgs.length; i++) {
if (console.error) {
console.error(printArgs[i]);
} else if (console.log) {
console.log(printArgs[i]);
}
}
}
_debugFunc()("Exception from Tracker " + from + " function:",
messageAndStack);
}
};
@@ -136,7 +131,7 @@ var constructingComputation = false;
* computation.
* @instancename computation
*/
Tracker.Computation = function (f, parent) {
Tracker.Computation = function (f, parent, onError) {
if (! constructingComputation)
throw new Error(
"Tracker.Computation constructor is private; use Tracker.autorun");
@@ -185,6 +180,7 @@ Tracker.Computation = function (f, parent) {
// to constrain the order that computations are processed
self._parent = parent;
self._func = f;
self._onError = onError;
self._recomputing = false;
// Register the computation within the global Tracker.
@@ -297,7 +293,11 @@ Tracker.Computation.prototype._recompute = function () {
try {
self._compute();
} catch (e) {
_throwOrLog("recompute", e);
if (self._onError) {
self._onError(e);
} else {
_throwOrLog("recompute", e);
}
}
}
} finally {
@@ -492,17 +492,23 @@ Tracker._runFlush = function (options) {
* @param {Tracker.Computation}
*/
/**
* @summary Run a function now and rerun it later whenever its dependencies change. Returns a Computation object that can be used to stop or observe the rerunning.
* @summary Run a function now and rerun it later whenever its dependencies
* change. Returns a Computation object that can be used to stop or observe the
* rerunning.
* @locus Client
* @param {Tracker.ComputationFunction} runFunc The function to run. It receives one argument: the Computation object that will be returned.
* @param {Tracker.ComputationFunction} runFunc The function to run. It receives
* one argument: the Computation object that will be returned.
* @param {Function} [onError] Optional. The function to run when an error
* happens in the Computation. The only argument it recieves is the Error
* thrown. Defaults to the error being logged to the console.
* @returns {Tracker.Computation}
*/
Tracker.autorun = function (f) {
Tracker.autorun = function (f, onError) {
if (typeof f !== 'function')
throw new Error('Tracker.autorun requires a function argument');
constructingComputation = true;
var c = new Tracker.Computation(f, Tracker.currentComputation);
var c = new Tracker.Computation(f, Tracker.currentComputation, onError);
if (Tracker.active)
Tracker.onInvalidate(function () {