JS异步加载的三种方案
- js加载的缺点:加载工具方法没必要阻塞文档,个别js加载会影响页面效率,一旦网速不好,那么整个网站将等待js加载而不进行后续渲染等工作。
- 有些工具方法需要按需加载,用到再加载,不用不加载。
一、defer与async
1.defer是IE独有的一种js异步加载模式,通过src加载的JS会等到文档解析完才会执行(document.readyState="interactive")。在script标签内部也可以写入内部JS代码,但是直接写入的内部JS代码会同步执行。
<script src="https://cdn.staticfile.org//vue/2.2.2//vue.min.js" type="text/javascript" charset="utf-8" defer=""defer">
//写这里的代码是同步执行
</script>
2.asyn是W3C的标准异步加载模式,通过src加载的JS要等所有资源加载完以后执行(例如:img)(docuement.readyState="complete"),通过asyn异步加载的外部JS才会执行,但是asyn模式的script标签内不能写JS代码。
<script src="https://cdn.staticfile.org//vue/2.2.2//vue.min.js" type="text/javascript" charset="utf-8" async="async">
//这里不能写代码
</script>
因为asyn是W3C标准,IE9之前都不兼容,所以还是很鸡肋。
二、通过插入script标签的方式实现兼容模式的JS异步加载
通过插入script标签的方式实现JS异步加载的原理其实很简单,直接来代码:
<script>
function loadScript(url){
var script = document.createElement("script");//新建一个script标签
script.type="text/javascript";//添加type属性
//绑定src,实现异步加载
script.src = url;
//document.head.appendChild(script);切勿这么做,IE7和IE5上document没有head的DOM对象属性。
var head = document.getElementsByTagName("head")[0];
//插入script标签
head.appendChild(script);//把script添加到domTree节点中,并且会触发执行
}
loadScript("xxx.js");
</script>
异步加载的JS会什么时候执行呢?执行会不会阻塞HTML解析呢?基于异步加载方法来一波测试:
<head>
....
//这里是异步加载的代码
<link rel="stylesheet" type="text/css" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script>
console.log("告诉我什么时候执行的");
</script>
</head>
-----------------------------------------------------------------------------
//这里是异步加载的外部JS文档内容
var n =Number(new Date());
var n2 = Number(new Date());
while((n2 - n) < (10*1000)){
n2 = Number(new Date());
console.log(1);
}
测试执行的结果:
---- 打印39733次1
---- 告诉我什么时候执行的
上面的测试结果告诉了我们,通过插入script异步加载的JS,加载完以后就会立即执行。并且执行的时候会阻塞HTML解析。
先来说说我为什么要在中间加入一行外部CSS代码,我们知道CSS是异步加载,但是CSS的加载会阻塞内部JS的执行,所以足够我测试的外部JS加载了。也就是说在内部JS执行前,外部JS肯定加载完成了,如果外部JS不会阻塞HTML解析也就不会在内部JS之前执行,但是测试的结果是通过添加script标签异步加载的外部JS在内部JS之前执行了,所以就说明了这种异步加载JS的方式加载完以后就会立即执行,并且如果HTML没有解析完就会阻塞HTML解析。
那为什么还需要这样的外部加载方式呢?
我们知道同步加载JS会阻塞HTML解析,而网络因素又是非常不可控的因素,如果某个同步加载的外部JS出现网络不畅通,就会一直阻塞页面。如果是一些工具脚本,不需要修改DOM的话,或者是一些不是一定需要的脚本(比如某个特定事件的JS脚本就可以用这种方式来加载),甚至可以在页面渲染完以后通过某个事件触发来加载它。
既然是异步加载的JS脚本,我们就有必要知道它什么时候加载完了,好方便我们使用,所以下面再来丰富以下这个异步加载JS的方法:
function loadScript(url,callback){
var script = document.createElement("script");//新建一个script标签
script.type="text/javascript";//添加type属性
if(script.readyState){
script.onreadystatechange = function(){
//script.readyState发生改变时触发script.onreadystatechange
if(script.readyState == "complete" || script.readyState == "loaded"){
//script.readyState -->状态码初始值是“loading”,根据文件加载进度,值发生改变
//IE通过script.readyState的状态码监听异步文件加载进度
tools[callback]();//采用对象属性调用需要执行的方法 -- 这里按需要使用
//看到有前辈说IE7和IE5有时候可能会即有"complete",又有"loaded"状态,为了防止万一可以在这里清除监听事件
script.onreadystatechange = null;
}
}
}else{
script.onload = function(){//script.onload-->表示加载完成以后执行
//除IE以外 Safari chrome firefox opera都兼容
tools[callback]();
}
}
//异步加载文件,必须放在事件添加后面,要不然出现先加载完了,事件函数没有绑定的的情况就不会触发了
script.src = url;
//document.head.appendChild(script);切勿这么做,IE7和IE5上document没有head的DOM对象属性。
var head = document.getElementsByTagName("head")[0];
head.appendChild(script);//把script添加到domTree节点中,并且会触发执行
}
W3C标准中有onload事件可以监听外部脚本是否加载完成,所以IE就需要兼容。
IE的script元素的DOM对象上有readyState属性记录外部资源的加载状况,与document对象上的readyState属性一样,有四个值:
uninitialized -- 还未开始载入;
loading - 载入中;
interactive - 已加载,文档与用户可以开始交互;
complete - 载入完成;(有些版本是loanded,听说有些版本这两个状态都会出现本人没遇到过)
(tools[callback](),是我测试回调外部脚本的方法,这个不重要,主要看需求,反正这里就是说明外部JS已经加载完毕了,可以处理自己要处理的程序了)
凌晨了,晚安。
JS异步加载的三种方案的更多相关文章
- JS异步加载的三种方式
js加载的缺点:加载工具方法没必要阻塞文档,过得js加载会影响页面效率,一旦网速不好,那么整个网站将等待js加载而不进行后续渲染等工作. 有些工具方法需要按需加载,用到再加载,不用不加载,. 默认正常 ...
- js异步加载的三种解决方案
默认情况javascript是同步加载的,也就是javascript的加载时阻塞的,后面的元素要等待javascript加载完毕后才能进行再加载,对于一些意义不是很大的javascript,如果放在页 ...
- 点评js异步加载的4种方式
主要介绍了点评js异步加载的4种方式,帮助大家更全面的了解js异步加载方式,感兴趣的小伙伴们可以参考一下 js异步加载的4种方式,点评开始. <!DOCTYPE html> <htm ...
- JavaScript异步加载的三种方式——async和defer、动态创建script
一.script标签的位置 传统的做法是:所有script元素都放在head元素中,必须等到全部js代码都被下载.解析.执行完毕后,才能开始呈现网页的内容(浏览器在遇到<body>标签时才 ...
- js异步加载的5种方式
方案1:$(document).ready 点评: 1.需要引用jquery 2.兼容所有浏览器. 方案2:<script>标签的async="async"属性 asy ...
- js异步加载的3种方式(转载)
1.defer标签 只支持IE defer属性的定义和用法: 属性规定是否对脚本执行进行延迟,直到页面加载为止.有的 javascript 脚本 document.write 方法来创建当前的文 ...
- javascript异步加载的三种解决方案
默认情况javascript是同步加载的,也就是javascript的加载时阻塞的,后面的元素要等待javascript加载完毕后才能进行再加载,对于一些意义不是很大的javascript,如果放在页 ...
- 关于JS异步加载方案
javascript延迟加载的解决方案: 1.使用defer标签 <span style="font-size: small;"><script type=&qu ...
- 转:web前端面试题合集 (Javascript相关)(js异步加载详解)
1. HTTP协议的状态消息都有哪些? 1**:请求收到,继续处理2**:操作成功收到,分析.接受3**:完成此请求必须进一步处理4**:请求包含一个错误语法或不能完成5**:服务器执行一个完全有效请 ...
随机推荐
- c/c++浮点数在内存中存储方式
转自:https://www.cnblogs.com/dolphin0520/archive/2011/10/02/2198280.html 任何数据在内存中都是以二进制的形式存储的,例如一个shor ...
- 实验吧逆向catalyst-system Writeup
下载之后查看知道为ELF文件,linux中执行之后发现很慢: 拖入ida中查看发现有循环调用 sleep 函数: 这是已经改过了,edit -> patch program -> chan ...
- markdown小知识总结
字体.字号.颜色 但如果我们想修改文字大小/颜色/字体,就要用font标签,代码如下: 宋体大小为2的字 color代表字体颜色(要用16进制颜色值),size代表文字大小,face代表字体 效果展示 ...
- 4.13Python数据处理篇之Matplotlib系列(十三)---轴的设置
目录 目录 前言 (一)设置轴的范围 1.同时对于x,y轴设置 2.分别对与x,y轴的设置 (二)设置刻度的大小 1.普通的刻度设置 2.添加文本的刻度设置 3.主副刻度的设置 (三)设置轴的数据 1 ...
- LeetCode算法题-Repeated Substring Pattern(Java实现)
这是悦乐书的第236次更新,第249篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第103题(顺位题号是459).给定非空字符串检查是否可以通过获取它的子字符串并将子字符 ...
- 数据流中的第k大元素的golang实现
设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中 ...
- DecimalFormat格式化十进制数字
DecimalFormat 是 NumberFormat 的一个具体子类,用于格式化十进制数字.该类设计有各种功能,使其能够分析和格式化任意语言环境中的数,包括对西方语言.阿拉伯语和印度语数字的支持. ...
- pydensecrf的使用
参考:https://github.com/lucasb-eyer/pydensecrf 1.使用 对于图像来说,最简单的使用该库的方法是使用DenseCRF2D类: import numpy as ...
- 实验吧 who are you
看到ip,然后提示是要把ip写到数据库里面,就想到了x-forwarded-for注入 扔burp里面试一下 确实有这个问题,从返回信息里面估计出来,应该是盲注,而且基于时间的盲注,试一下吧 测试延迟 ...
- .NET Core 开源工具 IPTools - 快速查询 IP 地理位置、经纬度信息
快速查询IP信息,支持国内和国外IP信息查询,支持查询经纬度,地理位置最高支持到城市. 1. IPTools.China 快速查询中国IP地址信息,包含国家.省份.城市.和网络运营商.非中国IP只支持 ...