JavaScript性能—加载与执行

问题

由于浏览器多数使用单一进程来处理用户界面(UI)和JavaScript的执行,也就是说当浏览器在执行JavaScript代码的时候,不能做其他任何事情。一旦JavaScript执行的时间过长,由于浏览器无法响应用户的其他操作,就会给人“卡住”的感觉。

反应在代码上,也就是每次遇到<script>标签,浏览器都会停下来等待脚本的下载、解析和执行。

之所以浏览器采用单进程来处理,是因为脚本执行的过程中随时有可能修改页面内容,所以必须等到脚本执行完毕之后才能进行UI的渲染。例如:

<!DOCTYPE html>
<html>
    <head>
        <title>Test</title>
    </head>
    <body>
        <div>
            <script>
                document.write(new Date().toDateString());
            </script>
        </div>
    </body>
</html>

解决措施

脚本位置

一般我们加载脚本文件或CSS文件都是如下写法:

<hmtl>
    <head>
        <script type="text/javascript" src="script1.js"></script>
        <script type="text/javascript" src="script2.js"></script>
        <script type="text/javascript" src="script3.js"></script>
        <link rel="stylesheet" type="text/css" href="style.css">
    </head>
    <body>
        <div>Hello World</div>
    </body>
</html>

理论上来说,把脚本和样式文件放在<head>标签内加载有利于页面渲染和交互的正确性。

不过这样会造成严重的性能问题,前面我们知道浏览器遇到<script>标签就会停下来等它们全部下载并执行完,之后才会继续渲染页面。而浏览器在解析到<body>标签之后才会渲染页面的内容

换句话说,将<script>标签放在<head>标签内加载可能会导致页面长时间显示空白页面,也无法与页面进行交互,给人的感觉就是加载十分缓慢。

虽然现代浏览器大都允许并行下载脚本文件,这是个好消息,但是脚本的下载过程依然会阻塞其他资源的下载,例如图片。而且,浏览器依然需要等待脚本全部执行完才能继续。所以问题并没有得到根本的解决而事实上,由于JavaScript的单线程,这个问题很难得到根治

不过,我们依然可以试图让这个问题在用户看起来不那么明显。

可以把<script>标签放在<body>标签的最底部,这样可以等到页面内容都加载出来再开始加载<script>

由于页面都已经加载出来了,所以给到用户的感觉就是“这个网页加载速度还行”,尽管此时可能脚本文件尚未完成加载与执行。

以上面代码为例:

<hmtl>
    <head>
        <link rel="stylesheet" type="text/css" href="style.css">
    </head>
    <body>
        <div>Hello World</div>
        <script type="text/javascript" src="script1.js"></script>
        <script type="text/javascript" src="script2.js"></script>
        <script type="text/javascript" src="script3.js"></script>
    </body>
</html>

组织脚本

由于脚本文件的下载会阻塞页面的渲染,哪怕是脚本文件可以并行下载,可是HTTP请求所带来的性能开销也十分可观,于是尽量减少脚本文件的个数,或者说<script>的个数将能够改善性能。

可以通过打包的方式,将多个脚本文件合成一个,从而减少<script>标签的个数。

无阻塞的脚本

减少脚本文件大小并限制HTTP请求数只是性能优化的第一步。尽管下载单个较大的脚本文件只产生一次HTTP请求,却会阻塞浏览器一大段时间。为了避免这种情况的发生,我们可以逐步往页面中加载JavaScript文件。

脚本延迟(defer)

HTML为<script>标签定义了一个扩展属性defer,用以表明本元素所含脚本不会修改DOM,因此代码能够安全地延迟执行。

带有defer属性的<script>可以放置在文档的任何地方。它会在浏览器解析到该标签是开始下载,但并不会执行,直到DOM加载完成(DOMReady)。

动态脚本

所谓动态脚本就是利用了可以使用JavaScript来创建<script>并加入到页面之中,这样就可以在需要时再加载脚本文件了。例如:

let script = document.createElement("script");
script.type = "text/javascript";
scirpt.src = "file1.js";
document.head.appendChild(script);

猜你喜欢

转载自blog.csdn.net/hjc256/article/details/93670299
今日推荐