前几天把服务器重置了一下,精力放在前端时,发现网页在手机上有卡顿的现象,尤其是点击“回到顶端”时特别明显。
通过chrome开发者工具性能监视,发现jQuery.color的2.0.0版本有不停重绘的现象,替换为最新版后消失。
进一步发现scroll事件调用过高:我主要在右侧栏悬浮时用到。

百度发现高性能滚动 scroll及页面渲染优化文章;学到了不少,推荐阅读.
我简要说一下因为scroll被触发的频率非常高,会发生大量的位置计算、DOM 操作、元素重绘,导致cpu占用高,掉帧严重。

我们可以通过节流和防抖来限制事件的触发频率


// 简单的防抖动函数
function debounce(func, wait, immediate) {
// 定时器变量
var timeout;
return function() {
  // 每次触发 scroll handler 时先清除定时器
   clearTimeout(timeout);
    // 指定 xx ms 后触发真正想进行的操作 handler
   timeout = setTimeout(func, wait);
   };
};

// 实际想绑定在 scroll 事件上的 handler
function realFunc(){
  console.log("Success");
}

window.addEventListener('scroll',debounce(realFunc,500));

节流与之区别是,在500ms的setTimeout事件外还添加了一个在1000ms必须执行一次的语句,防止因为一直滚动导致没有事件效果
间隔时间越高,精确度越低,我右侧栏在250ms就有些迟钝了。


// 简单的节流函数
function throttle(func, wait, mustRun) {
var timeout,
startTime = new Date();

return function() {
  var context = this,
  args = arguments,
  curTime = new Date();

  clearTimeout(timeout);
  // 如果达到了规定的触发时间间隔,触发 handler
  if(curTime - startTime >= mustRun){
    func.apply(context,args);
    startTime = curTime;
    // 没达到触发间隔,重新设定定时器
  }else{
   timeout = setTimeout(func, wait);
  }
 };
};
// 实际想绑定在 scroll 事件上的 handler
function realFunc(){
  console.log("Success");
}
// 采用了节流函数
window.addEventListener('scroll',throttle(realFunc,500,1000));

还有一种通过原生函数的方法实现,不过它有兼容问题,其次因为它只能实现以 16.7ms 的频率(60fps)来触发,可调性差。但比起前面方式更简便,性能也过得去。

var ticking = false; // rAF 触发锁

function onScroll(){
if(!ticking) {
  requestAnimationFrame(realFunc);
  ticking = true;
}
}
function realFunc(){
  // do something...
  console.log("Success");
  ticking = false;
}
// 滚动事件监听
window.addEventListener('scroll', onScroll, false);

我选择的是最后一个方案,因为精简啊,我还是喜欢简单一点的...

function i() {
  t || (requestAnimationFrame(e), t = !0);
}

function e() {
  var k = $(".navbar-brand"), f = $(".entry-title").text(), i = "opacity", e = $(".fixed-top"), s = $(window).scrollTop();
  if (s > 99 ? e.css(i, ".8") :e.css(i, "1"), 0 != f.length && s > 320 ? k.text(f) :k.text("新觉小屋"),
  !(0 == $("#sidebar-2").length || $("#main").height() <= $("#widget-area").height())) {
var a = $("#sidebar-2"), o = $("#sidebar-1");
  a.hasClass("fix") ? o.offset().top + o.height() > s + 45 && a.removeClass("fix") :a.offset().top < s + 66 && a.addClass("fix");
 }
t = !1;
}

var s = $(window).width(), t = !1;

s < 1e3 || window.addEventListener("scroll", i, !1);

如你所见,$(window).width()<1000px时,不使用该函数,即就是说,手机端和平板不使用此高耗能的效果。

更新于:2017-12-16