The Request Fails
The first level of failure is the request for the JS file. Sometimes there’s a problem on the network and a request fails. Sometimes there’s a problem on the server (perhaps your CDN), and the request fails. Sometimes the user is behind a corporate firewall and a particularly eager sysadmin has blocked access to JS files.
This is made worse if your file is particularly large (easy if it’s not been minified), or if you have multiple JS files.
As Jake Archibald says “all your users are non-JS while they’re downloading your JS.” The network can be slow: your users might be on a crappy mobile connection or a throttled ADSL connection.
Couple that with the fact that JS parse times can be slow for large files, especially on mobile devices, and some users will be waiting a while before they have all your JS.
If your users have any browser extensions installed (such as AdBlock), they may inadvertently interfere with the execution of your JS. If your page has any 3rd party JS, such as ads or tracking, they can also interfere with your code.
As much as we might hate to admit it, errors creep into everyone’s code sometimes. Yes, even yours (and definitely mine!). It’s probably more likely that your user will be served broken JS than not served your JS at all. JS is brittle and fault intolerant: one mistake and your code goes boom.
Testing for feature support (for example, by cutting the mustard) lets you serve a browser only the code that it will understand. Conditionally loading your JS file based on passing that test (for example, using Filament Group’s loadJS) means that you won’t waste your users’ data by sending them code their browser can’t use.