第一章:加载和执行

1.1脚本位置

将js脚本放在body底部

1.2组织脚本

文件合并,减少http请求(打包工具)

1.3无阻塞的脚本

js倾向于阻止浏览器的某些处理过程,如http请求和用户界面更新,这是所有开发者面临的最显著的性能问题。

尽管下载单个较大的js文件只产生一次http请求,却会死锁浏览器一大段时间。为避免这种情况,你需要向页面中逐步加载js文件,这样做在某种程度上来说不会阻塞浏览器。

无阻塞脚本的秘诀在于,在页面加载完成后才加载js代码。用专业术语来说,这意味着在window对象的load事件触发后再下载脚本。有很多方式可以做到这一点。

1.3.1延迟的脚本

HTML4为<script>标签添加了defer属性(部分浏览器支持),该属性指明本元素所含脚本不会修改DOM,因此代码能够安全地延迟执行。

1.3.2动态脚本元素

动态加载js文件,无论在何时启动下载,文件的下载和执行过程不会阻塞页面其他进程。

使用动态脚本节点下载文件时,返回的代码通常会立即执行。当脚本“自执行”时,这种机制运行正常。但是当代码只包含供页面其他脚本调用的接口时,你必须跟踪并确保脚本下载完成并准备就绪。可以通过侦听此事件来获得脚本加载完成时的状态:

function loadScript(url ,callback){
var script = documment.creatElement("script")
script.type = "text/javascript"; if(script.readystatechange = function(){//IE
script.onreadystatechange = function(){
if(script.readystate == "load' || script.readystate == "complete"){
script.onraedystatechange = null;
callback();
}
};
}else{//其它浏览器
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}

如果需要动态加载多个js文件,则需确保文件加载的顺序。在所有的主流浏览器中,只有firefox和opera能够按照开发人员指定的顺序执行,其他浏览器会按照从服务端还回的顺序下载和执行代码。你可以将下载操作串联起来以确保下载顺序,如

loadScript("file1.js",function(){
loadScript("file2.js,function(){
loadScript("file3.js,function(){
loadScript("file4.js,function(){
alert("All files are loaded!")
});
});
});
});

尽管方案可行,但如果需要下载的文件较多,这个方案会带来管理上的麻烦。

如果多个文件下载顺序很重要,更好的做法是把它们按照正确顺序写成一个文件(由于这个过程是异步的,因此大一点的文件不会有影响)。

1.3.3XMLHttpRequest脚本注入

此技术会先创建一个XHR对象,然后用它下载js文件,最后通过动态创建<script>元素将代码注入页面中。

1.3.4推荐的无阻塞模式

先添加动态加载所需的代码,然后加载初始化页面所需的剩下的代码。

第二章 数据访问

js的四种基本数据存取位置

直接量

直接量只代表自身,不存储在特定的位置。有字符串、数字、布尔值、对象、数组、函数、正则表达式以及特殊的null和undefined。

变量

开发人员用关键字var定义的数据储存单元。

数组元素

储存在js数组对象内部,以数字作为索引。

对象成员

储存在js对像内部,以字符串作为索引。

大多数情况下,从一个直接量和一个局部变量中存取数据比访问数组元素和对象成员的代价小些。

2.1管理作用域

2.1.1作用域链和标识符解析

function对象的内部属性[[Scope]]包含了一个函数被创建的作用域中对像的集合,这个集合被称为函数的作用域链。

2.1.2标识符解析的性能

标识符解析是有代价的,事实上没有哪种计算机操作可以不产生性能开销。在运行期上下文的作用域中,一个标识符所在的位置越深,它的读写速度也就越慢。

一个好的经验法则:如果某个跨作用域的值在函数中被引用一次以上,那么就把它存储到局部变量中。

2.1.3改变作用域链

一般来说,一个运行期上下文的作用域链是不会改变的。但是,有两个语句可以在执行时临时改变作用域链——with和catch子句。

