参考高性能javascript

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

<button onclick="handleClick()">click</button>
<script type="text/javascript">
function handleClick() {
var div = document.createElement('div');
div.innerHTML = "aaa";
document.body.appendChild(div);
}

在上面的例子中当按钮被点击的时候,它触发UI线程创建的两个任务并且添加到队列中,更新被点击按钮的UI和执行javascript代码(handleClick) 假如此刻队列是空闲的(也就数存在用户操作无法添加到队列的情况) 第一个任务会立即被执行然后javascript代码被提取出来并且执行,在执行javascript代码的过程中创建了一个div,当js运行完,又触发了另一次的UI更新(显示创建的DIV)

由于js脚本运行时间的长短会导致新创建的任务无法被加入队列,所以有必要对脚本的执行时间进行限制或者在脚本执行的过程中让出一会浏览器的UI线程让新的任务添加到队列

理解定时器  参考我之前的一篇blog  定时器相关setTimeout setInterval requestAnimationFrame

通过上面的一些点 定时器可以称为长时间运行脚本的跨浏览器的解决方案

使用定时器取代循环

  • 处理过程是否必须同步
  • 数据是否一定要按顺序处理

如果上面的两个回答都是否,那我们就可以使用定时器来代替循环了

  function processArray(items,process,callback) {
var todo = items.concat();
setTimeout(function(){
process(todo.shift()); if(todo.length > 0) {
setTimeout(arguments.callee,25);
} else {
callback(items);
}
},25);
}

上面的函数接受一个数组项  处理数组项的函数  回调函数    通过自调用的方式能保证队列中不会有缺失的代码片段也保证了代码执行的间隔至少是25ms

上面方式的缺陷是延长了处理数组的总时长(加入了时间间隔) 但是给出了一定时间间隔留给了UI线程,能避免代码长时间运行导致浏览器锁死

改进版的定时器取代循环

  function timedProcessArray(items,process,callback) {
var todo = items.concat(); setTimeout(function(){
var start = +new Date(); // 加号将Date对象转换成数字 do {
process(todo.shift());
} while(todo.length > 0 && (+new Date() - start) < 50) //当前处理的时间间隔短 就不进行循环的分解 if(todo.length > 0) {
setTimeout(arguments.callee,25);
} else {
callback();
}
}); }

分割任务

  将一个任务划分成多个原子任务,使用定时器去执行相应的原子任务,思路跟上面的循环处理数组的思路相同

  function multistep(steps,args,callback) {
var tasks = steps.concat(); setTimeout(function(){
var task = tasks.shift();
task.apply(null,args || []);
if(tasks.length > 0) {
setTimeout(arguments.callee,25)
} else {
callback();
}
},25)
} //这里的args必须是数组 因为我们使用的apply

了解web workers  通过定义一个包含worker代码的文件 通过new Worker("js文件url")就能在网页中创建一个新的线程,它通过特定的方法与主线程进行信息的交互,并且不影响主线程的执行

主线程
var worker = new Worker("worker.js"); //这段代码会异步的下载worker.js 当worker.js下载并执行完成后就启动了这个worker
worker.onmessage = function(event) {
alert(event.data);
} //网页代码接收数据的处理函数
worker.postMessage("hello");//网页代码向worker发送数据 worker.js self.onmessage = function(event) {
self.postMessage(event.data+"world");
} //worker接收网页代码数据的处理函数

只有特定的数据可以通过postMessage传递 例如原始值(字符串 数字 布尔值 null undefined ) 也可以传递Object和Array实例 数据会被序列化出入和传出worker 然后被反序列化

用处: web workers适用于处理纯数据或者与浏览器UI无关的长时间运行的脚本

编程实践

1.避免双重求值

eval()   Function()   setTimeout() setInterval() 允许在程序中提取一个包含代码的字符串,然后动态的的执行它  例如eval("num1 + num2") 这段代码会先对eval进行求值 然后对字符串中的内容进行求值返回结果  应该避免使用eval 和Function()  并且在使用setTimeout  和 setInterval的时候传入函数体

2. 使用object 和 array 直接量

3 避免重复的工作   例如跨浏览器的事件绑定函数

function addListenEvent(eventTarget,eventType,handler) {
if(eventTarget.addEventListener) {
eventTarget.addEventListener(eventType,handler,false);
} else if(eventTarget.attachEvent) {
eventType = "on" + eventType;
eventTarget.attachEvent(eventType,handler);
} else {
eventTarget["on"+eventType] = handler;
}
}

这个方法在每次调用的时候都进行了浏览器的检测,有重复的操作

我们可以通过延时加载和条件预加载的方式去优化这个函数

1延时加载 函数在使用之前不进行任何的操作,在调用后在决定根据情况去改变这个函数的状态 这种方式在第一次运行的时候会消耗较长的时间,适合当一个函数不会被立即调用的情况下使用  使用延时加载改写上面的函数

function addListenEvent(eventTarget,eventType,handler) {
if(eventTarget.addEventListener) {
addListenEvent = function(eventTarget,eventType,handler) {
eventTarget.addEventListener(eventType,handler,false);
}
} else if(eventTarget.attachEvent) {
addListenEvent = function(eventTarget,eventType,handler) {
eventType = "on" + eventType;
eventTarget.attachEvent(eventType,handler);
}
} else {
addListenEvent = function(eventTarget,eventType,handler) {
eventTarget["on"+eventType] = handler;
}
}
}

