视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001 知道1 知道21 知道41 知道61 知道81 知道101 知道121 知道141 知道161 知道181 知道201 知道221 知道241 知道261 知道281
问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
引入外部js脚本加载慢与页面白屏问题的解决
2020-11-27 22:02:49 责编:小采
文档

问题背景

最近做的一个项目需要引入一个外部的第三方js脚本。由于这是一个关于渲染3D建筑的脚本,所以体积比较大,大概有2M,加载完成也得要个好几秒,网速慢的时候十几秒都有可能。

之前也遇到脚本加载慢的问题,但是没这么慢,所以这次就特别写个文章记录一下我的解决过程。

首先上两张项目已完成的截图。

下图是通过第三方脚本渲染出来的3D建筑页面

下图是首页,不需要用到第三方脚本

遇到的问题和需求

  • 引入外部脚本太大,加载时间太长
  • 首页用不到外部脚本,需要先渲染出来
  • 用到外部脚本的页面,要是脚本还没加载好就点进去会报错
  • 解决问题的过程

    我一开始通过<script>标签直接引入到入口文件的头部,如下

    <head>
    <script src="./DDEarth.js"></script>
    </head>

    这样页面是可以正常加载的,但是页面出来的很慢,一开始会白屏一段时间等待这个js脚本加载完成。虽然脚本体积大是事实,但这用户体验肯定是可以优化的。

    后来我又把这个脚本放到了页面底部,也就是</body>标签下面。这样可以先让页面渲染出来,再慢慢加载这个庞大的脚本,于是首页是出来的很快,但是从首页跳转到需要用到这个脚本的页面就会报错,如下

    这个错误原因是这个页面需要用到window.DDEarth这个对象,但是由于此时这个脚本还没有加载完成,所以window下并没有这个对象,所以就报错了。

    于是我又想到等脚本加载完成再执行相关方法,这时就需要用到onload这个方法了,onload这个方法在脚本加载完成的时候会执行。我引入脚本的时候给它加了个id,方便以后通过dom找到,代码如下:

    // 入口文件
     </body>
     <script id="ddEarthScript" src="./DDEarth.js"></script>
    
    // PageTwo.js
    componentDidMount() {
     const scriptEle = document.getElementById('ddEarthScript'); // 找到脚本节点
     if (scriptEle) {
     scriptEle.onload = () => {
     // 脚本加载完成执行加载地图的操作
     this.loadEarthMap();
     };
     }
     }

    有了以上代码我跳转到PageTwo这个页面的时候,会等到DDEarth.js这个脚本加载完成,再执行加载建筑地图的操作,这样就不会报错了。

    但是这又有一个问题,就是如果我跳转到PageTwo的之前,DDEarth.js已经加载完成了,onload这个事件在PageTwo这个页面中就不生效了,loadEarthMap这个方法自然也就不会执行了。

    这个时候需要加一个判断,完整代码如下:

    // PageTwo.js
    componentDidMount() {
     if (window.DDEarth) { // 如果跳转到此页面之前,脚本已加载完成
     this.loadEarthMap();
     } else {
     const scriptEle = document.getElementById('ddEarthScript');
     if (scriptEle) {
     scriptEle.onload = () => {
     this.loadEarthMap();
     };
     }
     }
     }

    总结一下我以上解决问题的步骤

    在入口文件的底部引入第三方脚本,并给它加个id。当然也可以放在<head>里,但是需要额外加上html5新增的 async 这个属性,这样脚本才能异步加载。

    在需要用到这个脚本的页面,先判断脚本有没有加载完成(我这里是直接判断window.DDEarth对象是否为空)。如果已经加载完成,就直接执行相关操作;如果没有,先通过document.getElementById找到那个脚本,然后监听脚本的onload事件,再做相关操作。

    什么情况可以用我以上思路?

  • 引入的第三方脚本较大,加载所需时间较长
  • 页面按需加载,整个项目只有其中某几个页面需要用到引入的第三方脚本
  • 第三方脚本没加载完就渲染页面导致的页面报错
  • 下载本文
    显示全文
    专题