with包含了参数指定对象的所有属性,这个对象被推入所用作用域链的头部,这意味这所有局部变量第二个作用域链对象中,因此访问的代价更高。

把一个异常对象推入一个可变对象并置于作用域的头部。一旦catch子句执行完毕,作用域链就会返回到之前的状态。

2.1.4动态作用域

2.1.5闭包、作用域和内存

因为闭包的[[Scope]]属性包含了与运行上下文作用域链相同的对象的引用,因此会有一项副作用。通常来说,函数的活动对象,会随同运行期上下文一同销毁。但引入闭包时,由于引用仍然存在于闭包的[[Scope]]属性中,因此激活对象无法被销毁。这意味着脚本中的闭包与非闭包相比,需要更多的内存开销。在大幸Web应用中,这可能是个问题,尤其在IE浏览器中需要关注。由于IE使用非原生js对象来实现DOM对象,因此闭包会导致内存泄漏。

2.2对象成员

2.2.1原型

js中的对象是基于原型的。原型是其他对象的基础,定义并实现了一个新对象必须包含的成员列表。这一概念完全不同于传统面向对象编程语言中“类”的概念,“类”定义了创建新对象的过程。而原型对象为所有对象实例共享,因此这些实例也共享了原型对象的成员。

对象可以有两种成员类型:实例成员和原型成员。

可以用hasOwnProperty()方法来判断对象是否包含特定的实例成员,用in操作符来确定对象是否包含特定的属性。

2.2.2原型链

对象的原型决定了实例的类型。默认情况下,所有对象都是对象(Object)的实例,并继承了所有基本方法。

2.2.3嵌套成员

2.2.4缓存对象成员值

由于所有类似的性能问题都与对象成员有关,因此应该尽可能避免使用它们。更确切地说,应当小心,只有在必要时使用对象成员。

如:

function hasEitherClass(element,className1,className2){
return element.className == className1 ||
element.className == className2;
}

换成

function hasEitherClass(element,className1,className2){
var currentClassName = element.className;
renturn currentClassName == className1 ||
currentClassName ==className2;
}

js的命名空间是导致频繁访问嵌套属性的起因之一,不要再同一个函数里多次查找同一个对象成员,除非它的值改变了。

第3章 DOM编程

用脚本进行DOM操作的代价很昂贵,它是富Web应用中最常见的性能瓶颈。

三类

1.访问和修改DOM元素

2.修改DOM元素的样式会导致重绘(repaint)和重排(reflow)

3.通过DOM事件处理与用户的交互

3.1浏览器中的DOM

DOM与js是两个相互独立的功能,它们通过接口彼此连接,就会产生消耗。

3.2DOM访问与修改

修改元素会更为昂贵,因为它会导致浏览器重新计算页面的几何变化。

3.2.1innerHTML对比DOM方法

最终选择哪种方式取决于你的用户经常使用的浏览器,以及编码习惯。

3.2.2节点克隆

3.2.3HTML集合

HTML集合是包含了DOM节点引用的类数组对象。

读取一个集合的length比读取普通数组的length要慢很多,因为每次都要重新查询。

