序言
计时器1直是javascript动漫的关键技术性。而撰写动漫循环系统的重要是要了解延迟时间時间多长适合。1层面,循环系统间距务必充足短,这样才可以让不一样的动漫实际效果显得光滑顺畅;另外一层面,循环系统间距还要充足长,这样才可以保证访问器有工作能力3D渲染造成的转变。
大多数数电脑上显示信息器的更新频率是60Hz,大约非常于每秒钟重绘60次。大多数数访问器都会对重绘实际操作加以限定,不超出显示信息器的重绘频率,由于即便超出那个频率客户体验也不容易有提高。因而,最光滑动漫的最好循环系统间距是1000ms/60,约等于16.6ms。
而setTimeout和setInterval的难题是,它们都不精准。它们的本质运作体制决策了時间间距主要参数具体上只是特定了把动漫编码加上到访问器UI进程序列中以等候实行的時间。假如序列前面早已添加了别的每日任务,那动漫编码就要等前面的每日任务进行后再实行。
requestAnimationFrame选用系统软件時间间距,维持最好绘图高效率,不容易由于间距時间太短,导致过多绘图,提升花销;也不容易由于间距時间过长,应用动漫卡顿不顺畅,让各种各样网页页面动漫实际效果可以有1个统1的更新体制,从而节约系统软件資源,提升系统软件特性,改进视觉效果实际效果。
特性
用法
requestAnimationFrame方式将1个callback做为主要参数,回调函数涵数会被传入1个主要参数,DOMHighResTimeStamp,标示当今被 requestAnimationFrame() 排列的回调函数涵数被开启的時间。回到值是1个恳求 ID,表明回调函数目录中唯1的标志。能够传这个值给 window.cancelAnimationFrame() 以撤销回调函数涵数。
requestID = window.requestAnimationFrame(callback);
运用这个api,能够将一些编码放到下1次再次3D渲染时实行,防止短期内内开启很多reflow。
比如网页页面翻转恶性事件(scroll)的回调函数涵数就很合适应用这个api, 将回调函数实际操作延迟到下1次再次3D渲染。但必须留意的是requestAnimationFrame 无论理回调函数涵数,即在回调函数被实行前,数次启用带有同1回调函数涵数的 requestAnimationFrame,会致使回调函数在同1帧中实行数次。最简易的,能够用节流阀涵数来处理这个难题,还可以想方法让requestAnimationFrame的序列里一样的回调函数涵数仅有1个:
let scheduledAnimationFrame = false; document.body.onscroll = () => { if (scheduledAnimationFrame) return; scheduledAnimationFrame = true; window.requestAnimationFrame(() => { scheduledAnimationFrame = false; // do something }); };
自然,最好的运用情景還是在帧动漫里,能够大幅提升特性。
招聘面试题
怎样3D渲染几万条数据信息其实不卡住页面
这道题调查了怎样在不卡住网页页面的状况下3D渲染数据信息,也便是说不可以1次性将几万条都3D渲染出来,而应当1次3D渲染一部分 DOM,那末便可以根据 requestAnimationFrame 来每 16 ms 更新1次。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF⑻"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <ul>控制</ul> <script> setTimeout(() => { // 插进10万条数据信息 const total = 100000 // 1次插进 20 条,假如感觉特性不太好就降低 const once = 20 // 3D渲染数据信息一共必须几回 const loopCount = total / once let countOfRender = 0 let ul = document.querySelector("ul"); function add() { // 提升特性,插进不容易导致回流 const fragment = document.createDocumentFragment(); for (let i = 0; i < once; i++) { const li = document.createElement("li"); li.innerText = Math.floor(Math.random() * total); fragment.appendChild(li); } ul.appendChild(fragment); countOfRender += 1; loop(); } function loop() { if (countOfRender < loopCount) { window.requestAnimationFrame(add); } } loop(); }, 0); </script> </body> </html>
适配性
1些老的访问器是不适用这个api的,以便也能应用这个api, 能够自定这个方式,挂载到window下面:
(function() { var lastTime = 0; var vendors = ['webkit', 'moz']; 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) { 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); }; }());
以上便是本文的所有內容,期待对大伙儿的学习培训有一定的协助,也期待大伙儿多多适用脚本制作之家。