移动端 touchmove高频事件与requestAnimationFrame的结合优化
移动端最高频耗内存的的操作 莫属 touchmove 与scroll事件 两者需要 微观的 优化,使用 requestAnimationFrame性能优化 H5性能优化requestAnimationFrame
这里 我们 讲述 touchmove;touchmove 事件发生很频繁,会比屏幕刷新率快,导致无效的渲染和重绘;
帧数 –显示设备通常的刷新率通常是50~60Hz –1000ms / 60 ≈ 16.6ms(1毫秒的优化意味着 6%的性能提升)
这就是 常说的 16.6毫秒的优化

浏览器对每一帧画面的渲染工作需要在16毫秒(1秒 / 60 = 16.66毫秒)之内完成 ;如果超过了这个时间限度,页面的渲染就会出现卡顿效果,也就是常说的jank;我们需要在 正确的时间 做正确的渲染;
拖拽的都会写,先上图看看效果;

大概了解一下 Timeline 查看看渲染情况 旧版如下( 新的 在 Performance )
ps Performance 可以在控制台出入 查看

(function() {
handleAddListener('load', getTiming)
function handleAddListener(type, fn) {
if(window.addEventListener) {
window.addEventListener(type, fn)
} else {
window.attachEvent('on' + type, fn)
}
}
function getTiming() {
try {
var time = performance.timing;
var timingObj = {};
var loadTime = (time.loadEventEnd - time.loadEventStart) / 1000;
if(loadTime < 0) {
setTimeout(function() {
getTiming();
}, 200);
return;
}
timingObj['重定向时间'] = (time.redirectEnd - time.redirectStart) / 1000;
timingObj['DNS解析时间'] = (time.domainLookupEnd - time.domainLookupStart) / 1000;
timingObj['TCP完成握手时间'] = (time.connectEnd - time.connectStart) / 1000;
timingObj['HTTP请求响应完成时间'] = (time.responseEnd - time.requestStart) / 1000;
timingObj['白屏时间'] = (time.responseStart - time.navigationStart) / 1000;
timingObj['DOM渲染时间'] = (time.domComplete - time.domInteractive) / 1000;
timingObj['domready时间--DOMContentLoaded事件完成的时间'] = (time.domContentLoadedEventEnd - time.fetchStart) / 1000;
timingObj['onload时间 --页面所有资源完全加载的时间 '] = (time.loadEventEnd-time.fetchStart)/1000;
for(item in timingObj) {
console.log(item + ":" + timingObj[item] + '毫秒(ms)');
}
console.log(performance.timing);
} catch(e) {
console.log(timingObj)
console.log(performance.timing);
}
}
})();

上面的代码 可以放入页面查看性能。


在看看 帧模式 渲染情况;

那些没必要的 move 什么也不需要做;没必要在16.6毫秒内多余的event对象计算;

关于帧模式:



