JS同步、异步、延迟加载的方法


Posted in Javascript onMay 05, 2018

本文讲述了JS同步、异步、延迟加载的方法。分享给大家供大家参考,具体如下:

一:同步加载

我们平时使用的最多的一种方式。

<script src="http://yourdomain.com/script.js"></script>

同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止后续的解析,只有当当前加载完成,才能进行下一步操作。所以默认同步执行才是安全的。但这样如果js中有输出document内容、修改dom、重定向等行为,就会造成页面堵塞。所以一般建议把<script>标签放在<body>结尾处,这样尽可能减少页面阻塞。

二:异步加载

异步加载又叫非阻塞加载,浏览器在下载执行js的同时,还会继续进行后续页面的处理。主要有三种方式。

方法一:也叫Script DOM Element

(function(){
 var scriptEle = document.createElement("script");
 scriptEle.type = "text/javasctipt";
 scriptEle.async = true;
 scriptEle.src = "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js";
 var x = document.getElementsByTagName("head")[0];
 x.insertBefore(scriptEle, x.firstChild); 
 })();

<async>属性是HTML5中新增的异步支持。此方法被称为Script DOM Element 方法。Google Analytics 和 Google+ Badge 都使用了这种异步加载代码。

(function(){;
 var ga = document.createElement('script'); 
 ga.type = 'text/javascript'; 
 ga.async = true; 
 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 
 var s = document.getElementsByTagName('script')[0]; 
 s.parentNode.insertBefore(ga, s); 
})();
 

但是这种加载方式执行完之前会阻止onload事件的触发,而现在很多页面的代码都在onload时还执行额外的渲染工作,所以还是会阻塞部分页面的初始化处理。

方法二:onload时的异步加载

