2

I am using Firefox 32 and Chrome 37 with Mithril.js and have now been repeatedly tripped up by typos in variable names just silently causing the JS to stop executing at the point of the reference. It's particularly frustrating for me coming from C and Java since I am used to the compiler catching such trivial mistakes before I even attempt to run the code.

I have narrowed down the problem to be occurring only in functions running as part of the AJAX promise chain, like this:

function getListData(ctl) {
    ctl.data([]);
    ctl.loading(true);
    return m.request({ method: "GET", url: apiBase, background: true }).then(done,fail);

    function done(rspdta) {
        xctl.loading(false);
        ctl.data(rspdta.Customer);
        m.redraw();
        };

    function fail(rspdta) {
        ctl.loading(false);
        ajaxError(ctl);
        m.redraw();
        throw rspdta;                                                                               // continue error condition
        };
    }

Notice the deliberate xctl.loading(false) in the done function -- the script just appears to stop there, but a ReferenceError is thrown. However, nothing is logged.

I am working on how to prove have proved that it's being caught and ignored by Mithril.js now, in this code:

function thennable (ref, cb, ec, cn) {
    if ((typeof val == 'object' || typeof val == 'function') && typeof ref == 'function') {
        try {

            // cnt protects against abuse calls from spec checker
            var cnt = 0
            ref.call(val, function (v) {
                if (cnt++) return
                val = v
                cb()
            }, function (v) {
                if (cnt++) return
                val = v
                ec()
            })
        } catch (e) {
            /**/console.log("[**] Caught in thennable: %o",e);
            val = e
            ec()
        }
    } else {
        cn()
    }
};

Hopefully someone from that community will be able to say whether I've done something wrong, am misusing the promise chain (??) or if it's a bug in Mithril.js 0.1.21.

Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
  • Can you point out the typo in your code above? I can't notice anything with such short/confusing names – Ian Sep 24 '14 at 02:22
  • @Ian: The code above is correct, sorry if that was misleading -- I was showing the code structure with the `"use strict"` whereby I expect it to give an error for undeclared `var`s. Simply changing any `rspdta` to, say, `rpsdta` is enough for the script to simply halt executing at that point. It's almost as if an exception is thrown, caught by the event loop, but not reported. – Lawrence Dol Sep 24 '14 at 03:03
  • Well then I'm confused about your problem. Unless I'm remembering wrong, there's nothing bad about **accessing** "undefined" variables (since they could be global). **Setting** undefined variables isn't allowed in strict mode. Is that what you're thinking of? – Ian Sep 24 '14 at 06:04
  • @Ian: In strict mode, I thought accessing an undefined global is an error. But if it's not, why does it halt the script? It's not ***reporting*** anything, so things just stop with no clue as to why. – Lawrence Dol Sep 24 '14 at 16:06
  • I've never heard/seen that before. From the MDN, the only reference I see is "First, strict mode makes it impossible to accidentally create global variables". I never see it mention changes to **accessing** undefined global variables, because that wouldn't make sense anyways. Accessing variables with `undefined` value is different than not being defined. You're definitely right that **if** something was being halted but not reporting, it would be a problem. But I can't reproduce that - can you provide a simpler jsFiddle or something? – Ian Sep 24 '14 at 16:14
  • 1
    @Ian: Good idea -- I'll try to do that. I have proven beyond any doubt that it does just silently halt - all I have to do is change any variable name in any code; but I can't prove yet that it's not because something, say `Mithril.js`, is not swallowing an exception. (Also, you are quite correct about strict mode; I was misrembering that, perhaps just frazzled from hours of try to figure out why my code was just stopping. :-) ) – Lawrence Dol Sep 24 '14 at 16:18
  • Sounds good. For example, it reports fine here: http://jsfiddle.net/hfudcu4L/ . But note that my use of the `creation.ajaxError` may not be consumed like your actual code is, and therefore may not function the same. And trust me, I mix up/forget things about strict mode often too – Ian Sep 24 '14 at 16:20
  • As there are no answers yet, I am rewriting this question to reflect how I have narrowed it down. – Lawrence Dol Sep 24 '14 at 18:32

2 Answers2

2

Long story short, it's a problem in the Promises/A+ spec (basically it doesn't differentiate between checked and unchecked errors). For Mithril 0.1.21 (and for that matter, for native ES6 Promises), the workaround to catch the error is to do what Zolmeister said.

.then(buggyCallback) //this throws the ReferenceException
.then(null, function(e) {console.error(e)})

Alternatively, Mithril 0.1.19 (the last version before the Promiz PR merge) throws to console by default.

Mithril 0.1.22 will ship with a promise exception monitor that will allow you to configure how to early-catch promise exceptions (and will default to throwing to the console for programmer errors). You can find this version in the development repo.

LeoHorie
  • 1,320
  • 11
  • 11
  • Do I understand that to mean that errors like ReferenceError will console log by default in the next version? With the stack trace? If so, that's perfect. – Lawrence Dol Sep 24 '14 at 21:21
  • Is 0.1.22 stable enough to use in production? – Lawrence Dol Sep 24 '14 at 21:23
  • After digesting the response on [to my issue on github](https://github.com/lhorie/mithril.js/issues/279), I believe what's missing from Mithril is some kind of `finally` mechanism. But I agree with Raynos on that thread that you can't technically know that the exception was not handled until the promise is GC'd because some asyn code may attach a handler at any point. At the same time, in any context silently absorbed and unhandled exceptions is awful. That said, it still seems like errors from coding blunders should always be logged when they are detected. – Lawrence Dol Sep 24 '14 at 23:25
  • 1
    I'm probably going to release 0.1.22 this week. Just finishing up some documentation on components – LeoHorie Sep 25 '14 at 02:30
1

Errors thrown inside an onFulfilled handler result in a rejected promise. Spec: http://promisesaplus.com/#point-42

Here is the solution:

abc.then(thrower, fail1).then(null, fail2)

It will be caught by fail2

Zolmeister
  • 204
  • 3
  • 5
  • I would agree for a general deliberately thrown exception from user/library code, but for a JavaScript engine *Error*, I think that they should be handled and rethrown. As a test in Mithrils 4 `catch` clauses I added a catch and rethrow for `Error` and the end result was an console error with the line of *my* code where the typo was. Don't you think that would be more correct? – Lawrence Dol Sep 24 '14 at 21:08
  • This solution seems to say I have to anticipate the possibility that I might cause a JS error (ReferenceError, RangeError, etc) and ***everywhere*** I have to add another handler to, what?, rethrow the error? – Lawrence Dol Sep 24 '14 at 21:10