普通的拖拽
<script>
function getStyle(obj,attr){
return obj.currentStyle? obj.currentStyle[attr]: getComputedStyle(obj,false)[attr];
}
var oDiv = document.getElementById("oDiv"); //当前元素
var direction="horizontal";
var disX=0;
var disY=0;
var self = this; //上下文
var downLeft=0;
var downTop=0;
var isDown = false;
var oDivWidth=parseInt(oDiv.offsetWidth);
oDiv.onmousedown = function (e) {
var e=e||window.event;
//鼠标按下,计算当前元素距离可视区的距离
downLeft= parseInt(getStyle(oDiv,'left'));;
downTop= parseInt(getStyle(oDiv,'top'));;
disX = e.clientX ;
disY = e.clientY;
console.log("开始位置",e.clientX,"downLeft",downLeft);
isDown = true;
document.onmousemove = function (e) {
var e=e||window.event;
e.preventDefault();
oDiv.style.cursor="move";
if (isDown == false) {
return;
}
//通过事件委托,计算移动的距离
var l = e.clientX - disX+downLeft;
var t = e.clientY - disY+downTop;
//移动当前元素
if(direction=="horizontal"){//水品
oDiv.style.left = l + 'px';
}else if(direction=="vertical"){//垂直
oDiv.style.top = t + 'px';
}else{
oDiv.style.left = l + 'px';
oDiv.style.top = t + 'px';
}
// console.log("移动位置",e.clientX,"移动中left",l,"最终",getOffset(oDiv).left);
//将此时的位置传出去
//binding.value({x:l,y:t,direction:direction})
};
document.onmouseup = function (e) {
var e=e||window.event;
var left2=e.clientX-disX;
var top2=e.clientY-disY;
isDown = false;
// console.log("结束位2置",e.pageX,"移asa中left",left2,"最终",getOffset(oDiv).left);
//将此时的位置传出去
document.onmousemove = null;
document.onmouseup = null;
return false; //FF等高版本浏览器中阻止默认行为
};
};
</script>
附上源代码:
function drag(element){
var startX=0,
startY=0,
ticking=false,
raf,
doc=document;
element.addEventListener("touchstart",function(e){
var e=e||window.event,
touchs = e.touches[0];
e.preventDefault(); //低端安卓 touch事件 有的导致touchend事件时效 必须开始 就加 e.preventDefault();
// text a ipnut textarea 几个 等标签除外
// ,另外自定义移动端touchstart touchend组合的 hover事件,建议不加这个,不然页面无法滚动
//touchmove 开始 就加 不然抖动一下,才能touchmove, 然后才正常 尤其早些的 三星 系列自带浏览器
startX=parseInt(touchs.pageX-(element.lefts||0));
startY=parseInt(touchs.pageY-(element.tops||0));
doc.addEventListener("touchmove",update,false);
doc.addEventListener("touchend",end,false);
},false);
var update=function (e) {
var e=e||window.event;
if (e.touches.length > 1 || e.scale && e.scale !== 1) return;
e.preventDefault();
//cancelAnimationFrame(raf);
if(!ticking) {
var touchs = e.changedTouches[0];
//1先触摸移动
element.lefts = touchs.pageX - startX;
element.tops = touchs.pageY - startY;
//2交给requestAnimationFrame 更新位置
//raf=requestAnimationFrame(function(){draw();});
raf=requestAnimationFrame(draw);
}
ticking = true;
};
var draw= function (){
ticking = false;
var nowLeft=parseInt(element.lefts); //滑动的距离 touchmove时候,如果加阻力,可能有细小的抖动;我想应该是移动端 部分支持0.5px的缘故; parseInt的转化有点牵强;
var nowTop=parseInt (element.tops); //滑动的距离
element.style.webkitTransform=element.style.transform = "translate3D(" + nowLeft + "px," + nowTop + "px,0px)";
};
var end=function(){
var endLeft= parseInt(element.lefts); //滑动的距离
var endTop= parseInt(element.tops); //滑动的距离
//element.style.webkitTransform=element.style.transform = "translate(" + endLeft+ "px," + endTop + "px)";
doc.removeEventListener("touchmove",update,false);
doc.removeEventListener("touchend",end,false);
// cancelAnimationFrame(raf);
}
};
注意点:RequestAnimationFrame的兼容
;(function(){var lastTime=0;var vendors=["ms","moz","webkit","o"];for(var x=0;x<vendors.length&&!window.requestAnimationFrame;++x){window.requestAnimationFrame=window[vendors[x]+"RequestAnimationFrame"];window.cancelAnimationFrame=window[vendors[x]+"CancelAnimationFrame"]||window[vendors[x]+"CancelRequestAnimationFrame"]}if(!window.requestAnimationFrame){window.requestAnimationFrame=function(callback,element){var currTime=new Date().getTime();var timeToCall=Math.max(0,16-(currTime-lastTime));var id=window.setTimeout(function(){callback(currTime+timeToCall)},timeToCall);lastTime=currTime+timeToCall;return id}}if(!window.cancelAnimationFrame){window.cancelAnimationFrame=function(id){clearTimeout(id)}}}());
RequestAnimationFrame的简易动画库
requestAnimationFrame 节流函数
function throttle1(fn, wait) {
let previous = 0;
return function () {
let now = new Date().getTime();
if (now - previous > wait) {
fn.apply(this, arguments);
previous = now;
}
}
}
function raf_debounce(fn){ //touchmove scroll节流
var ticking=false;
var that=this;
return function(e) {
var ev=e||window.event;
// console.log("正1确的e",e);
if(!ticking) {
ticking = true;
requestAnimationFrame(function(){
//console.log("正2确的e",ev);
fn(ev);
ticking = false;
});
}
}
};
var sb=1;
window.addEventListener("scroll",function(e){
if(sb){
sb=0;
//var d = (+new Date());
console.log("sb",e)
}
})
var sa=1;
window.addEventListener("scroll",throttle1(function(e){
if(sa){
//sa=0;
var d = (+new Date());
console.log("sa",e);
}
},12))
var sc=1;
window.addEventListener("scroll",raf_debounce(function(e){
if(sc){
//sa=0;
var d = (+new Date());
console.log("sc",e);
}
}))
1513763671784
1513763671800
1513763671817
1513763671834
1513763671850
1513763671867
1513763671883
1513763671900
1513763671917
1513763671934
观察最后2位 数字 后一个大于前一个的 16 两个大约相差16.6毫秒 执行scroll fn一次
注意正确的上下文 event 对象

