1、三种加载方式图解
同步加载、延迟加载和异步加载三种加载方式图解如下:
从上面图中,可以看出:
<script>:同步模式,脚本的获取和执行是同步的。此过程中页面被阻塞,停止解析。
<script defer = “defer”>:延迟模式,脚本的获取是异步的,执行是同步的。脚本加载不阻塞页面的解析,脚本在获取完后并不立即执行,而是等到DOMready之后才开始执行。
<script async = “async”>:异步模式,脚本的获取是异步的,执行是同步的。但是和<script defer = “defer”>的不同点在于脚本获取后会立刻执行,这就会造成脚本的执行顺序和页面上脚本的排放顺序不一致,可能造成脚本依赖的问题。
2、三种加载方式的适用场合
同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止后续的解析,只有当当前加载完成,才能进行下一步操作。所以默认同步执行才是安全的。但这样如果js中有输出document内容、修改dom、重定向等行为,就会造成页面堵塞。所以一般建议把<script>标签放在<body>结尾处,这样尽可能减少页面阻塞。
延迟加载也称为惰性加载,即在长网页中延迟加载图像。用户滚动到它们之前,视口外的图像不会加载。这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快。在某些情况下,它还可以帮助减少服务器负载。举个例子来说明,当打开淘宝首页的时候,只有在浏览器窗口里的图片才会被加载,当你滚动首页向下滑的时候,进入视口内的图片才会被加载,而其它从未进入视口的图像不会也不会加载。
有些JS代码在某些情况才需要使用,并不是在页面初始化的时候就要用到。延迟加载就是为了解决这个问题,将JS切分成许多模块,页面初始化时只加载需要立即执行的JS,然后其它JS的加载延迟到第一次需要用到的时候再加载,类似图片的延迟加载。
JS的加载分为两个部分:下载和执行。异步加载只是解决了下载的问题,但是代码在下载完成后就会立即执行,在执行过程中浏览器处于阻塞状态,响应不了任何需求。
3、script标签文本通常放在</body>之前,Google为什么把它放在</body>标签之后</html>之前?
Google并没有把<script>插入在</body>之后,而只是没有写</body>和</html>闭合标签。这样做是符合标准的,不仅是html5标准,从第一个HTML正式标准HTML 2.0开始,这样做都是允许的。相反,在</body>之后再插入其他元素,从HTML 2.0起就是不合标准的。
按照HTML5标准中的HTML语法规则,如果在</body>后再出现<script>或任何元素的开始标签,都是parse error,浏览器会忽略之前的</body>,即视作仍旧在body内。所以实际效果和写在</body>之前是没有区别的。
总之,这种写法虽然也能work,但是并没有带来任何额外好处,实际上出现这样的写法很可能是误解了“将script放在页面最末端”的教条。所以还是不要这样写为好。放在 html 结束标签之前应该是不规范的(通不过 HTML 验证),放在 body 结束之前才对。