javascript无阻塞加载脚本
javascript无阻塞加载脚本
1 脚本阻塞并行下载
行内脚本通过script标签引入整段javascript:
1
2
3
4
5
function displayMessage(msg){ alert(msg);
}
外部脚本通过script的src属性把独立文件中的JavaScript引入:
src属性定义了需加载的外部URL,如果缓存中有脚本文件,浏览器就从缓存中读取,否则就发送HTTP请求获取。
浏览器在下载和执行脚本时出现阻塞的原因:1 document.write改变了页面 2 其中一个js依赖于另一个js(浏览器要确保要确保脚本在HTML文档中出现的顺序来执行;否则可能会出现竞争状态;可以按顺序执行,但不一定要按顺序下载)。
2 更好的运行脚本
方案:1 把所有javascript内嵌到页面中(少量是可以的;由于通常页面大小和缓存能带来更多好处,因此推荐外部引入javascript)
下面这些技术既可以避免因阻塞导致的减速影响,由拥有脚本的好处(可以并行运行脚本)。
(1)XHR Eval。
(2)XHR注入(XHR Injection)。
(3)Script in Iframe。
(4)Script Dom Element。
(5)Script Defer。
(6)document.write Script Tag。
XHR Eval (XMLHttpRequest(XHR)从服务端获取脚本;当响应完成时,通过eval命令执行内容)
缺点:通过MLHttpRequest获取的脚本必须部署在和主页面相同的域中。以下是XH Eval相关代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var xhrObj = getXHRObject();
xhrObj.onreadystatechange =
function(){
if ( xhrObj.readyState == 4 && 200 == xhrObj.status ){ eval (xhrObj.responseText); }
};
xhrObj.open("GET", 'A.js', true);//必须和主页面在·同一个域中
xhrObj.send("");
function getXHRObject() {
var xhrObj = false; try{ xhrObj = new XMLHttpRequest(); } catch(e){ var progid = ["MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"]; for( var i = 0;i< progid.length; ++i){ try{ xhrObj = new ActiveXObject(progid[i]); } catch(e){ continue; } break; } } finally { return xhrObj; }
}
XHR注入(通过创建一个script的DOM元素,然后把XMLHttpRequest的响应注入script中执行javascript;通过XMLHttpRequest获取的内容必须部署在和主页面相同的域中。)XHRInjection代码如下:
1
2
3
4
5
6
7
8
9
10
11
var xhrObj = getXHRObject();
xhrObj.onreadystatechange =
function (){
if (xhrObj.readyState == 4 ){ var scriptElem = document.createElement("script"); document.getElementsByTagName('head')[0].appendChild(scriptElem); scriptElem.text = xhrObj.responseText; }
};
xhrObj.open ('GET', 'a.JS', true);
xhrObj.send('');
Script in Iframe
iframe URL和主页面同域。即使主页面同域,我们任然要修改javascript来创建他们之间的关联。
方案一:
//使用“frames”访问主页面上的iframe
window.frames[0].createNewDiv();
//使用“getElementById”访问主页面上的iframe
document.getElementById('frame').contentWindow.createNewDiv();
方案二:
//ifame使用parent变量引用父页面:
//在iframe中使用“parent”访问主页面
function createNewDiv(){
var newDiv = parent.document.createElemnent('div');
parent.document.body.appendChild(newDiv);
}
//iframe自身的消耗比较高
Script Dom Element
相对于在HTML中使用script标签下载脚本文件而言,该技术使用JavaScript动态地创建script DOM 元素并设置src属性,这只要两三行javascript代码就可以实现。
var scriptElem = document.createElement('script');
scriptElem.src = 'http://anydomain.com/A.js' ;
document.getElementByTagName('head')[0].appendChild(scriptElem);
//这种方式下载脚本不会阻塞其它组件。允许跨域获取脚本。外部脚本可以直接调用。
//script DOM Element http://stevesouders.com/cuzillin/?ex=10010&title=Script+Dom+Element
,浏览器还有ScriptnDefer以及document.write ScriptTag 我这里就不一一介绍了。
3、浏览器忙指示器
浏览器忙指示器,让用户感知到页面还在加载。浏览器忙指示器包括:状态栏、进度条、标签页图标和光标。
另外两个浏览器忙指示器是组赛渲染和阻塞onload事件。缺点:当使用SCRIPT SRC技术下载脚本时,浏览器停止渲染所有脚本后面的内容。通常页面的onload事件要等到所有页面下载完时才会触发。如果让状态栏等待更长时间,才显示“完成”,并且默认输入框取焦点,影响用户体验。(忙指示器是否出发,是所使用的技术和浏览器共同决定的)
4、确保(或避免)按顺序执行
很多网页都包含多个有特定依赖顺序的脚本,它们会按照到达的顺序执行——最先到达,最先执行。这会导致竞争状态,进而导致未定义标识符错误。要想是浏览器按照顺序执行,而不是加载的顺序执行,可以使用Script Defer 和document.write ScriptTag保证脚本按照顺序执行。
(脚本按照特定顺序执行并非总那么重要,有时候按照加载的顺序执行,可以快速的渲染页面。)
不推荐使用document.write Script Tag技术。因为它只在部分浏览器中实现并行下载,而且还阻塞脚本之外所有其它资源的下载。Script Defer技术也只在部分浏览器中实现了并行下载。
当脚本与主页面同域时,XHR Eval 、XHR 注入和Script in Iframe可以满足需求。但如果使用XHR Eval 或Script in Iframe技术,我们需要重构一部分脚本,而XHR注入和Script DOM Element技术可以直接使用现有的脚本文件,无需任何改动。
5、最佳方案
根据项目需求·合理选择最佳的技术。有下面六种情况:
有不同域、无序
不同域,保持顺序
同域、无序、无忙指示器
同域、无序、有忙指示器
同域、保持顺序、无忙指示器
同域、保持顺序、由忙治时期
开发者可以通过该函数来确保按最佳方案加载脚本,原理如下:
function loadScript(url, bPreserverOrder, bShowBusy);
原文地址https://www.cnblogs.com/yaosusu/p/11275507.html
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
JVM的GC日志
查看jvm默认gc收集器 cmd执行命令: java -XX:+PrintCommandLineFlags -version gc类型 GC日志查看 可以通过在java命令种加入参数来指定对应的gc类型,打印gc日志信息并输出至文件等策略。GC的日志是以替换的方式(>)写入的,而不是追加(>>),如果下次写入到同一个文件中的话,以前的GC内容会被清空。 -XX:+PrintGCDetails 输出GC的详细日志 -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式) -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800) -XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息 -Xloggc:../logs/gc.log 日志文件的输出路径 这里使用如下的参数来进行日志的打印: 对于新生代回收的一行日志,其基本内容如下: 2014-07-18T16:02:17.606+0800: 611.633: [GC 611.633: [DefNew: ...
- 下一篇
设计模式及python实现
设计模式及python实现Christopher Alexander:“每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样你就能一次又一次地使用该方案而不必做重复劳动。” 设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码。反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言。一个好的设计模式应该能够用大部分编程语言实现(如果做不到全部的话,具体取决于语言特性)。最为重要的是,设计模式也是一把双刃剑,如果设计模式被用在不恰当的情形下将会造成灾难,进而带来无穷的麻烦。然而如果设计模式在正确的时间被用在正确地地方,它将是你的救星。 起初,你会认为“模式”就是为了解决一类特定问题而特别想出来的明智之举。说的没错,看起来的确是通过很多人一起工作,从不同的角度看待问题进而形成的一个最通用、最灵活的解决方案。也许这些问题你曾经见过或是曾经解决过,但是你的解决方案很可能没有模式这么完备。 虽然被称为“设计模式”,但是它们同“设计“领域并非...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Linux系统CentOS6、CentOS7手动修改IP地址
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- CentOS7,CentOS8安装Elasticsearch6.8.6
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS6,CentOS7官方镜像安装Oracle11G
- Windows10,CentOS7,CentOS8安装Nodejs环境