Author: joeyguo

After the launch of the Web project, it opened the door and waited for users from all over the country with various network states to arrive. In the various network states, it is inevitable to encounter front-end resource loading failure when visiting the page, which may account for a small proportion. However, once encountered, the page style may be confused, or the white screen may not be opened, affecting the user experience, and even affecting the user’s work in emergency cases, which is a very serious problem.

This paper will focus on the front-end JS file from how to monitor the loading failure, how to optimize the loading failure, always load failure and how to deal with the problem one by one.

How do I monitor resource loading failures

Scheme 1: script onerror

We can add an onError attribute to the script tag, which will trigger an event callback if the load fails to catch the exception.

<script onerror="onError(this)"></script>
Copy the code

And, with the help of build tools such as webpack’s script-ext-html-webpack-plugin, it is easy to automate the injection of onError tags into all script tags without breaking a break.

new ScriptExtHtmlWebpackPlugin({
  custom: {
    test: /\.js$/,
    attribute: "onerror".value: "onError(this)",}});Copy the code

Solution 2: window.addeventListener

This is all well and good, but can we reduce onerrror tag injection? Similar to the global monitoring mode of Script error onerror (see: Optimization of Script Error Volume – Monitoring reporting and Script Error), can we also use window.onerror to listen for global loading failure?

The answer is no, because onError events do not bubble up, and window.onerror does not receive loading failures. Bubbling doesn’t work, but capture does! We can capture load failure errors globally, although this also monitors script errors, but through! (Event instanceof ErrorEvent) can be used to filter out loading failure errors.

window.addEventListener(
  "error".(event) = > {
    if(! (eventinstanceof ErrorEvent)) {
      // todo}},true
);
Copy the code

Through monitoring data analysis, we found that the reality is not optimistic. The number of resource loading failures during page visits exceeds 10,000 per day and increases as page views increase.

In addition, there are more ways to monitor resource load failures. The above two methods are better solutions, and the other methods are not expanded.

Failed to optimize resource loading. Procedure

Solution 1: Reload the page when loading fails

Once you have the monitoring data, you can start optimizing. When a resource fails to load, refreshing the page is probably the easiest and most straightforward way to try to recover. So when the resource failed to load, we forced the browser refresh to reload the resource through location.reload(true), and combined with SessionStorage to limit the automatic refresh times in order to prevent constant refresh.

According to the monitoring data, 30% of the total abnormal load can be recovered by automatically refreshing the page, and the optimization ratio is not high. In addition, the page refreshing results in multiple blank pages, resulting in poor user experience.

Solution 2: Reload the file that fails to be loaded

Replace dynamic domain name reloading Only the files that fail to be loaded are reloaded. In addition, to prevent loading failures caused by domain name hijacking, the file that fails to be loaded is reloaded using a new domain name. The way to replace the domain name can be to retry multiple CDN domain names, and finally retry to the static server of the page master domain name (master domain is less likely to be hijacked).

However, after the failed resource is successfully reloaded, the original loading order of the page may change, and the final execution order may change, resulting in abnormal execution.

Ensure that JS is executed sequentially

Without considering compatibility, if a resource fails to load by writing a new script tag through document.write, the execution of subsequent script scripts can be blocked until the new tag is loaded and executed, thus ensuring the original order. However, it did not work properly in IE and Edge, which could not meet the compatibility of our project.

So we need to add the logic of “managing the order of JS execution”. After loading the JS file, check whether the dependent files are loaded before executing the service logic. If the file fails to be loaded, the system waits until the file is loaded to ensure normal execution.

Manually managing dependencies and execution timing between module files can be costly to maintain. In fact, modern module packaging tools, such as Webpack, have taken care of this problem naturally. By analyzing the code after construction, it can be found that the code generated by construction not only supports the dependency management between modules, but also supports the above logic of waiting for the completion of loading and then unified execution.

// Check that all loads are complete, and if so, start executing the business logic
function checkDeferredModules() {
  // ...
  if (fulfilled) {
    // All loaded, start executing
    result = __webpack_require__((__webpack_require__.s = deferredModule[0])); }}Copy the code

By default, however, the execution of the business code does not determine whether the configured External module exists. Therefore, if the external file is not loaded or fails to be loaded, using the corresponding module will cause an error.

"react":  (function(module.exports) {
     eval("(function() { module.exports = window[\"React\"]; } ());");
})
Copy the code

Therefore, we need to ensure that the external dependencies are loaded before the business logic is executed. Finally, the wait-external-webpack-plugin webpack plug-in is developed to analyze the dependent external during construction, inject monitoring code, and wait for all dependent files to be loaded before unified execution. (See: Analysis and Optimization of Code execution time after Webpack packaging)

At this point, the logic of retry for a failed load resource is ultimately automated by the build tool and transparent to the developer. Retry with load failure optimized by 99%. Reduced most of the exceptions caused by the original load failure.

What if it always fails to load

How do we deal with the constant failure of loading when the user’s network is constantly changing, or the user is temporarily disconnected, or the browser is suddenly abnormal? A friendly reminder box or the last straw, to avoid the user ineffective wait, ease the user experience.

conclusion

The above is the overall solution of resource loading failure optimization, from how to monitor the loading failure, retry when loading failure, retry failure reminder and so on. Significant optimizations have fixed loading failures and alleviated the user experience of real exceptions.

If there is anything wrong, please correct it. Thank you.


AlloyTeam welcomes excellent friends to join. Resume submission: [email protected] For details, please click Tencent AlloyTeam to recruit Web front-end engineers.