Data is king. We collected and analyzed the top 10 most frequently occurring JavaScript errors. Rollbar collects all errors for each project and summarizes the number of times each error occurred. We do this by grouping errors based on “fingerprints” (an algorithm used by rollbar, see: https://rollbar.com/docs/grouping-algorithm/). Basically, if the second error is just a duplicate of the first error, we group both errors into the same group. This will give the user a good overview, rather than an overwhelming dump like what you see in the log file.
We focus on the bugs most likely to impact you and your users. To do this, we ranked the errors by studying project sets from various companies. If we only looked at the total number of times each error occurred, the errors produced by a high-volume project might overwhelm other errors, resulting in a data set of errors that would not be relevant to most readers.
Here are the top 10 JavaScript errors:
We have shortened each error description for easier reading. Next, let's dive into each error to determine what causes it and how to avoid creating it.
1. Uncaught TypeError: Cannot read property
If you are a JavaScript developer, you may have seen this error more times than you dare to admit ( LOL…). This error occurs in Chrome when you read a property of an undefined object or call its method. You can easily test (try it out) in the Chrome Developer Console.
There are many reasons why this happens, but a common one is improper initialization of state when rendering UI components.
Let’s look at an example of what happens in a real application: we choose React, but the same applies to Angular, Vue or any other framework.
class Quiz extends Component { componentWillMount() { axios.get('/thedata').then(res => { this.setState({items: res.data}); }); } render() { return ( <ul> {this.state.items.map(item => <li key={item.id}>{item.name}</li> )} </ul> ); } }
There are two important things to achieve here:
The component's state (e.g. this.state) starts from undefined.
When data is obtained asynchronously, whether it is obtained in the constructor componentWillMount or componentDidMount, the component will be rendered at least once before the data is loaded. When Quiz is first rendered, this.state. items is undefined. This in turn means that the ItemList defines items as undefined and an error appears in the console - "Uncaught TypeError: Cannot read property 'map' of undefined".
This is easily solved. The simplest way: initialize the state in the constructor with sensible default values.
class Quiz extends Component { // Added this: constructor(props) { super(props); // Assign state itself, and a default value for items this.state = { items: [] }; } componentWillMount() { axios.get('/thedata').then(res => { this.setState({items: res.data}); }); } render() { return ( <ul> {this.state.items.map(item => <li key={item.id}>{item.name}</li> )} </ul> ); } }
The specific code in your application may be different, but we hope we have given you enough clues to solve or avoid it in your application This problem arises in . If you haven't yet, keep reading as we'll cover more examples of related errors below.
2. TypeError: ‘undefined’ is not an object
This is an error that occurs when reading a property or calling a method on an undefined object in Safari. You can easily test this in the Safari Developer Console. This is essentially the same Chrome error mentioned in #1, but Safari uses a different error message.
3. TypeError: null is not an object
This is when reading properties or calling on an empty object in Safari An error occurred during the method. You can easily test this in the Safari Developer Console.
Interestingly, null and undefined are not the same in JavaScript, which is why we see two different error messages. undefined is usually a variable that has not been assigned, while null means the value is empty. To verify that they are not equal, try using the strict equality operator ===:
In a real world example, one scenario where this error can occur is : If you try to use the element in JavaScript before the element is loaded. Because the DOM API returns null for a blank object reference.
Any JS code that executes and processes DOM elements should be executed after the DOM element is created. JS code is interpreted from top to bottom as specified in HTML. So, if the DOM element is preceded by a tag, the JS code inside the script tag will be executed when the browser parses the HTML page. This error occurs if the DOM element has not been created before loading the script.
在这个例子中,我们可以通过添加一个事件监听器来解决这个问题,这个监听器会在页面准备好的时候通知我们。 一旦 addEventListener被触发,init() 方法就可以使用 DOM 元素。
<script> function init() { var myButton = document.getElementById("myButton"); var myTextfield = document.getElementById("myTextfield"); myButton.onclick = function() { var userName = myTextfield.value; } } document.addEventListener('readystatechange', function() { if (document.readyState === "complete") { init(); } }); </script> <form> <input type="text" id="myTextfield" placeholder="Type your name" /> <input type="button" id="myButton" value="Go" /> </form>
4. (unknown): Script error
当未捕获的 JavaScript 错误(通过window.onerror处理程序引发的错误,而不是捕获在try-catch中)被浏览器的跨域策略限制时,会产生这类的脚本错误。 例如,如果您将您的 JavaScript 代码托管在 CDN 上,则任何未被捕获的错误将被报告为“脚本错误” 而不是包含有用的堆栈信息。这是一种浏览器安全措施,旨在防止跨域传递数据,否则将不允许进行通信。
要获得真正的错误消息,请执行以下操作:
1. 发送 ‘Access-Control-Allow-Origin' 头部
将 Access-Control-Allow-Origin 标头设置为 * 表示可以从任何域正确访问资源。 如有必要,您可以将域替换为您的域:例如,Access-Control-Allow-Origin:www.example.com。 但是,处理多个域会变得棘手,如果你使用 CDN,可能由此产生更多的缓存问题会让你感觉到这种努力并不值得。 在这里看到更多。
这里有一些关于如何在各种环境中设置这个头文件的例子:
Apache
在 JavaScript 文件所在的文件夹中,使用以下内容创建一个 .htaccess 文件:
Header add Access-Control-Allow-Origin "*"
Nginx
将 add_header 指令添加到提供 JavaScript 文件的位置块中:
location ~ ^/assets/ { add_header Access-Control-Allow-Origin *; }
HAProxy
将以下内容添加到您为 JavaScript 文件提供资源服务的后端:
rspadd Access-Control-Allow-Origin:\ *
2. 在