HTML5触摸界面设计与开发--笔记--javaScript性能优化

来源:互联网 发布:mac破折号 编辑:程序博客网 时间:2024/06/05 21:49

一 : 本文中使用的性能优化策略

1 只写入DOM,因为DOM交互式相当慢的
测试:

  console.time('test');  var test=document.getElementById('index-bn').title ;  console.timeEnd('test');  test: 0.091ms  var cache=['111'];  console.time('test');  var test=cache[0];   console.timeEnd('test');  test: 0.021ms    ```
1.1 显然不可能完全避免从DOM中读取数据,但我们可以使用缓存数据来减少读取的频率,如果你认为会再次使用某个DOM,你可以将它储存在一个变量中。1.2 DOM操作是阻塞的,当一个DOM操作在运行时,其他的什么都不能做。

2 给用户反馈的优先级是最高的
2.1 输出
浏览器中的javaScript是单线程,这意味着同一时间javaScript引擎在同一时间只能做一件事情,这个线程通常被称为UI线程,并行是通过将所有任务推到一个队列中来实现的,队列中的任务会在线程变得空闲时执行,如果一个缓慢的DOM操作在执行,传入的时间必须排队等候,直到DOM操作完成处理,如一个缓慢的DOM读取在执行,此时用户与页面进行交互,那么事件将不会马上被处理。
2.2 延迟执行
如果浏览器正忙着给用户返回,而你需要处理AJAX响应这种成本比较大的操作,你可以延迟执行。

例 –无限滚动

<div id="wrapper"></div><script id="slide" type="text/x-handlebars">    <div class="slide">        <p class="logo"></p>        <div class="imgholder">            <a title="by {{ownername}} on Flickr" target="_blank"             href="http://www.flickr.com/photos/{{owner}}/{{id}}"><img class="img" data-src="{{url_n}}"></a>            <p>{{title}}</p>        </div>    </div></script>

样式

body {  margin: 0;  padding: 0;  text-align: center;}.slide {  width: 300px;  padding: 20px;  margin: 10px auto 10px auto;  height: 250px;  background: #f6f6ed;  position: relative;  text-align: center;}.slide p {  width: 100%;  overflow: hidden;  white-space: nowrap;  text-overflow: ellipsis;  font-family: sans-serif;}.slide .img {  max-width: 100%;  max-height: 210px;  text-align: center;  opacity: 1;  display: inline;  -webkit-transition: opacity 0.25s ease-in-out;  -moz-transition: opacity 0.25s ease-in-out;  -o-transition: opacity 0.25s ease-in-out;  transition: opacity 0.25s ease-in-out;}.imgholder {  width: 100%;  text-align: center;}

无限滚动脚本

function handleScroll(e) {    if(window.scrollY + window.innerHeight + 1000 > document.body.offsetHeight) {        fetchBirds();//请求数据    }    handleDefer();  //判断是否可见} window.addEventListener('scroll', handleScroll);

获取包含很多图片的内容时,当他们被插入到页面中是,浏览器就开始获取图像,这意味着同时下载,浏览器的下载通道被占满,使用户看的图片显示更慢,同时,由于内容先于用户加载,可能下载永远无法被看到的图像,在这里可以使用延迟加载,当图像被看到时才下载加载图像,使页面更快,还可以节省用户的流量。

延迟加载图像

function isVisible(node) {//判断是否可见    //get the dimensions we need    var scrollTop = window.scrollY,        offTop = node.offsetTop,        offsetHeight = node.offsetHeight,        innerHeight = window.innerHeight,        topViewPort = scrollTop,        bottomViewPort = scrollTop + innerHeight;    //figure out if it is in the viewport or not    return offTop + offsetHeight > topViewPort && offTop < bottomViewPort;}function handleDefer() {//可见就加载图片    //find all the slides, I'm fetching the container    //rather than the image because I don't know the image    //heights yet    var list = document.querySelectorAll('.slide');    for (var i=0, len = list.length; i < len; i++) {        thisImg = list[i].querySelector('.img');        if(thisImg.src) {            continue;        }        //if they are visible, update the src        if(isVisible(list[i])) {            var src = thisImg.getAttribute('data-src');            if(src) {                thisImg.src = src;                thisImg.removeAttribute('data-src');            }        }    }}

现在图像使延迟加载的,但加载时会看到图像空白,体验并不是很好,我们可以加上动画效果并优化延迟加载效果

.slide .img{ transition:opacity .25s ease-in-out;}function handleDefer() {    console.time('defer');    var i, list, thisImg, deferSrc, img, handler,    //the slide cache is populated by the function that    //loads the data so that the defer code doesn't need    //to keep querying the dom.    list = slideCache,     len = listLength;    for (i=0; i < len; i++) {        thisImg = list[i].img        var deferSrc = list[i].src;        if(isVisible(list[i].id)) {            //create a closure for for simple preload stuff            handler = function() {                var node, src;                node = thisImg;                src = deferSrc;                return function () {                    node.src = src;                    node.style.opacity = 1;                    loaded[deferSrc] = true;                }            }();            //申明一个image,然后将src赋给改image的src,等待图像下载完成后再讲路径替换(此时图像已经下载到本地了,并使用动画效果显示)            var img = new Image();            img.onload = handler;            img.src = list[i].src;        }    }    console.timeEnd('defer');}

现在加上了动画效果,在感知的性能上的提升是显著的。
可能你已经注意到了,我们是从slideCache而不是从DOM得到的幻灯片信息,这是应用了“只写入DOM”策略。DOM只有在添加新内容时才会被修改。数据会使用updateSlideCache函数来缓存。

var slideCache;function updateSlideCache(node) { //在插入数据时调用此函数    var list = node.querySelectorAll('.slide'),        len = list.length        obj;    slideCache = [];    for (var i=0; i < len; i++) {        obj = {            node:list[i],            id:list[i].getAttribute('data-id'),            img:list[i].querySelector('.img')        }        obj.src = obj.img.getAttribute('data-src');        slideCache.push(obj);    }}

这里的node是一个只包含新添加的数据的节点。

另一个减低速度的是isVisible()函数, isVisible()函数需要大量的DOM读取和检查来执行它的运算。
使用缓存来快速检查元素的可见性

var slideMap = {};//to simplify look up this now takes a photo id,//which is the same as a slide id.function isVisible(id) {    var offTop, offsetHeight, data;    //if the slide is cached we can get the    //values from there    if(slideMap[id]){        offTop = slideMap[id].offTop;        offsetHeight = slideMap[id].offsetHeight;    //if the slide is not cached, update the cache    }else {        node = document.getElementById('s-' + id);        offsetHeight = parseInt(node.offsetHeight);        offTop = parseInt(node.offsetTop);        data = {            node:node,            offTop:offTop,            offsetHeight:offsetHeight        };        slideMap[id] = data;    }    //in the cached case this is just math, no DOM inspection at all    if(offTop + offsetHeight > topViewPort && offTop < bottomViewPort) {         return true;    } else {        return false;    }}
0 0
原创粉丝点击