高性能JS(读书札记)的更多相关文章

  1. js读书笔记

    js读书笔记 基本类型的基本函数总结 1. Boolean() 数据类型 转换为true的值 转换为false的值 Boolean true false String 任何非空字符串 "&q ...

  2. 《高性能js》读书笔记

    第一章:加载和执行 .浏览器的JavaScript的引擎是编译器层的优化: .当浏览器执行JavaScript代码时,不能同时做其他任何事情(单一进程),意味着 .主流浏览器都允许并行下载JS. .减 ...

  3. 高性能JavaScript读书笔记

    零.组织结构 根据引言,作者将全书划分为四个部分: 一.页面加载js的最佳方式(开发前准备) 二.改善js代码的编程技巧(开发中) 三.构建与部署(发布) 四.发布后性能检测与问题追踪(线上问题优化) ...

  4. 高性能 js -- 无阻塞加载脚本

    参考: <<高性能JavaScript>> Nicbolas C. Zakas 著 javascript代码的下载和执行过程会阻塞浏览器的其他进程, 比如页面的绘制, 遇到&l ...

  5. d3.js读书笔记-1

    d3.js入门 d3入门 D3是一个强大的数据可视化工具,它是基于Javascript库的,用于创建数据可视化图形.在生成可视化图形的过程中,需要以下几步: 把数据加载到浏览器的内存空间: 把数据绑定 ...

  6. JS读书心得:《JavaScript框架设计》——第12章 异步处理

    一.何为异步   执行任务的过程可以被分为发起和执行两个部分. 同步执行模式:任务发起后必须等待直到任务执行完成并返回结果后,才会执行下一个任务. 异步执行模式:任务发起后不等待任务执行完成,而是马上 ...

  7. 高性能JS笔记3——DOM编程

    一.访问与修改DOM DOM和JS 相当于两个岛屿,访问操作的次数越多,要交的过路费越多,对性能产生很大影响. 减少访问DOM的次数,把运算尽量留在JS端操作. 二.innerHTML 对比 DOM ...

  8. 了不起的Node.js读书笔记

    原文摘自我的前端博客,欢迎大家来访问 http://www.hacke2.cn 第二章 Js概览 基于GoogleV8引擎 Object.keys(o) 数组方法:遍历forEach.过滤filter ...

  9. 高性能JS笔记1——加载执行

    一.脚本位置 1.Script标签尽可能放到Body底部,以减少脚本文件下载对整个页面UI渲染的影响. 2.Script标签永远不要紧跟Link标签后面. 二.组织脚本 1.合并多个文件在一个Scri ...

随机推荐

  1. 正则表达式regex(golang版)

    代码: //File: main.go package main import ( "fmt" "regexp" ) func main() { r := re ...

  2. Java 通过地址获取经纬度 - 高德地图

    一.添加依赖 <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-v ...

  3. [LeetCode]2. 两数相加

    题目链接:https://leetcode-cn.com/problems/add-two-numbers/ 题目描述: 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 ...

  4. 山东省网络安全技能大赛 部分writeup

    web1 提示:ip不在范围内 直接抓包加client-ip: 127.0.0.1 即可得到flag web2 <?php include 'here.php';    $key = 'kela ...

  5. 数据采集工具Telegraf:简介及安装

    接着上一篇博客:InfluxDB简介及安装,这篇博客介绍下Linux环境下Telegraf安装以及其功能特点... 官网地址:influxdata 官方文档:telegraf文档 环境:CentOS7 ...

  6. UOJ143 万圣节的数列 构造

    传送门 做过这道题,然后这道题告诉你怎么构造数据-- 一种可行的构造方式是:将奇数和偶数分成两半,奇数放在偶数前面,然后除以2,再递归下去处理. 构造的正确性是显然的:如果存在"奇数偶数奇数 ...

  7. LightGBM大战XGBoost,谁将夺得桂冠?

    引 言 如果你是一个机器学习社区的活跃成员,你一定知道 提升机器(Boosting Machine)以及它们的能力.提升机器从AdaBoost发展到目前最流行的XGBoost.XGBoost实际上已经 ...

  8. docker 在centos6 和centos7上的区别

    这些天研究了下docker,在centos6.6上装了个docker1.7.1,在centos7.6上装了个docker18.09.0 两者还是有区别的. 1.配置docker国内镜像加速  Dock ...

  9. Centos7修改时区

    设置时区同样, 在 CentOS 7 中, 引入了一个叫 timedatectl 的设置设置程序. 用法很简单: # timedatectl # 查看系统时间方面的各种状态 Local time: 四 ...

  10. vhdl 数据类型转换 使用IEEE标准库numeric_std 需要进行两次转换 use ieee.numeric_std.all;

    use ieee.numeric_std.all;