高性能JavaScript - 加载和执行

2019-12-12  本文已影响0人  _树先生_

### 无阻塞的脚本

减少`JavaScript`文件大小,并限制`HTTP`请求数,仅仅是创建响应迅速的Web应用的第一步。Web应用功能越丰富,所需的`JavaScript`代码就越多,所以精简源代码并不总是可行。尽管下载单个较大的`JavaScript`文件只会产生一次HTTP请求,却会锁死浏览器一大段时间。为避免这种情况,我们需要向页面中逐步加载`JavaScript`代码,这样做在某种程度上来说不会阻塞浏览器。

无阻塞脚本的秘诀在于,在页面加载完成后才加载`JavaScript`代码。即在`window`对象的`load`事件触发后再下载脚本。

### 延迟的脚本

```

<script type="text/javascript" src="./init.js" defer="defer"></script>

<script src="./init.js" async="async" />

```

- [defer](http://www.w3school.com.cn/tags/att_script_defer.asp) 只有 Internet Explorer 支持 defer 属性。

- [async](http://www.w3school.com.cn/tags/att_script_async.asp) async 属性是 HTML5 中的新属性。

### 动态脚本元素

```

var script = document.createElement('script');

script.type = "text/javascript";

script.src = "./init.js";

document.getElementsByTagName("head")[0].appendChild(script);

```

### XMLHttpRequest 脚本注入

```

var xhr = new XMLHttpRequest();

xhr.open("get", "./init.js", true);

xhr.onreadystatechange = function () {

    /**

    * Uninitialized (0) - 初始化状态

    * Open (1) - open() 方法已调用,但是 send() 方法未调用;请求还没有被发送

    * Sent (2) - Send() 方法已调用,HTTP 请求已发送到 Web 服务器。未接收到响应。

    * Receiving (3) - 所有响应头部都已经接收到。响应体开始接收但未完成。

    * Loaded (4) - HTTP 响应已经完全接收。

    */

    if (xhr.readyState == 4) {

        var status = xhr.status; // HTTP状态码

        if (status >= 200 && status < 300 || status == 304) {

            var script = document.createElement('script');

            script.type = "text/javascript";

            script.text = xhr.responseText;

            document.body.appendChild(script);

        }

    }

}

xhr.send(null);

```

### 推荐的无阻塞模式

```

/**

* 加载脚本

* url [String] 要加载的脚本地址

* callback [Function] 加载成功后的回调函数

*/

function loadScript (url, callback) {

    var script = document.createElement('script');

    script.type = "text/javascript";

    if (script.readyState) { // IE浏览器方案

        script.onreadystatechange = function () {

            /**

            * uninitialized: 初始状态

            * loading: 开始下载

            * loaded: 下载完成

            * interactive: 数据下载完成但尚不可用

            * complete: 所有数据已准备就绪

            */

            var readyState = script.readyState;

            if (readyState == "loaded" || readyState == "complete") {

                script.onreadystatechange = null;

                callback();

            }

        }

    } else {

        script.onload = function () {

            callback();

        }

    }

    script.src = url;

    document.getElementsByTagName("head")[0].appendChild(script);

}

loadScript("./init.js", function () {

    Application.init();

})

```

### 小结

    每次遇到`<script>`标签都会阻塞浏览器的其他进程,如界面渲染;页面需要等待代码下载并执行完成,才可以渲染。推荐一下几种优化方案:

    1、将所有的`<script>`标签放在`</body>`闭合标签前;确保在脚本执行前页面已经渲染完成。

    2、合并脚本。减少`<script>`标签使 加载 和 响应都变得更快。

    3、无阻塞下载方法:

        - 使用`<script>`标签的`defer`属性

        - 使用动态创建`<script>`元素来下载并执行代码。

        - 使用`XHR`对象下载代码并注入页面执行

上一篇下一篇

猜你喜欢

热点阅读