Giter VIP home page Giter VIP logo

Comments (9)

JAAulde avatar JAAulde commented on July 27, 2024

How consistent is the exception object from browser to browser for run time messages? In Firefox you get file, line, stack, etc. If there is enough info between the browsers you could log as much as possible to help us find line, etc. I also thought about a config option that lets us ask the whole stack to quit on error.

from labjs.

getify avatar getify commented on July 27, 2024

I don't think the exception object is that consistent between browsers. I'm not positive, but I don't think it has line numbers and filenames exposed in most of the browsers. For instance, in V8, I know it tracks those values, so that the browser's error console can display them if an exception is left uncaught. But I don't think it exposes all of that data to the JS error object. Perhaps I'm wrong, not 100% positive.

But whatever properties are on the object, of course they could be serialized and displayed in the console.error() message. It might just be that in some browsers you don't get as helpful of information as in others.

from labjs.

getify avatar getify commented on July 27, 2024

there's going to be something like this feature in 2.0. Still not entirely decided on how it will look, but probably will be console.log()'ing that will be turned on only if you put $LAB into DEBUG mode.

from labjs.

getify avatar getify commented on July 27, 2024

there's now a DEBUG mode in LABjs 2.0a

from labjs.

frosas avatar frosas commented on July 27, 2024

Does it mean we have to run LABjs in debug mode in production if we don't want errors to be swallowed?

What about simply throwing the error outside of the chain? E.g. with a setTimeout(function() { throw error }, 0). It would pretty much mimic the behavior when using <script> (i.e. an "uncaught error" is thrown, having the option to use window.onerror to track it). Check this for a comparison: <script> vs LABjs.

from labjs.

getify avatar getify commented on July 27, 2024

You should not have errors as a matter of practice in production. If you have errors, you should have a way to find and FIX them, not a way to find and IGNORE them. That's the philosophy applied here. That's why LABjs comes with this optional debug build. Moreover, as explained in the thread above, LABjs' assumption is that by default, developers don't want errors leaking out into the consoles in production.

So, if you experience issues, either in dev or production, with your loading, swap in the debug LABjs, enable debug mode, and find them. And FIX them. Then swap back to non-debug production LABjs and go home and enjoy your weekend. :)

Moreover, there's a simple fix to this problem which doesn't involve changing your LABjs file nor enabling a mode. It's putting your own try..catch error handling (or other robust feature testing!) around any code which, you know, might actually error if something's missing. I would suggest avoiding writing code which can error, and being more robust yourself. But to whatever extent that's not possible, it then becomes your responsibility to do the extra work to use LABjs' debug build to find and fix such errors.

Example: Don't just use $ assuming it's there, and let an error happen. Test if it's there first:

if (typeof $ !== "undefined") {
   $("..")...
}
else {
   logErrorToServer("Oops, jquery is missing.");
   ShowPoliteErrorMessageToUser();
}

Note: I don't recommend running with the debug build of LABjs in production, even with the debug mode turned off. But, it's not much bigger, nor appreciably slower (same try..catchs in place regardless), so it might be your chosen option to always run with the debug build of LABjs in production, and then all you have to do to "see" the errors is turn debug mode on (no file switching necessary).

from labjs.

getify avatar getify commented on July 27, 2024

Also, I would remind you, you should avoid having very much code in .wait(..) callbacks. If it's more than a few lines here or there, you should consider moving that code into its own file, where the "error handling" (aka suppression) that LABjs does won't hurt you. Then you'll only have a few .wait(..) lines to worry about with errors and debug modes and builds and such. Your team and your future self will thank you for reducing the surface error of such issues. :)

from labjs.

frosas avatar frosas commented on July 27, 2024

Sorry if I'm not nicer in the following lines, it's late and I'm tired so I'll try go straight to the point(s).

You should not have errors as a matter of practice in production. If you have errors, you should have a way to find and FIX them, not a way to find and IGNORE them. That's the philosophy applied here. That's why LABjs comes with this optional debug build. Moreover, as explained in the thread above, LABjs' assumption is that by default, developers don't want errors leaking out into the consoles in production.

I must have expressed very bad if you understood I'm trying to hide any error, cause my goal it's exactly the opposite.

I'm not going to argue whether hiding errors is what you want to do by default (but probably you're already guessing I think this is just a bad programming practice). But please, tell me, how I'm supposed to know whether I'm having errors in production if queueWait() is hiding them? As said before, am I supposed to run LABjs in debug mode in production the whole time in order to achieve this?

Moreover, there's a simple fix to this problem which doesn't involve changing your LABjs file nor enabling a mode. It's putting your own try..catch error handling (or other robust feature testing!) around any code which, you know, might actually error if something's missing. I would suggest avoiding writing code which can error, and being more robust yourself. But to whatever extent that's not possible, it then becomes your responsibility to do the extra work to use LABjs' debug build to find and fix such errors.

Thanks for recommending me to don't write faulty code, it's something I already try to do, but not even with all the tests in the world one can avoid sh*t happening in unpredictable ways with any of the millions of users we currently have.

Regarding to your suggestion of using try/catch, currently I'm working in monkey patching LABjs in the following way:

(function() {
  var originalQueueWait = $LAB.queueWait;
  $LAB.queueWait = function(callback) {
    return originalQueueWait.call($LAB, function() {
      try {
        callback();
      } catch (error) {
        setTimeout(function() { throw error; }, 0);
      }
    });
  };
})();

Example: Don't just use $ assuming it's there, and let an error happen. Test if it's there first:

I really hope I'll never have to write such a defensive code! Compare it to the following (considering LABjs whould be throwing the errors):