(function(){
 if(window.attachEvent){
 window.attachEvent("load", asyncLoad);
 }else{
 window.addEventListener("load", asyncLoad);
 }
 var asyncLoad = function(){
 var ga = document.createElement('script'); 
 ga.type = 'text/javascript'; 
 ga.async = true; 
 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 
 var s = document.getElementsByTagName('script')[0]; 
 s.parentNode.insertBefore(ga, s);
 }
)();

这种方法只是把插入script的方法放在一个函数里面,然后放在window的onload方法里面执行,这样就解决了阻塞onload事件触发的问题。

注:DOMContentLoaded与load的区别。前者是在document已经解析完成,页面中的dom元素可用,但是页面中的图片,视频,音频等资源未加载完,作用同jQuery中的ready事件;后者的区别在于页面所有资源全部加载完毕。

方法三:其他方法

由于JavaScript的动态性,还有很多异步加载方法: XHR Injection、 XHR Eval、 Script In Iframe、 Script defer属性、 document.write(script tag)。

XHR Injection(XHR 注入):通过XMLHttpRequest来获取javascript,然后创建一个script元素插入到DOM结构中。ajax请求成功后设置script.text为请求成功后返回的responseText。

//获取XMLHttpRequest对象,考虑兼容性。
 var getXmlHttp = function(){
 var obj;
 if (window.XMLHttpRequest)
  obj = new XMLHttpRequest();
 else
  obj = new ActiveXObject("Microsoft.XMLHTTP");
 return obj;
 }; 
 //采用Http请求get方式;open()方法的第三个参数表示采用异步(true)还是同步(false)处理
 var xmlHttp = getXmlHttp();
 xmlHttp.open("GET", "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js", true);
 xmlHttp.send(); 
 xmlHttp.onreadystatechange = function(){
 if (xmlHttp.readyState == 4 && xmlHttp.status == 200){
  var script = document.createElement("script");
  script.text = xmlHttp.responseText;
  document.getElementsByTagName("head")[0].appendChild(script);
 }
 }

XHR Eval:与XHR Injection对responseText的执行方式不同,直接把responseText放在eval()函数里面执行。 

//获取XMLHttpRequest对象,考虑兼容性。
 var getXmlHttp = function(){
 var obj;
 if (window.XMLHttpRequest)
  obj = new XMLHttpRequest();
 else
  obj = new ActiveXObject("Microsoft.XMLHTTP");
 return obj;
 }; 
 //采用Http请求get方式;open()方法的第三个参数表示采用异步(true)还是同步(false)处理
 var xmlHttp = getXmlHttp();
 xmlHttp.open("GET", "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js", true);
 xmlHttp.send(); 
 xmlHttp.onreadystatechange = function(){
 if (xmlHttp.readyState == 4 && xmlHttp.status == 200){
  eval(xmlHttp.responseText);
  //alert($);//可以弹出$,表明JS已经加载进来。click事件放在其它出会出问题,应该是还没加载进来
  $("#btn1").click(function(){
  alert($(this).text());
  });
 }
 }

Script In Irame:在父窗口插入一个iframe元素,然后再iframe中执行加载JS的操作。

var insertJS = function(){alert(2)};
 var iframe = document.createElement("iframe");
 document.body.appendChild(iframe);
 var doc = iframe.contentWindow.document;//获取iframe中的window要用contentWindow属性。
 doc.open();
 doc.write("<script>var insertJS = function(){};<\/script><body onload='insertJS()'></body>");
 doc.close();

GMail Mobile:业内JS内容被注释,所以不会执行,在需要的时候,获取script中的text内容去掉注释,调用eval()执行。

<script type="text/javascript"> 
 /* 
 var ... 
 */ 
 </script>

HTML5新属性:async和defer属性
defer属性:IE4.0就出现。defer属声明脚本中将不会有document.write和dom修改。浏览器会并行下载其他有defer属性的script。而不会阻塞页面后续处理。注:所有的defer脚本必须保证按顺序执行的。

    <script type="text/javascript" defer></script>

async属性:HTML5新属性。脚本将在下载后尽快执行,作用同defer,但是不能保证脚本按顺序执行。他们将在onload事件之前完成。

    <script type="text/javascript" defer></script>

Firefox 3.6、Opera 10.5、IE 9和最新的Chrome和Safari都支持async属性。可以同时使用async和defer,这样IE 4之后的所有IE都支持异步加载。

没有async属性,script将立即获取(下载)并执行,期间阻塞了浏览器的后续处理。如果有async属性,那么script将被异步下载并执行,同时浏览器继续后续的处理。

总结: 对于支持HTML5的浏览器,实现JS的异步加载只需要在script元素中加上async属性,为了兼容老版本的IE还需加上defer属性;对于不支持HTML5的浏览器(IE可以用defer实现),可以采用以上几种方法实现。原理基本上都是向DOM中写入script或者通过eval函数执行JS代码,你可以把它放在匿名函数中执行,也可以在onload中执行,也可以通过XHR注入实现,也可以创建一个iframe元素,然后在iframe中执行插入JS代码。

三:延迟加载

有些JS代码在某些情况在需要使用,并不是页面初始化的时候就要用到。延迟加载就是为了解决这个问题。将JS切分成许多模块,页面初始化时只加载需要立即执行的JS,然后其它JS的加载延迟到第一次需要用到的时候再加载。类似图片的延迟加载。

JS的加载分为两个部分:下载和执行。异步加载只是解决了下载的问题,但是代码在下载完成后就会立即执行,在执行过程中浏览器处于阻塞状态,响应不了任何需求。

解决思路:为了解决JS延迟加载的问题,可以利用异步加载缓存起来,但不立即执行,需要的时候在执行。如何进行缓存呢?将JS内容作为Image或者Object对象加载缓存起来,所以不会立即执行,然后在第一次需要的时候在执行。

1:模拟较长的下载时间:

利用thread让其sleep一段时间在执行下载操作。

2:模拟较长的JS代码执行时间

var start = Number(new Date());
while(start + 5000 > Number(new Date())){//执行JS}

这段代码将使JS执行5秒才完成!

JS延迟加载机制(LazyLoad):简单来说,就是在浏览器滚动到某个位置在触发相关的函数,实现页面元素的加载或者某些动作的执行。如何实现浏览器滚动位置的检测呢?可以通过一个定时器来实现,通过比较某一时刻页面目标节点位置和浏览器滚动条高度来判断是否需要执行函数。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript效率调优经验
Jun 04 Javascript
js读取本地excel文档数据的代码
Nov 11 Javascript
讲解JavaScript的Backbone.js框架的MVC结构设计理念
Feb 14 Javascript
对象转换为原始值的实现方法
Jun 06 Javascript
Javascript 基础---Ajax入门必看
Jul 06 Javascript
深入理解React中es6创建组件this的方法
Aug 29 Javascript
Node.js实现兼容IE789的文件上传进度条
Sep 02 Javascript
使用Ajax与服务器(JSON)通信实例
Nov 04 Javascript
JS如何实现在页面上快速定位(锚点跳转问题)
Aug 14 Javascript
通过源码分析Vue的双向数据绑定详解
Sep 24 Javascript
node.js读取Excel数据(下载图片)的方法示例
Aug 02 Javascript
微信小程序实现滑动操作代码
Apr 23 Javascript
JavaScript生成指定范围随机数和随机序列的方法
May 05 #Javascript
JS文件中加载jquery.js的实例代码
May 05 #jQuery
关于js的三种使用方式(行内js、内部js、外部js)的程序代码
May 05 #Javascript
js动态引入的四种方法
May 05 #Javascript
关于HTML5的data-*自定义属性的总结
May 05 #Javascript
深入浅析Vue.js计算属性和侦听器
May 05 #Javascript
详解js跨域请求的两种方式,支持post请求
May 05 #Javascript
You might like
PHP中函数内引用全局变量的方法
2008/10/20 PHP
Function eregi is deprecated (解决方法)
2013/06/21 PHP
浅谈web上存漏洞及原理分析、防范方法(文件名检测漏洞)
2013/06/29 PHP
12个非常有创意的JavaScript小游戏
2010/03/18 Javascript
javascript检测对象中是否存在某个属性判断方法小结
2013/05/19 Javascript
7个让JavaScript变得更好的注意事项
2015/01/28 Javascript
JavaScript使用concat连接数组的方法
2015/04/06 Javascript
js实现文本框宽度自适应文本宽度的方法
2015/08/13 Javascript
jQuery添加和删除指定标签的方法
2015/12/16 Javascript
JS获取时间的相关函数及时间戳与时间日期之间的转换
2016/02/04 Javascript
Jquery实现的简单轮播效果【附实例】
2016/04/19 Javascript
JavaScript_object基础入门(必看篇)
2016/06/13 Javascript
AngularJS实现星星等级评分功能
2016/09/24 Javascript
基于JS实现仿百度百家主页的轮播图效果
2017/03/06 Javascript
JS实现线性表的顺序表示方法示例【经典数据结构】
2017/04/11 Javascript
微信小程序实现点击按钮修改字体颜色功能【附demo源码下载】
2017/12/05 Javascript
vue.js项目 el-input 组件 监听回车键实现搜索功能示例
2018/08/25 Javascript
nodejs中实现用户注册路由功能
2019/05/20 NodeJs
vue项目出现页面空白的解决方案
2019/10/31 Javascript
react实现复选框全选和反选组件效果
2020/08/25 Javascript
[08:29]DOTA2每周TOP10 精彩击杀集锦vol.7
2014/06/25 DOTA
python利用beautifulSoup实现爬虫
2014/09/29 Python
浅谈Python数据类型之间的转换
2016/06/08 Python
Python实现获取照片拍摄日期并重命名的方法
2017/09/30 Python
Python pymongo模块常用操作分析
2018/09/01 Python
python利用Tesseract识别验证码的方法示例
2019/01/21 Python
opencv3/C++图像像素操作详解
2019/12/10 Python
Django 解决上传文件时,request.FILES为空的问题
2020/05/20 Python
Python Celery异步任务队列使用方法解析
2020/08/10 Python
CSS3 中filter(滤镜)属性使用详解
2020/04/07 HTML / CSS
英国最大的电子产品和家电零售企业:Currys PC World
2016/09/24 全球购物
商务英语毕业生自荐信范文
2013/11/08 职场文书
七年级音乐教学反思
2014/01/26 职场文书
党员三严三实对照检查材料
2014/10/13 职场文书
模范班主任事迹材料
2014/12/17 职场文书
结婚纪念日感言
2015/08/01 职场文书