document.onmousemove = moveBy;
// document.onmousemove = raf_debounce(function(e){
// moveBy (e);
// });
充分合理 使用 requestAnimationFrame性能优化 对H5网页的体验 有着微观细致的影响;
from memory cache与from disk cache

三级缓存原理
1、先查找内存,如果内存中存在,从内存中加载;
2、如果内存中未查找到,选择硬盘获取,如果硬盘中有,从硬盘中加载;
3、如果硬盘中未查找到,那就进行网络请求;
4、加载到的资源缓存到硬盘和内存;
三、HTTP状态码及区别
200 form memory cache
不访问服务器,一般已经加载过该资源且缓存在了内存当中,直接从内存中读取缓存。浏览器关闭后,数据将不存在(资源被释放掉了),再次打开相同的页面时,不会出现from memory cache。200 from disk cache
不访问服务器,已经在之前的某个时间加载过该资源,直接从硬盘中读取缓存,关闭浏览器后,数据依然存在,此资源不会随着该页面的关闭而释放掉下次打开仍然会是from disk cache。304 Not Modified
访问服务器,发现数据没有更新,服务器返回此状态码。然后从缓存中读取数据。

链接:https://www.jianshu.com/p/8332da83955d
参考网站:
谷歌开发者,非常专业:https://developers.google.com/web/fundamentals/getting-started/?hl=zh-cn 需要翻墙;
Web前端性能优化的微观分析 http://velocity.oreilly.com.cn/2013/ppts/16_ms_optimization--web_front-end_performance_optimization.pdf
移动端性能调优:ttps://speakerdeck.com/baofen14787/yi-dong-duan-xing-neng-diao-you-ji-16msyou-hua
总结:做的东西多了,得 整理一下以;
移动端 scroll,touchmove的事件用的还是比较多的;有时间还是要 细细优化的;虽然感觉很微观 ,甚至觉得 优化的几乎看不出来;但是你去优化好,还是费不少时间 的;
requestAnimationFrame是个移动端的利器;动画尽量用它或者除集合css3实现;
一个基于 requestAnimationFrame 的动画函数,仿造jquery http://www.cnblogs.com/surfaces/p/5129868.html
移动端 transition动画函数的封装(仿Zepto)以及 requestAnimationFrame动画函数封装(仿jQuery)
移动端 touchmove高频事件与requestAnimationFrame的结合优化的更多相关文章
- 关于移动端的Click事件
在移动端执行Click事件,通常情况出现有300毫秒的延迟,为防止这种不必要的延迟效果,我们可以换种方式来实现,同样达到快速执行Click事件的效果. 先了解一下移动端Click的执行顺序: touc ...
- 移动端touch触摸事件(滑动效果和手势操作)
一.定义 ①touch是移动端的触摸事件,而且是一组事件,主要有以下事件: touchstart 事件:当手指触摸屏幕的时候触发 touchmove 事件:当手指在屏幕来回滑动的时候触发 touche ...
- 移动端 之 触摸事件、Tap事件和swipe事件
触摸事件 touch是一个事件组,意思不止一个事件,是移动端滑动事件组,touchstart touchmove touchend touchcancel touchstart 当刚刚触摸屏幕的时候触 ...
- 移动端touch拖动事件和click事件冲突问题解决
通过一个悬浮球交互功能的案例来阐述问题,以及解决办法. 实现效果 类似微信里的悬浮窗效果,苹果手机的悬浮球功能效果 可以点击拖动,然后吸附在窗口边缘 点击悬浮球,可以跳转界面,或者更改悬浮球的形态 准 ...
- (转)客户端触发Asp.net中服务端控件事件
第一章. Asp.net中服务端控件事件是如何触发的 Asp.net 中在客户端触发服务端事件分为两种情况: 一. WebControls中的Button 和HtmlControls中的Type为su ...
- 移动端的click事件延迟触发的原理是什么?如何解决这个问题?
移动端的click事件延迟触发的原理是什么?如何解决这个问题? 原理 :移动端屏幕双击会缩放页面 300ms延迟 会出现点透现象 在列表页面上创建一个弹出层,弹出层有个关闭的按钮,你点了这个按钮关闭弹 ...
- 高频dom操作和页面性能优化(转载)
作者:gxt19940130 原文:https://feclub.cn/post/content/dom 一.DOM操作影响页面性能的核心问题 通过js操作DOM的代价很高,影响页面性能的主要问题有如 ...
- 关于如何获取移动端 touchmove 事件中真正触摸点下方的元素
移动端的touchstart, touchmove, touchend三个事件,点击元素并拖动时,获取到了touchmove事件, 但是event.touches[0].target所指向的元素却是t ...
- 移动端的touchstart,touchmove,touchend事件中的获取当前touch位置
前提:touchstart,touchmove,touchend这三个事件可以通过原生和jq绑定. 原生:document.querySelector("#aa").addEven ...
随机推荐
- POJ 1838 Banana (并查集)
Description Consider a tropical forrest, represented as a matrix. The cell from the right top corner ...
- 堆栈帧的组织——C/C++内存管理必须掌握
程序栈 说到堆栈帧,你得先说说程序栈. 记忆功能程序堆栈区是支持操作,通常共享堆. 程序栈通常占领内存区域的下部,而堆用的是上部. 程序栈存放栈帧,栈帧有时候也称为活跃记录或活跃帧.栈帧存放函数參数和 ...
- 一个极其简洁的Python网页抓取程序,自己主动从雅虎財经抓取股票数据
本程序使用Python 2.7.6编写,扩展了Python自带的HTMLParser,自己主动依据预设的股票代码列表,从Yahoo Finance抓取列表中的数据日期.股票名称.实时报价.当日变化率. ...
- POJ 2299 Ultra-QuickSort (求序列的逆序对数)
题意:废话了一大堆就是要你去求一个序列冒泡排序所需的交换的次数. 思路:实际上是要你去求一个序列的逆序队数 看案例: 9 1 0 5 4 9后面比它小的的数有4个 1后面有1个 0后面没有 5后面1个 ...
- Javascript语言精粹之Array常用方法分析
Javascript语言精粹之Array常用方法分析 1.Array常用方法分析 1.1 Array.prototype.sort() Javascript的默认比较函数假定被排序元素都是字符串,所以 ...
- 一些Android框架
从网上收集一些框架,敲代码偷懒这些框架非常实用,必须记下来,为了以后少写代码,用别人好的框架 ThinkAndroid ThinkAndroid(一个ThinkAndroid教程地址:http://m ...
- SVM-SVM概述
(一)SVM背景资料简介 支持向量机(Support Vector Machine)这是Cortes和Vapnik至1995首次提出,样本.非线性及高维模式识别中表现出很多特有的优势,并可以推广应用到 ...
- Oracle SQL Lesson (8) - 使用集合操作符(Union,Intersect,Minus)
集合操作符UNION/UNION ALLINTERSECTMINUS Union All不排序,不去重,其余均升序且去重.create table e1 as select * from emp wh ...
- Unity--关于优化方面的那些事儿(一)
近期做一个小项目,要求包的大小不能超过30M. 晚上做了个小实验,方法的确非常本,只是曾经非常多没懂的地方如今清晰了很多,我是菜鸟!希望本文章对大家有帮助,谢谢! 实验结果: 实验结果: 1.场景中仅 ...
- 在MyEclipse8.5中配置Tomcat6.0服务器
一.单击工具栏的的黑小三角,选择—>Configure Server,出现首选项对话框,在对话框的左边框中找到MyEclipse—>Application Servers下找到Tomcat ...