# 高性能javascript
# 浏览器在代码执行的过程中遇到script标签都会阻塞浏览器执行
- 位置:script代码*合放置于body结束标签前,确保页面渲染之后再执行脚本,不会导致长时间空白屏
- 合并:合并脚本,减少script标签,不管是外链还是内嵌脚本
- 下载方式:优化script代码无非就是保证script最后执行,无阻塞执行
- script标签使用defer属性
- 动态创建script标签
 
  function loadScript(url, script) {
    var script=document.createElement('script')
    script.type="text/javascript";
    if(script.readyState){ // IE
      script.onreadystatechange = function () {
      if (script.readyState === "loaded" || script.readyState === "complete") {
        script.onreadstatechange = null;
        callback();
      } else { // 其他浏览器
          script.onload = function () {
            callback();
          }
      }
      script.src = url
      document.getElementsByTagName("body")[0].appendClid(script)
      }
    }
  }
- xhr对象执行下载javascript注入到页面中
# 常用的延时加载库
- YUI3
- LazyLoad
- LABjs
# 对象的优化
- 访问字面量和变量比访问对象和对象成员要快
- 经常定义局部变量,作用域链位置越深,访问所需的时间更长
- 属性和方法原型的位置越深,访问的时间越长
- 一般来说,常访问的变量将一个局部变量来保存,可以提高访问速度
# Dom节点优化
- 减少 - dom节点的访问次数- innerHTML(常用)
- cloneNode(克隆方法)
 
- 多次访问某个 - dom节点,使用局部变量来存储
- html集合会实时连接着底层文档,将集合长度缓存在一个变量中,如果经常使用该集合,可以转成数组来使用,使用数组比使用集合要快N倍 
- 披露修改 - dom节点时,需将元素脱离文档流,处理- dom元素之后,再带回文档中
# 脱离文档流方法
- 隐藏元素,引用修改,重新显示,使用display
  var ul = document.getElementById('list');
  ul.style.display="none"
  appendDataToElement(ul, data) // 更新节点通用函数
  ul.style.display="block"
*使用文档片段document.createDocumentFragment来操作(最优)
  var fragment = document.createDocumentFragment()
  appendDataToElement(fragment, data) // 更新节点通用函数
  document.getElement('list').appendChild(fragment)
- 先克隆元素,在处理
  var old=document.getElementById('list')
  var clone = old.cloneNode(true)
  appendDataToElement(fragment, data) // 更新节点通用函数
  old.parentNode.replace(clone, old)
- 常用的方法
| 属性名 | 被代替的属性名 | 
|---|---|
| children | childNodes | 
| childElementCount | childNodes.length | 
| firstElementChild | firstChild | 
| lastElementChild | lastChild | 
| nextElementSibling | nextSibling | 
| previousElementSibling | previousSibling | 
- 动画使用绝对定位,使用拖放代理
- 使用事件委托减少事件处理器的数量
# JS的算法和流程控制
- 使用 - for,- while, 和- do-while循环性能特性相当,但避免使用- for-in循环,除非需要遍历一个属性未知的对象, 函数的迭代- forEach,- map性能比原始的for循环
- 使用查找表比 - if-else和- switch更快
// 返回值集合存入数组
var results = [result0, result1, result2]
// 返回当前的结果
return results[value]
- 递归:函数通过自身反复的调用,或者两个函数之间反复的调用达到循环的目的。递归会有栈溢出的风险 - 迭代(遍历):递归的实现算法都可以用迭代来实现,通过循环来实现 
提示
如果由于使用递归算法导致栈溢出,可以考虑使用迭代算法或者memoization来避免重复计算
# 字符串和正则表达式
- 如果考虑ie7以及更早的版本的话,可以使用数组合并,再转成字符串。不考虑的话使用简单的+和+=操作符来替代
- 回溯既是正则表达式匹配功能的基本组成部分,也是正则表达式的低效之源,回溯失控发生于正则表达式原本能快速匹配的地方,由于某些特殊字符导致运行缓慢甚至浏览器奔溃
# 避免该问题的发生
- 使用相邻的字元互斥
- 避免量词对同一字符串的相同部分多次匹配
- 通过服用利用预查的原子组去除不必要的回溯
# js代码编程实战
- 避免双重求值, 因为通过动态执行字符串时,会自动创建一个新的解析器实例,来执行这字符串 动态执行字符串中的js方法: - eval() - eval('num1+num2')
- function()构造器 - new Function('num1','num2', 'return num1+num2' )
- setTimeout - setTimeout('num1+num2', 25)
- setTimeInterval - setTimeInterval('num1+num2', 25)
 
- 避免重复工作 需要检测浏览器时,可以使用延迟加载或条件预加载 
function addHandler(target, eventType, handler) {
    if (target.addEventListener) {
        target.addEventListener(eventType, handle, false)
    } else { // IE
      target.attactEvent('on' + eventType, handler)
    }
}
# 解决办法
- 延迟加载: 第一次调用时,先检查一下并决定使用那个方法,然后原始函数会被正确的函数覆盖 - function addHandler(target, eventType, handler) { if (target.addEventListener) { addHandler = target.addEventListener(eventType, handle, false) } else { // IE addHandler = target.attactEvent('on' + eventType, handler) } // 调用新函数,并且覆盖 addHandler(target, eventType, handler) }- 条件预加载: 在脚本加载时直接提前检测,不会等到调用时再检测
 - var addHandle = document.body.addEventListener ? function addHandler(target, eventType, handler) { target.addEventListener(eventType, handle, false) } : function addHandler(target, eventType, handler) { // IEtarget.attactEvent('on' + eventType, handler) }
- 尽量使用直接量创建对象或数组,直接量比非直接量的形式要快 
- 数学计算时,考虑使用操作数字的二进制形式的位运算 (opens new window) 
- 尽量用js中的原生方法,比如Math方法 
# 书籍