onerror = function(message, file, line, column, error) {
  logErrorToServer(error && error.message || error || message);
  ShowPoliteErrorMessageToUser();
};

I'm not saying this is the best approach for any given case but this would act as a good enough safety net for 99% of the cases.

I would remind you, you should avoid having very much code in .wait(..) callbacks. If it's more than a few lines here or there, you should consider moving that code into its own file, where the "error handling" (aka suppression) that LABjs does won't hurt you. Then you'll only have a few .wait(..) lines to worry about with errors and debug modes and builds and such.

Please, consider this example:

$LAB.script('main.js').wait(function() {
  someFunctionInMainJs();
});

Even in this minimalistic wait() callback thousands of instructions can be executed because of it, so I'm afraid I can't just "avoid having much code in it".

And now I see you're proposing to move my code to its own file a new question comes to my mind. Why such a different error handling between script() and wait()?

Hope I've been clearer this time!

from labjs.

getify avatar getify commented on July 27, 2024

First, I'd suggest reading this thread #57, specifically these two comments, for more back-story on my reasoning: comment 1 comment 2

if queueWait() is hiding them?

I am not "hiding them", I am preventing them from affecting the rest of the queueWait()s which might come later in the chain.

Since LABjs is driven by code, it has to be more sensitive to the fact that errors in user code could stop LABjs itself from doing the rest of its job.

By contrast, in native browser behavior, errors in one <script> element cannot stop other <script> elements from running (it just abandons execution of the first one and moves on).

If LABjs didn't catch the errors, any error thrown would cause the rest of the LABjs controlled parts of the chain to stop working. But, quite confusingly, the actual script load-and-run behavior (which the browser handles) would NOT be stopped, so some of the chain (script()s) would continue and some of the chain (wait()s) would not.

THAT kind of behavior would be far worse.

I'm attempting to keep LABjs working as much like the native browser behavior as possible, with the least amount of surprise of possible. I know you think the current "hiding errors" behavior is surprising, but the other choice would be much more surprising.

Let me illustrate. Let's take this series of markup:

<script src="script1.js"></script>
<script>
   doSomethingInScript1(); // let's say this throws an error!
</script>
<script src="script2.js"></script>
<script>
   doSomethingForScript3(); // no errors here!
</script>
<!-- requires `doSomethingForScript3()` to have completed successfully first! -->
<script src="script3.js"></script>

OK, so in normal browser behavior, script1.js loads and runs, then it tries to run the next inline <script> block, which throws an error. Then, script2.js runs, then the next inline <script> block runs (no errors), then script3.js runs.

But, hypothetically, what if the browser did this instead:

script1.js loads and runs, then the first inline <script> block runs, which throws an error. Next, script2.js still loads and runs fine, but then the next inline <script> block is never going to even be attempted, because of the previous error. Lastly, script3.js loads, and tries to run, but since doSomethingForScript3() never even tried to run, now tons of errors in script3.js are going to spam your error logs.

Think about that scenario for a moment. Is that scenario more or less surprising than the current native behavior (which you could describe as "run as much of this stuff as you can")?

I'd say unequivocally that the current behavior is much better than this second hypothetical scenario.

That hypothetical scenario is exactly what would happen if LABjs didn't catch-and-swallow errors inside of wait(). :(

Hopefully, that fully explains why we can't just let the errors be thrown.


Now, I bet the next thing you're wondering is, "can't you just catch any errors but dump them all to the error log?" Of course I can. That's what the debug build and debug mode is for!

Why didn't I just make the core do that? Because philosophically, I believe devs don't want, by default, to have errors that occur in production spamming the console logs of millions of users' browsers. By default, the production build of LABjs tries to be silent, while the debug build tries to be very chatty.

You have to specifically choose to do one of these things to opt into such verbose reporting:

  1. use the debug build and DEBUG mode of LABjs
  2. put your own try..catch around your inline wait(..) code that dumps errors yourself

Either way, you are specifically saying, "I want to see production errors". I would hope you only do that when troubleshooting a problem, and not all the time, but even if you do it all the time, then it's you that had to opt-in to that, rather than having to opt-out.

I call that "pit of success" rather than "pit of failure".


Lastly...

how I'm supposed to know whether I'm having errors in production

This is a very important dev-ops type of question, but it's vastly more complicated than anything LABjs even remotely tries to tackle.

You'll note that just dumping stuff into the console of your users isn't telling you if you're having problems in production. If the kinds of problems you're trying to find are anything like the kinds I've run into, they don't happen for everyone, only some. So, you can't just rely on seeing the messages in your console when you run the production app.

Odds are you're going to need to have a robust production monitoring solution in place. Perhaps something which sees if any JS errors happen and remotely logs those to your server logs.

If what happens by the error being swallowed is that some part of your app fails to get initialized, but the rest of it gets loaded, one thing that may occur is that other cascading errors will happen later when users click certain buttons (which your production monitoring would catch).

Another thing that could happen is that the error remains "silent". That is, most or all users don't even notice, or if they do, it's not a big enough deal that they care or complain.

If that is the kind of error you're worried about missing, because you don't even know it's happening, stop and ask yourself, "why am I so worried?" If an error occurs, but no one notices, and it doesn't cause any other breakage, what is the big deal, and more importantly, why would dumping that into an error console help identify it?

I think the more likely scenario is that you WILL hear about errors, through user complaints, or through your production monitoring solutions, or some other channel, and THEN you will know it's time to go (temporarily) flip on the debug mode of LABjs in production to start narrowing it down.

Bottom line: I doubt there really are that many "hidden silent errors" in production, when it comes down to real world scenarios playing out.

I'm sure I haven't convinced you, but hopefully this narrative helps explain more completely where my philosophy is coming from.

from labjs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.