2条件预加载     这种方式需要在脚本加载的时候就进行检测,适用于一个函数马上就需要被调用并且在整个页面的生命周期被频繁使用的场景

var addListenEvent = document.body.addEventListener ? function(eventTarget,eventType,handler) {
eventTarget.addEventListener(eventType,handler,false);
} : function(eventTarget,eventType,handler) {
eventType = "on" + eventType;
eventTarget.attachEvent(eventType,handler);
};

使用速度快的运算方式

例如在判断奇数偶数的时候 通过与1进行按位与的来代替取余操作能提高性能

使用原生的方法

小记  ~25 = -26

25的二进制形式为   11001  取反的二进制形式为 00110   左边   右边  因为~x+1 = -x 所以右边~26 + 1 = 00110

高性能javascript学习笔记系列(5) -快速响应的用户界面和编程实践的更多相关文章

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

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

  2. 高性能javascript学习笔记系列(1) -js的加载和执行

    这篇笔记的内容主要涉及js的脚本位置,如何加载js脚本和脚本文件执行的问题,按照自己的理解结合高性能JavaScript整理出来的 javascript是解释性代码,解释性代码需要经历转化成计算机指令 ...

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

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

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

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

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

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

  6. JavaScript学习笔记系列2:Dom操作(一)

    一.什么是Dom? DOM------>Document Object Model 直接翻译就是文档对象模型. DOM------>定义了表示和修改文档所需的对象.这些对象的行为和属性以及 ...

  7. 高性能javascript 学习笔记(1)

    加载和运行 管理浏览器中的javascript代码是个棘手的问题,因为代码运行阻塞了其他浏览器处理过程,诸如用户绘制,每次遇到<script>标签,页面必须停下来等待代码下载(如果是外部的 ...

  8. JavaScript学习笔记系列1:JavaScript的是什么?

    一.JS是什么? JavaScript作为Netscape Navigator浏览器的一部分首次出现在1996年.它最初的设计目标是改善网页的用户体验. 作者:Brendan Eich 期初JavaS ...

  9. Dynamic CRM 2013学习笔记 系列汇总

    这里列出所有 Dynamic CRM 2013学习笔记 系列文章,方便大家查阅.有任何建议.意见.需要,欢迎大家提交评论一起讨论. 本文原文地址: Dynamic CRM 2013学习笔记 系列汇总 ...

随机推荐

  1. java线程 公平锁 ReentrantLock(boolean fair)

    一.公平锁 1.为什么有公平锁 CPU在调度线程的时候是在等待队列里随机挑选一个线程,由于这种随机性所以是无法保证线程先到先得的(synchronized控制的锁就是这种非公平锁).但这样就会产生饥饿 ...

  2. KnockoutJS 3.X API 第七章 其他技术(8) 异步错误处理

    注意:本文档适用于Knockout 3.4.0及更高版本. ko.onError Knockout包装内部异步调用,并在抛出原始错误之前查找可选的ko.onError回调以执行(如果遇到异常). 这使 ...

  3. C#设计模式系列:适配器模式(Adapter)

    在实际的软件系统设计和开发中,为了完成某项工作需要购买一个第三方的库来加快开发.这带来一个问题,在应用程序中已经设计好的功能接口,与这个第三方提供的接口不一致.为了使得这些接口不兼容的类可以在一起工作 ...

  4. 手机软件Toast无法显示提示信息

    近日在做项目时,测试组的同事提出一个bug,就是在一台LG手机上,原本应该显示的Toast信息,都不显示,消息栏也没有出现通知,后来经过查资料知道有些三星.LG手机默认禁用了显示通知那一项,而不显示通 ...

  5. 应用程序框架实战三十八:项目示例VS解决方案的创建(一)

    进行项目开发的第一步,是创建出适合自己团队习惯的VS解决方案,虽然我已经提供了项目示例,但毕竟是我创建的,你直接使用可能并不合适,另外你如果尝试模仿重新创建该示例,中间可能碰到各种障碍,特别是项目间的 ...

  6. Expression Template(表达式模板,ET)

    1.前言 在前一篇文章自己实现简单的string类中提到在实现+操作符重载函数时,为了防止返回时生成的临时对象调用拷贝构造函数动态申请内存空间,使用了一个叫move的函数,它是C++0x新增的特性.既 ...

  7. webapp应用---cordova.js 3.7.0插件安装总结

    今天是2014年的最后一天,年终总结什么的就不写了.记录一下今天的工作内容.如果不知道phoneGap,那么就不需要往下看了,phoneGap现在已经叫cordova了,叫什么不重要,重要的是它对we ...

  8. Oracle并行添加主键的方法

    环境:Oracle 11.2.0.3 需求:生产一张表由于前期设计不当,没有主键.现需要添加主键,数据量很大,想并行建立.   1.直接添加,提示ora-3001:未实施的功能;只能单线程建立主键 S ...

  9. 三步将Node应用部署到Heroku上

    Heroku是一个提供快速部署服务的云平台.支持Node,Ruby,Java,PHP,Python,Go多种语言,今天体验了下,简直不要太爽.下面简单的介绍一下. 首先还是要注册一个账号:https: ...

  10. js构建ui的统一异常处理方案(三)

    笔者之前分析了如何实现js的责任链异常处理的方法,通过promise这个异步模型,我们能够对同步方法和异步方法的两种情况,均可以实现责任链模式.有了这些武器,我们就可以开始设计ui的统一异常处理方案了 ...