【原创】前端性能优化之按需加载JS文件

274 阅读2分钟

关键词:Angular 性能优化 加载JS文件

1.背景

近期发现了项目组内一个Angular项目存在性能问题,加载缓慢,运行稍显卡顿。作为极限性能的追求者,必然要找到问题,优化性能。 存在的问题较多,其中一个典型的问题就是在index.html直接外部链接了太多的JS脚本。你可以想象源码是这样的。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Demo</title>
</head>
<body>
  <app-root></app-root>
  <script src="1.js" defer></script>
  <script src="2.js" defer></script>
  <script src="3.js" defer></script>
  <script src="4.js" defer></script>
  <script src="5.js" defer></script>
  <script src="6.js" defer></script>
  <script src="7.js" defer></script>
  <script src="8.js" defer></script>
  <script src="9.js" defer></script>
  <script src="10.js" defer></script>
</body>
</html>

PS:有些小伙伴分不清defer和async的区别,可以点击此篇博客学习:defer和async的区别

  • 从用户的场景出发,很多JS脚本加载了,但是不会实际用到。这等同于浪费了页面加载性能和页面运行内存
  • 加载的脚本太多,尤其是都设置了defer,一旦中间的一个脚本加载阻塞,会影响后面所有的脚本执行
  • 未使用Angular的scripts能力加载脚本,可能导致JS未压缩
  • ... ...

2.优化

2.1 使用webpack的import函数

this.zone.run(() => { 
     if (this.platform.IOS) {     // 用户设备为苹果手机时,加载fastclick.js 
        import('../assets/js/fastclick.js').then(FastClick => {  
            FastClick.attach(document.body);    })  
        }
      if (['local'].indexOf(environment.env) !== -1) { // 环境匹配时,显示vconsole 
         import('../assets/js/vconsole.min.js').then(VConsole => {   
           new VConsole.default();  
         })  
    }})

2.2 使用script标签

封装ScriptUtil

import {Observable, of, Subject} from 'rxjs';

export class ScriptUtil {
  private static CACHED_SCRIPTS = [];

  static asyncLoad(src: string): Observable<void> {
    if (ScriptLoadUtil.hasBeenLoaded(src)) {
      return of(null);
    }
    const result$ = new Subject<void>();
    const scriptEl = document.createElement('script');
    scriptEl.src = src;
    document.body.appendChild(scriptEl);
    scriptEl.onload = () => {
      ScriptLoadUtil.CACHED_SCRIPTS.push(src);
      result$.next();
    };
    return result$.asObservable();
  }

  static hasBeenLoaded(src: string): boolean {
    return ScriptLoadUtil.CACHED_SCRIPTS.indexOf(src) !== -1;
  }
}```

**加载JS脚本**
```TypeScript
ScriptLoadUtil.load('assets/ckeditor/ckeditor.js')
    .subscribe(() => {  console.log('load js sucess')});

2.3 使用angular.json的scripts

某一些JS脚本还是必须立即加载的,不建议直接写在index.html的方式,可以通过在angular.json配置异步加载脚本

{
    "projects":{
        "demo":{
            "architect":{
                "build":{
                    "scripts":[
                        {  "input": "src/assets/js/browserCheck/browser-version.min.js",  "bundleName": "browser"}
                    ]
                }
            }
        }
    }
}

总结

本文主要介绍外链JS脚本加载与使用的一些优化实践,不局限于Angular,适用于各类项目。 如果您有更好的一些实践,也希望一起讨论学习。