Ways to capture and analyze JavaScript error

Source: Internet
Author: User
Tags anonymous exception handling regular expression stack trace

  This article mainly describes how to capture and analyze JavaScript Error, interested friends can refer to the following

How to capture and analyze JavaScript error    Front-End engineers know that JavaScript has basic exception handling capabilities. We can throw the new error () and the browser throws an exception when we invoke the API error. But it is estimated that most front-end engineers have not considered collecting these exception information. Anyway, as long as the JavaScript error after the refresh is no longer, the user can solve the problem by refreshing, the browser will not crash, when it did not happen well. This assumption was established before the single Page App was popular. Now the single Page APP runs for a period of time after a very complex state, the user may have a number of input operations to come here, said refresh on the refresh Ah? Do you want to redo the previous operation? So we still need to capture and analyze these exception information, and then we can modify the code to avoid impacting the user experience.   How to catch the exception     Our own Write throw new Error () want to capture, of course, because we know exactly where throw is written. However, the exception that occurs when invoking the browser API is not necessarily so easily captured, and some APIs are written in the standard to throw exceptions, and some APIs only individual browsers throw exceptions because of differences or flaws. For the former we can also capture through Try-catch, for which we must listen for global exceptions and then capture them.     try-catch    If some browser APIs are known to throw exceptions, then we need to put the call into the Try-catch to avoid an error causing the entire program to enter an illegal state. For example, Window.localstorage is an API that throws an exception when the write data exceeds the capacity limit, as is the case in Safari's privacy browsing mode.     Code as follows: Try {  localstorage.setitem (' Date ', Date.now ()); } catch (Error) {  ReportError (Error ; }    Another common Try-catch scenario is the callback. Because the code for the callback function is not controllable, the quality of the code will not invoke any other API that throws an exception, we don't know. In order not to cause other code that calls the callback to fail because of a callback error, the call is returned to the TRY-CAtch inside is necessary.     Code as follows: Listeners.foreach (function (listener) {  try {  Listener (); } catch (Error) {  Orterror (Error); } });    window.onerror    for Try-catch is not covered, if there is an exception can only pass Window.onerror to capture it.   Code as follows: Window.onerror =  function (errormessage, Scripturi, linenumber) {  ReportError ({  message: errormessage,  script:scripturi,  line:linenumber }); }    Be careful not to use smart tricks Window.addeventlistener or window.attachevent in the form of listening to Window.onerror. Many browsers only implement Window.onerror, or only WINDOW.ONERROR implementations are standard. Taking into account the definition of the draft standard is also Window.onerror, we use window.onerror just fine.   Property Loss     Suppose we have a reporterror function to collect the caught exception and then bulk send it to the server-side store for query analysis, so what information do we want to collect? Useful information is the type of error (name), error message, script file address (scripts), line numbers (lines), column numbers (columns), stack traces (stack). If an exception is captured through Try-catch, the information is on the Error object (supported by mainstream browsers), so ReportError can collect the information as well. But if captured through Window.onerror, we all know that this event function has only 3 parameters, so the information outside these 3 parameters is lost.   Serialization Message     If the Error object is created by ourselves, then the error.message is controlled by us. Basically what we put into the error.message, the Window.onerror's first argument (message) is what. (browsers can actually make minor changes, such as adding ' uncaught Error: ' prefix.) So we can serialize the attributes we're focusing on (for example, JSON). stringify) is then deposited into the error.message and then deserialized on Window.onerror read. Of course, this is limited to the Error object we created ourselves.   Fifth parameter     Browser vendors also know the limitations of using window.onerror, so start adding new parameters to Window.onerror. In view of the fact that only line numbers do not appear to be symmetrical, IE first add the column number and place the fourth parameter. However, we are more concerned about the ability to get the full stack, so Firefox said to put the stack on the fifth parameter bar. But Chrome said it would be better to put the entire Error object on the fifth argument, and what attributes you want to read, including custom attributes. As a result of the faster chrome action, the new Window.onerror signature was implemented in Chrome 30, which led to the standard drafts being written accordingly.     Code as follows: Window.onerror = function (  errormessage,  scripturi,  linenumber,  columnnumber,  error ) {  if (error) {  ReportError (Error); } else {  ReportError ({  message:errormessage,  script:scripturi,  line:linenumber,  column:columnnumber }); }& nbsp }    Attribute Normalization     The Error object properties we discussed earlier, whose names are based on the Chrome naming method, howeverThe Error object properties are named differently by different browsers, such as script file addresses that are called scripts in Chrome but are called filename in Firefox. Therefore, we also need a special function to normalize the Error object, that is, to map different attribute names to the uniform attribute names. The specific procedure can refer to this article. Although the browser implementation is updated, it is not too difficult for a human to maintain such a mapping.     is similar to the format of the stack trace (stack). This property preserves the stack information of an exception when it occurs in plain text, because the text format used by each browser is different, so it also requires manual maintenance of a regular expression used to extract each frame's function name (identifier), file (script) from plain text, Line number and column number (column).   Security Restrictions     If you've also encountered the message ' script error. ', you'll understand what I'm talking about. This is actually a browser's restriction on different source (origin) script files. The reason for this security restriction is this: Suppose a network of silver in the user login after the return of HTML and anonymous users see the HTML is not the same, a Third-party Web site will be able to put the net silver URI into the script.src attribute. HTML of course can not be used as JS parsing, so the browser will throw an exception, and this Third-party Web site will be able to resolve the abnormal location to determine whether the user has logged in. This browser for different source script files thrown by the exception to filter, filtering only the "script error." Such a unchanged message, all the other attributes disappear.     for a certain size of the site, the script file on the CDN, not homologous is very normal. Now, as a small web site, common frameworks such as jQuery and backbone can directly reference the version on the public CDN to speed up user downloads. So this security constraint does cause some trouble, and the exception information we collect from Chrome and Firefox is useless ' Script error. '   cors    wants to circumvent this limitation by ensuring that the script file and the page itself are homologous. But is the script file on the server without CDN acceleration, does not reduce the user download speed? One solution is that the script files continue to be on the CDN, using XMLHttpRequest to download the content via CORS, and then create <script> tag into the pageOf The code embedded in the page is of course homologous.     This is simple to say, but there are a lot of details to realize. In a simple example,:    code is as follows: <script src= "Http://cdn.com/step1.js" ></script>  <script>   (function Step2 () {}) ();  </script>  <script src= "Http://cdn.com/step3.js" ></script >    We all know that this step1, Step2, Step3, if there is a dependency, you must strictly follow this order, or you may be wrong. Browsers can request step1 and step3 files in parallel, but the order of execution is guaranteed. If we get the contents of Step1 and step3 through xmlhttprequest ourselves, we need to ensure that the order is correct. In addition, don't forget to Step2, step1 in the form of non-blocking download Step2 can be executed, so we must also artificially intervene step2 let it wait for Step1 to complete and then execute.     If we already have a complete set of tools to generate <script> tags on different pages on the site, we need to adjust the tool to make changes to <script> tags:  the   code as follows: <script>  scheduleremotescript (' http://cdn.com/step1.js ');  </script>  <script>   Scheduleinlinescript (function code () {  (function Step2 () {}) (); });  </script>  < script>  scheduleremotescript (' http://cdn.com/step3.js ');  </script>    We need to implement Scheduleremotescript and Scheduleinlinescript These two functions, and make sure they are defined before the first <script> tag that references the external script file, and then the remaining <script> The label will be rewritten as the above form. Note that the STEP2 function, which was originally executed immediately, was placed inside a larger code function. The code function is not executed, it is just a container, so that the original step2 can be preserved without escaping, but will not be executed immediately.     Next we also need to implement a complete set of mechanisms to ensure that the contents of these files are downloaded by scheduleremotescript from the address and by the Scheduleinlinescript The code that is obtained directly can be executed one after the other in the correct order. Detailed code I am not here to give, we are interested to be able to achieve their own.   Line number counter-check     get content through CORS and then inject code into the page can break through security restrictions, but introduce a new problem, that is line number conflict. It was possible to navigate to a unique script file via Error.script and then navigate to a unique line number via Error.line. Now because the page is embedded code, a number of <script> tags can not be differentiated by error.script, however, each <script> tag inside the line number is from 1, The result is that we can't use the exception information to locate the source code where the error resides.     In order to avoid line number conflicts, we can waste some line numbers, so that each <script> label has the actual code used by the line number interval does not overlap. For example, assuming that the actual code in each <script> tag is no more than 1000 lines, I can have the code in the first <script> tag occupy the 1–1000 line so that the code in the second <script> tag occupies the 1001–2000 Line (insert 1000 blank lines before), the third <script> label code occupies the first 2001–3000 line (insert 2000 blank lines before), and so on. We then use the data-* attribute to record this information for easy retrieval.     Code as follows: <script  data-src= "http://cdn.com/step1.js "  data-line-start=" 1 "  > //code for step 1  </script>  < Script data-line-start= "1001" > //' n ' * 1000 //code for step 2  </script>  <script&nbsp ; Data-src= "Http://cdn.com/step3.js"   data-line-start= "2001"   > //' n ' * 2000 /code for step 3&N Bsp </script>    After such treatment, if a wrong error.line is 3005, it means that the actual error.script should be ' http://cdn.com/step3.js ', and the actual error.line should be 5. We can complete this line number in the previous mentioned ReportError function to check the work.     Of course, because we have no way to guarantee that each script file is only 1000 lines, it is possible that some script files are significantly less than 1000 lines, so there is no need to allocate 1000 lines of the interval to each <script> tag. We can allocate intervals based on the number of actual script lines, as long as the intervals used by each <script> label are guaranteed to overlap.   Crossorigin Properties     The security restrictions for different sources of content are of course not limited to <script> tags. Since XMLHttpRequest can break through this limitation through CORS, why is the resource referenced directly through the tag not available? Of course this is possible.     references to different source script files for <script> tags also work on <img> tags referencing different source picture files. If a <img> label is a different source, once used in the <canvas> drawing, the <canvas> will becomeWrite-only status, ensuring that Web sites cannot steal unauthorized different source image data through JavaScript. Later <img> tags solved the problem by introducing the Crossorigin attribute. If you use crossorigin= "anonymous", it is equivalent to an anonymous CORS, and if you use ' crossorigin= ' use-credentials, it is equivalent to a CORS with authentication.     Since <img> tags can do this, why <script> labels can't do that? The browser vendor then adds the same crossorigin attribute to the <script> tag to address the security restrictions mentioned above. Now the Chrome and Firefox support for this property is completely fine. Safari treats crossorigin= "anonymous" as crossorigin= "Use-credentials", and the result is that Safari will fail as a certificate if the server only supports anonymous CORS. Because the CDN server is designed to return only static content because of its performance, it is impossible to dynamically return the required HTTP Header,safari of the authentication CORS according to the request equivalent to not being able to use this feature to solve the above problem.   Summary     JAVASCRIPT exception handling looks very simple, it's no different from other languages, but it's not easy to actually capture the exception and then analyze the attributes. Now, although there are third-party services that provide a Google Analytics service to capture JavaScript exceptions, it is necessary to make sure that the details and principles are made in your own hands.    
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.