这篇笔记的内容主要涉及js的脚本位置,如何加载js脚本和脚本文件执行的问题,按照自己的理解结合高性能JavaScript整理出来的

javascript是解释性代码,解释性代码需要经历转化成计算机指令的过程,这个过程就会带来一定的性能损耗,所以在js中做性能的优化是必须的

javascript的阻塞特性:浏览器在执行js代码的时候,不能做其他的任何事情,因为浏览器使用单一的进程来处理用户界面的刷新和javascript的脚本执行,也就是说什么时候执行js脚本影响着用户对页面的使用体验(之所以js会阻塞页面的解析和渲染,是因为无法预期js时候会对页面进行修改,所以会先执行完js代码在继续解析和渲染界面,无论是外链的js文件或者是内联的js文件的)

基于以上的原因,js文件位置决定这用户的体验并且通过js文件的优化能尽可能的提高页面的性能

<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>

上面这种模式我们将js文件放置在head中,这样的位置是存在问题的

(1)首先js的阻塞特性会导致必须等待这两个文件下载和执行,页面才会渲染,会出现空白,用户体验不好

(2)浏览器在解析body标签之前不会渲染页面的任何部分,也就是在a.js  和 b.js 在执行的过程中不存在页面的dom树,这个时候对页面进行操作就会出错

/*虽然现代的浏览器可以实现js的并行下载,但是js的下载过程中还是会阻塞其他资源的下载,例如图片等 外链的CSS文件本身已经是并行下载的*/

所以推荐的js脚本放置位置是下面这样的形式

<body>

<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
</body>

这样的放置模式在下载脚本文件和执行脚本文件的时候,页面的大部分内容已经显示给用户,也就是放置在body的最底部

组织脚本

script标签会阻塞页面的渲染,从提高页面的性能的角度考虑,就是如何尽可能的减少script标签去组织脚本,由于现在js文件的模块化和功能化越来越清晰,文件的数量有的时候很难去实质的减少,一个并不是特别好的方案,就是简单的合并两个js文件,因为减少了http请求这样的方式会比单纯的下载两个之前独立的js文件要快,但是这样也存在一定的问题

(1)破坏了js文件的模块性,两个不同功能的模块糅合在一起了

(2)在服务端我们需要增加更多的js文件,占据着服务器的资源

我们可以通过一些静态打包工具或者类似雅虎提供的合并处理器通过它们的CDN来实现一个url来加载两个js文件

/*不要将内联脚本放置在外链样式表的后面,这样会导致页面阻塞去等待样式表去下载(为了在js文件执行的时候获取到最精准的样式信息)*/

无阻塞脚本

通过上面合并url或者合并js文件并不能很好地提高的页面的性能,所以提出了无阻塞脚本,就是在页面加载完成后才加载js代码,也就是在相应window.onload事件触发后才去下载脚本(仔细理解无阻塞脚本就是这个js文件的下载不会阻塞页面其他元素的下载) 有几种方式可以实现上面的要求

(1)延时脚本defer

defer属性在js文件不会修改文档的时候可以使用,因为js文件不会修改文档,就不需要等待js的执行去停止页面的渲染 等待页面完成后执行(无位置需求)

ansyc 属性 js文件下载完成后自动执行(body底部 下载执行的时候需要页面的元素准备完毕)

可以通过上面这两种方式实现无阻塞脚本

举一个defer的例子

/*我测试了chrome下和IE下都支持了defer属性 但是当js文件是内联的时候 defer就会失效 */

<body>
<script type="text/javascript" src="a.js" defer></script>
<script type="text/javascript" defer>
console.log(1);
</script>
<input type="button" value="test" id="btn" /> </body>

a.js中的内容如下

var btn = document.getElementById("btn");
console.log(btn);

通过查看控制台我们发现a.js的确延时执行了,也就是在页面window.load 之前执行了a.js文件 但是内联的js的文件并没有延时

(2)动态脚本元素 script元素与其他元素一样可以动态的创建script元素,并且这种方式文件下载和执行的过程不会阻塞其他的进程,并且这种方式添加的脚本文件会在下载完成后立即执行,但是当你添加的这个脚本是一个提供接口的脚本的时候就需要获取一些信息来确认当前这个接口是否可以然后在进行后面的操作 IE下可以通过onreadystatechange事件 通过script的readyState状态来获取脚本完成时的状态 标准浏览器是通过onload事件来判断添加的js文件的状态

可以通过下面这个函数来实现动态的加载js文件

  function loadScript(url,callback) {
var script = document.createElement("script");
script.type = "text/javascript";
if(script.readyState) {
script.onreadystatechange = function(){
if(script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null;
callback();
}
}
} else {
window.onload = function() {
callback();
}
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script); /*添加到页面的时候开始下载,下载的过程执行都不会阻塞其他进程*/
console.log(1);/*1会在新添加的script执行前输出*/
}

如果需要脚本之间按照特定的顺序下载执行可以按照回调的方式一个一个的加载js文件

  loadScript("a.js",function(){
loadScript("b.js",function(){});
});

(3)XMLHttpRequest脚本注入  也就是通过xhr对象去下载脚本文件 这种情况的优势是你可以下载到代码但不立即执行,等到你准备好的时候在去执行相应的代码

  var xhr = new XMLHttpRequest();
xhr.open("get","a.js",true); /*true表示异步*/
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
var script = document.createElement("script");
script.type = "text/javascript";
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
}
xhr.send(null);

推荐的方式:  通过阻塞的方式加载一小部分代码,例如loadSript 然后在去动态的加载剩余的代码

