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 相关文章推荐
showModelessDialog()使用详解
Sep 21 Javascript
javascript中的startWith和endWith的几种实现方法
May 07 Javascript
javascript中文本框中输入法切换的问题
Dec 10 Javascript
javascript实现下班倒计时效果的方法(可桌面通知)
Jul 10 Javascript
jQuery语法小结(超实用)
Dec 31 Javascript
WordPress中鼠标悬停显示和隐藏评论及引用按钮的实现
Jan 12 Javascript
深入浅析JavaScript面向对象和原型函数
Feb 06 Javascript
jQuery EasyUI框架中的Datagrid数据表格组件结构详解
Jun 09 Javascript
JS检测数组类型的方法小结
Mar 14 Javascript
使用 Node.js 开发资讯爬虫流程
Jan 07 Javascript
javascript设计模式 ? 适配器模式原理与应用实例分析
Apr 13 Javascript
JavaScript 中的执行上下文和执行栈实例讲解
Feb 25 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
打造计数器DIY三步曲(下)
2006/10/09 PHP
浅析php静态方法与非静态方法的用法区别
2016/05/17 PHP
利用Laravel事件系统如何实现登录日志的记录详解
2017/05/20 PHP
Javascript与vbscript数据共享
2007/01/09 Javascript
PNGHandler-借助JS让PNG图在IE下实现透明(包括背景图)
2007/08/31 Javascript
修改好的jquery滚动字幕效果实现代码
2011/06/22 Javascript
在js中判断checkboxlist(.net控件客户端id)是否有选中
2013/04/11 Javascript
14款NodeJS Web框架推荐
2014/07/11 NodeJs
Javascript前端UI框架Kit使用指南之Kitjs简介
2014/11/28 Javascript
JS实现仿雅虎首页快捷登录入口及导航模块效果
2015/09/19 Javascript
快速掌握Node.js环境的安装与运行方法
2016/02/16 Javascript
JS实现动态表格的添加,修改,删除功能(推荐)
2016/06/15 Javascript
JavaScript中数组Array.sort()排序方法详解
2017/03/01 Javascript
layer弹出层框架alert与msg详解
2017/03/14 Javascript
bootstrap3 dialog 更强大、更灵活的模态框
2017/04/20 Javascript
nodejs实现爬取网站图片功能
2017/12/14 NodeJs
防止Layui form表单重复提交的实现方法
2019/09/10 Javascript
JavaScript提升机制Hoisting详解
2019/10/23 Javascript
[04:14]从西雅图到上海——玩家自制DOTA2主题歌曲应援TI9
2019/07/11 DOTA
Python解惑之True和False详解
2017/04/24 Python
Python实现基本数据结构中队列的操作方法示例
2017/12/04 Python
pytorch 调整某一维度数据顺序的方法
2018/12/08 Python
Pandas读写CSV文件的方法示例
2019/03/27 Python
python flask安装和命令详解
2019/04/02 Python
基于Numpy.convolve使用Python实现滑动平均滤波的思路详解
2019/05/16 Python
Python numpy线性代数用法实例解析
2019/11/15 Python
使用Python实现 学生学籍管理系统
2019/11/26 Python
css3中background新增的4个新的相关属性用法介绍
2013/09/26 HTML / CSS
html5 canvas实现给图片添加平铺水印
2019/08/20 HTML / CSS
html5跳转小程序wx-open-launch-weapp踩坑
2020/12/02 HTML / CSS
东方电视购物:东方CJ
2016/10/12 全球购物
英国折扣零售连锁店:QD Stores
2018/12/08 全球购物
一些Unix笔试题和面试题
2012/09/25 面试题
2014年营销工作总结
2014/11/22 职场文书
怎样做好公众演讲能力?
2019/08/28 职场文书
解决SpringBoot跨域的三种方式
2021/06/26 Java/Android