JS的加载和执行
从JS的加载和执行谈性能优化
---高性能JS读后感(第一章)
从脚本的"霸道"说起,随着浏览器的进步,js越来越听话了,所以,我们先说说以前的浏览器是怎么加载js的,以及js如何个霸道法.
1.阻塞的脚本
在以前,js很霸道.
问:当我们在网页中使用<script></script>时,到底发生了什么?
答:无论是内嵌的<script>标签代码还是用<script>引入文件,当浏览器解析到<script>元素时,浏览器就会去加载js内容,这时,页面的其他资源的加载和渲染都会停止,可以说<script>元素是老大,当他说话(加载)时,其他人都不敢说(其他资源都会停止加载和渲染),这就是我们常说的js会阻塞资源加载和页面渲染.这是<script>的霸道(特点).单加载就阻塞了,执行就更不用说了.
所以,我们一般把js放在页面的底部,</body>之前,这样当页面加载到底部的js时,页面的结构和渲染都完成了,这个时候你阻塞也不影响我页面的加载.
后来浏览器开始进步
当浏览器解析到<script>元素时,依旧会阻塞页面其他资源的加载(比如图片)和渲染(css的渲染),但是如果页面有多个<script>,就是说如果我们引入两份js文件,那么这两份js文件是可以并行加载的,不用像之前一样,得第一份加载完再去加载第二份.
浏览器继续进步
2.无阻塞的脚本
无阻塞脚本的秘诀在于,在页面加载完成后才加载js代码.就是说在window对象的load事件触发后再下载脚本.
无阻塞脚本之延迟的脚本(这里的延迟指的是延迟执行,而不是延迟加载)
在现在的主流浏览器,js的加载已经不会阻塞页面了,他能够与其他资源和平共处,就是说他越来越乖巧了,当他在加载时,他允许图片等其他资源的加载,当然执行的话还是会阻塞的.
如下图,js与图片并行加载.(主流浏览器)
js的加载说完了,我们说说js的执行.
问:js执行为什么会阻塞页面的渲染.
答:js在执行时,一般都会操作DOM,操作DOM就会影响到DOM树的渲染,所以js的执行肯定会阻塞渲染.
注意:js是单线程,但浏览器是多线程,js在执行时,DOM树在构建,同时渲染树也在渲染,这个时候如果js构建和浏览器即将渲染的是同一个节点怎么办?所以,为免冲突,js在执行时,停止渲染.
现在js的加载和执行略懂略懂,那么问题来了.
问:js放置的最优位置的底部,我现在有一份js必须在head,等页面结构加载完(window.onload)就马上执行,就是说我要先加载后执行,那么我该怎么办?
答:用defer,在<script>加上defer属性
<script type="text/javascript" src="jquery-1.8.3.min.js" defer></script>
defer的功能:指明本元素所含的脚本不会修改DOM,(即只加载不执行),因此代码能安全的延迟执行.阻塞的脚本变成延迟的脚本了.
问:我现在有一份js必须在head,想让它加载完马上执行怎么办?
答:用async,在<script>加上async属性
<script type="text/javascript" src="jquery-1.8.3.min.js" async></script>
async的功能:异步并行加载js,加载完之后立即执行.defer是加载后等页面加载后再执行,两者的区别是执行方式的不同.
问:我们什么时候用defer,什么时候用async?
答:
1.当js并不需要立马加载的时候,我们把js放在页面底部就可以了,不需要用到这两个属性.
2.当某段js需要立马加载时,判断其是否需要立即执行,需要就用async,不需要立即执行就用defer.
当然,这里需要强调下,js立即执行,这个时候是会阻塞页面的渲染的.
也需要考虑到,这两个属性的浏览器支持情况,在不支持这两个属性的浏览器上,其实他们是会阻塞页面的渲染的(不支持的情况下,加载js不阻塞,但是加载完后的js会去立马执行,这个时候就会阻塞了).
3.DOM树创建完并不意味着页面资源加载完,所以在DOM树创建完,触发window.onload的时候,中间还是有一点时间的,这个时间就是加载其他资源的时间.(比如说加载js)
4.其实,在不考虑多个js文件有多个http请求数的情况下,当你把js放在页面底部的时候,其实已经是一种无阻塞的脚本了.
总结:(摘自书中内容)
减少js对性能的影响:
1.</body>闭合标签之前,将所有的<script>标签放到页面底部.这能确保在脚本执行前页面已经完成了渲染.
2.合并脚本.页面的中的<script>标签越少,加载也就越快,响应也更迅速.无论外链文件还是内嵌脚本都是如此.
3.有多种无阻塞下载js的方法:(可自行搜索用法)
- 使用<script>标签的defer属性
- 使用动态创建的<script>元素来下载并执行代码
- 使用XHR对象下载js代码并注入页面中
个人觉得,在目前,js模块加载器,js模块打包器都有,解决文件的依赖关系并且打成一个包是比较容易的,再把打成的包放到</body>,可以减少http请求,也不会阻塞页面加载和渲染(可以说这是一个无阻塞的脚本),虽然这个文件可能很大,但相对于减少了http请求数来说,还是利大于弊的,因为我们一个页面不打包可能有很多个js,这样请求数会很多.
当然对于一些库,我们可以单独引入,这样可以缓存起来,缓存起来的文件加载就更快了.
有错请指出,欢迎交流~
JS的加载和执行的更多相关文章
- JS 动态加载脚本 执行回调
JS 动态加载脚本 执行回调 关于在javascript里面加载其它的js文件的问题可能很多人都遇到过,但很多朋友可能并不知道怎么判断我们要加载的js文件是否加载完成,如果没有加载完成我们就调用文件 ...
- 性能优化-css,js的加载与执行
前端性能优化 css,js的加载与执行 javascript是单线程的 一个网站在浏览器是如何进行渲染的呢? html页面加载渲染的过程 html渲染过程的一些特点 顺序执行,并发加载 词法分析 并发 ...
- JS 动态加载脚本 执行回调_转
关于在javascript里面加载其它的js文件的问题可能很多人都遇到过,但很多朋友可能并不知道怎么判断我们要加载的js文件是否加载完成,如果没有加载完成我们就调用文件里面的函数是不会成功的.本文讲解 ...
- JS脚本加载与执行对性能的影响
高性能JavaScript-JS脚本加载与执行对性能的影响 在web产品优化准则中,很重要的一条是针对js脚本的加载和执行方式的优化.本篇文章简单描述一下其中的优化准则. 1. 脚本加载优化 1.1 ...
- 前端性能优化 css和js的加载与执行
一个网站在浏览器端是如何进行渲染的? html本身首先会被渲染成 DOM 树,实际上 html 是最先通过网址请求过来的,请求过来之后,html 本身会由一个字节流转化成一个字符流,浏览器端拿的就是字 ...
- 高性能javascript学习笔记系列(1) -js的加载和执行
这篇笔记的内容主要涉及js的脚本位置,如何加载js脚本和脚本文件执行的问题,按照自己的理解结合高性能JavaScript整理出来的 javascript是解释性代码,解释性代码需要经历转化成计算机指令 ...
- js并行加载,顺序执行
js并行加载,顺序执行 <script>运行脚本或加载外部文件时,会阻塞页面渲染,阻塞其他资源的加载.如果页面中需要加载多个js文件,在古老浏览器中性能会比较糟糕. 因此有了最原始的优化原 ...
- jquery js 动态加载 js文件
jquery方法 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://ww ...
- 使用getScript()方法异步加载并执行js文件
使用getScript()方法异步加载并执行js文件 使用getScript()方法异步请求并执行服务器中的JavaScript格式的文件,它的调用格式如下所示: jQuery.getScript(u ...
随机推荐
- Delphi 运行后错误提示“无效的授权说明”
Delphi 运行后错误提示“无效的授权说明” 一般情况是:数据库的连接出现了问题. 解决方法:检查加载数据库是否正常,能否正常连接.
- python中常用内置函数用法总结
强制类型转换:int()float()str()list()tuple()set()dict()总结,这几种类型转换函数得用法基本一致,基本就是int(要转换得数据).返回值类型为对应得数据类型 ...
- 【SpingBoot】 测试如何使用SpringBoot搭建一个简单后台1
很久没写博客了,最近接到一个组内的测试开发任务是做一个使用SpringBoot 开发一个后台程序(还未完成),特写感想记录一下 1. 为什么选择SpringBoot ? 首先是目前很多公司的后台还是J ...
- Java反射实现Servlet处理多个请求--server分发
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.serv ...
- fpm rpm制作
使用fpm命令制作rpm包并安装 工作中有如下情况需要将文件打包rpm: 避免重复工作,将源码程序打包为rpm 使用yum发布项目,项目打包为rpm 将自己写好的程序打包为rpm,提供给用户下载 其他 ...
- 启动线程,start和run的区别
每个线程都有要执行的任务.线程的任务处理逻辑可以在Tread类的run实例方法中直接实现或通过该方法进行调用,因此 run()相当于线程的任务处理逻辑的入口方法,它由Java虚拟机在运行相应线程时直接 ...
- LeetCode 最短无序连续子数组
题目链接:https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/ 题目大意: 略. 分析: 如果排序区间为 [L ...
- luoguP1313 计算系数 题解(NOIP2011)
P1313 计算系数 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include<cm ...
- UVA 12446 How Many... in 3D! ( 递推 + 树状数组 )
C. How Many... in 3D! Time Limit: 1000ms Memory Limit: 131072KB 64-bit integer IO format: %lld ...
- JavaScript 盖尔-沙普利算法
最近在学 JavaScript , 为了尽快熟悉语法,决定移植以前写的盖尔-沙普利算法. c# 下的代码:https://www.cnblogs.com/aitong/p/10973774.html ...