<script type="text/javascript" src="load.js"></script>
<script type="text/javascript">
loadScript("b.js",function(){
console.log("OK");
});
</script>

参考高性能javascript

高性能javascript学习笔记系列(1) -js的加载和执行的更多相关文章

  1. 高性能javascript学习笔记系列(6) -ajax

    参考 高性能javascript javascript高级程序设计 ajax基础  ajax技术的核心是XMLHttpRequest对象(XHR),通过XHR我们就可以实现无需刷新页面就能从服务器端读 ...

  2. 高性能javascript学习笔记系列(5) -快速响应的用户界面和编程实践

    参考高性能javascript 理解浏览器UI线程  用于执行javascript和更新用户界面的进程通常被称为浏览器UI线程  UI线程的工作机制可以理解为一个简单的队列系统,队列中的任务按顺序执行 ...

  3. 高性能javascript学习笔记系列(4) -算法和流程控制

    参考高性能javascript for in 循环  使用它可以遍历对象的属性名,但是每次的操作都会搜索实例或者原型的属性 导致使用for in 进行遍历会产生更多的开销 书中提到不要使用for in ...

  4. 高性能javascript学习笔记系列(2)-数据存取

    参考 高性能javascript Tom大叔深入理解javascript系列 相关概念 1.执行上下文   当控制器转到ecmascript可执行代码的时候,就会进入一个执行上下文,执行上下文是以堆栈 ...

  5. 高性能javascript学习笔记系列(3) -DOM编程

    参考 高性能javascript 文档对象模型(DOM)是独立于语言的,用于操作XML和HTML文档的程序接口API,在浏览器中主要通过DOM提供的API与HTML进行交互,浏览器通常会把DOM和ja ...

  6. JS 动态加载脚本 执行回调

    JS 动态加载脚本  执行回调 关于在javascript里面加载其它的js文件的问题可能很多人都遇到过,但很多朋友可能并不知道怎么判断我们要加载的js文件是否加载完成,如果没有加载完成我们就调用文件 ...

  7. JS的加载和执行

    从JS的加载和执行谈性能优化 ---高性能JS读后感(第一章) 从脚本的"霸道"说起,随着浏览器的进步,js越来越听话了,所以,我们先说说以前的浏览器是怎么加载js的,以及js如何 ...

  8. 性能优化-css,js的加载与执行

    前端性能优化 css,js的加载与执行 javascript是单线程的 一个网站在浏览器是如何进行渲染的呢? html页面加载渲染的过程 html渲染过程的一些特点 顺序执行,并发加载 词法分析 并发 ...

  9. selenium学习笔记——driver.get(url) 页面加载时间太长

    # 两个同时设置才行 # 实现效果:加载状态停止,进行代码下一步操作 driver.set_page_load_timeout(10) driver.set_script_timeout(10) # ...

随机推荐

  1. 【转】Windows Phone在隔离存储里存取图片文件

    一共两个页面,第一个为MainPage.xaml,代码如下: <!--ContentPanel - place additional content here--> <Grid x: ...

  2. jQuery插件之ajaxFileUpload

    原文:http://www.cnblogs.com/kissdodog/archive/2012/12/15/2819025.html ajaxFileUpload是一个异步上传文件的jQuery插件 ...

  3. 通过zero copy来实现高效的数据传输

    这段时间在学习一些系统底层的知识,真后悔大学没有好好学习操作系统,导致好多文章看不懂.说到这不得不吐槽一下,像介绍系统层次的一些书籍好多都是中文翻译版,而大部分的中文翻译版大都语句晦涩,难懂,而且极易 ...

  4. ReflectionHelper

    public static T GetInstance<T>(Assembly assembly, string fullNamespace) { return (T)assembly.C ...

  5. C++二维码相关库编译

    一.瞎想 坐在地铁上闲来无聊,突然想到了二维码,顺手就百度了下相关的资料,目前C++二维码相关的库不多,也就zbar(开源中国上下了半天也没下载下来).zxing,不过这两个库据说都是解析二维码的,不 ...

  6. Eclipse窗口总是在最前的解决办法

    Eclipse窗口总是在最前的解决办法 状况: Eclipse在偶然的情况下,会莫名其妙地保持在窗口的最前面,一直保持在最前:然后alt + tab,或者鼠标点击其他窗口.想切换/激活其他窗口时,根本 ...

  7. Javascript 布尔操作符总结

    在一门编程语言中,布尔操作符的重要性堪比相等操作符.如果没有测试两个值关系的能力,那么诸如if...else和循环之类的语句就不会有用武之地了.在像javascript这样弱类型语言更有其妙用,让我们 ...

  8. js中局部变量必须用var去声明

    js中的变量与其他的脚本语言都是很不一样的,在function中你如果不用var 声明一个变量,那么这个变量将在全局可见,也就相当于创建了全局变量.所以在function中声明变量尽量都是用var来声 ...

  9. C++宏和枚举

    宏 我们的计算器程序,用1234对应加减乘除,对于人阅读很产生一点障碍.隔一个月后再看此代码可能想不起是0123还是1234了,还得去代码中查找,如果能为代表四则运算的四个数取个有意义的别名就好了,一 ...

  10. SEO技巧汇集

    每个人都喜欢好用的技巧,对吗?这里有55个用于搜索引擎优化的小技巧,甚至你的老妈用起来都易如反掌.哦,不是我的老妈,但你明白我的意思.这意味着网页设计师和SEO新手中大部分人都能迅速上手,没有任何困难 ...