From d6af3605ca4af142f92fcf12545f709ebdcdb6d1 Mon Sep 17 00:00:00 2001 From: Slava Kim Date: Thu, 26 Feb 2015 01:14:27 -0800 Subject: [PATCH] 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. --- packages/tracker/tracker.js | 64 ++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/packages/tracker/tracker.js b/packages/tracker/tracker.js index 1460e1f062..ee71832b16 100644 --- a/packages/tracker/tracker.js +++ b/packages/tracker/tracker.js @@ -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 () {