备注:因为有使用到window挂载,不同环境node可以对比切为global或者其他公用地方都可以
定时器
基本描述:
1.基于window.requestAnimationFrame函数精准渲染,基本是1s60帧--16.7ms一帧--所以大概误差在16.7ms内
2.名称不会冲突--基本名称+uuid标识+时间戳
3.封装了,使用方便
const requestAnimationFrameTimer = (callbak, timer) => {
(() => {
/**
* 执行函数
* @param {根时间} reqTimerTime
* @param {requestAnimationFrame生成的id,取消的时候可以使用} reqTimerId
* @param {时间阀--判断时间是否到达的标准} timer
*/
const dealFn = (reqTimerTime, reqTimerId, timer) => {
let tempTime = Date.now();
if (tempTime - window[reqTimerTime] >= timer) {
//是否满足时间
console.log(`时间够了${tempTime}`);
window.cancelAnimationFrame(window[reqTimerId]); //取消requestAnimationFrame函数
callbak();
} else {
setReqFrameId(reqTimerTime, reqTimerId, timer); //不满足重新执行requestAnimationFrame
console.log(`时间不够${tempTime}:${tempTime - window[reqTimerTime]}`);
}
};
/**
* 为了构建一个随机名称
* @returns
*/
const guid = () => {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
};
/**
* 设置requestAnimationFrame生成的标识
* @param {根时间} reqTimerTime
* @param {requestAnimationFrame生成的id,取消的时候可以使用} reqTimerId
* @param {时间阀--判断时间是否到达的标准} timer
*/
const setReqFrameId = (reqTimerTime, reqTimerId, timer) => {
window[reqTimerId] = window.requestAnimationFrame(() =>
dealFn(reqTimerTime, reqTimerId, timer)
);
};
//初次执行
let nameTimestamp=Date.now()
let guidName= guid().split("-").join("")+nameTimestamp
let reqTimerTime = "requestAnimationFrametime" + guidName;
let reqTimerId = "requestAnimationFrameId" +guidName;
window[reqTimerTime] = Date.now();
setReqFrameId(reqTimerTime, reqTimerId, timer);
})();
};
requestAnimationFrameTimer(() => {
console.log("我是定时器callback");
}, 1500);
轮询
//基于以上封装的requestAnimationFrameTimer定时器基础--设计轮式机制
//其实这里用requestAnimationFrame去实现轮询有点奢侈,比如如果你项目是与物理设备交互,想精确的高频率去刷新来轮询,可以用这个。不然要求不严格的话,setInterval也是不错选择
const requestAnimationFrameTimerLoop = (callbak, timer) => {
(() => {
/**
* 执行函数
* @param {根时间} reqTimerTime
* @param {requestAnimationFrame生成的id,取消的时候可以使用} reqTimerId
* @param {时间阀--判断时间是否到达的标准} timer
*/
const dealFn = (reqTimerTime, reqTimerId, timer) => {
if(sessionStorage.getItem('reqFrameClose')){
return
}
let tempTime = Date.now();
if (tempTime - window[reqTimerTime] >= timer) {
//是否满足时间
console.log(`时间够了${tempTime}`);
window.cancelAnimationFrame(window[reqTimerId]); //取消requestAnimationFrame函数
callbak();
console.log('继续执行');
} else {
setReqFrameId(reqTimerTime, reqTimerId, timer); //不满足重新执行requestAnimationFrame
console.log(`时间不够${tempTime}:${tempTime - window[reqTimerTime]}`);
}
};
/**
* 为了构建一个随机名称
* @returns
*/
const guid = () => {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
};
/**
* 设置requestAnimationFrame生成的标识
* @param {根时间} reqTimerTime
* @param {requestAnimationFrame生成的id,取消的时候可以使用} reqTimerId
* @param {时间阀--判断时间是否到达的标准} timer
*/
const setReqFrameId = (reqTimerTime, reqTimerId, timer) => {
if(sessionStorage.getItem('reqFrameClose')){
return
}
window[reqTimerId] = window.requestAnimationFrame(() =>
dealFn(reqTimerTime, reqTimerId, timer)
);
};
//初次执行
let nameTimestamp=Date.now()
let guidName= guid().split("-").join("")+nameTimestamp
let reqTimerTime = "requestAnimationFrametime" + guidName;
let reqTimerId = "requestAnimationFrameId" +guidName;
window[reqTimerTime] = Date.now();
setReqFrameId(reqTimerTime, reqTimerId, timer);
})();
};
const loop=function(type){
try {
if(type=='start'){
requestAnimationFrameTimerLoop(() => {
//执行自己逻辑--比如与物理设备交互
console.log("我是定时器callback");
//处理完后需要重新触发loop
loop('start')
}, 1500);
}
if(type=='close'){
/**
* 为什么这里用缓存来去做一个拦截取消,主动调用 window.cancelAnimationFrame不行吗
* 1.因为cancelAnimationFrame调用后,其实requestAnimationFrame可能会刚好走到重新生成/调用requestAnimationFrame,导致没有取消掉
* 2.所以这里可以做一个静态标识判断处理,主要捕捉这种标识,就不再去生成requestAnimationFrame
*/
sessionStorage.setItem('reqFrameClose',true)
}
} catch (error) {
loop('start')
}
}
loop('start')
setTimeout(() => {
loop('close')
}, 4500);