电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

requestAnimationFrame定時動畫屏幕刷新率節流示例淺析

瀏覽:96日期:2022-06-02 09:26:47
目錄
  • 前言
  • 早期定時動畫
  • 屏幕刷新率
  • requestAnimationFrame
  • cancelAnimationFrame
  • 通過 requestAnimationFrame 節流

前言

很長時間以來,計時器和定時執行都是 JavaScript 動畫最先進的工具。雖然 CSS 過渡和動畫方便了開發者實現某些動畫,但 JavaScript 動畫領域多年來進展甚微。requestAnimationFrame() 方法應運而生,這個方法會告訴瀏覽器要執行動畫了,于是瀏覽器可以通過最優方式確定重繪的時序。

早期定時動畫

以前,在 JavaScript 中創建動畫基本上就是使用 setInterval() 來控制動畫的執行:

(function () {
  function updateAnimations() {
    doAnimation1();
    doAnimation2();
    // ...
  }
  setInterval(updateAnimations, 100);
})();

這種定時動畫的問題在于,無法準確知曉循環之間的延時。

無論是 setInterval() 還是 setTimeout(),都是不能保證時間精度的。作為第二個參數的延時只能保證何時會把代碼添加到瀏覽器的任務隊列,并不能保證添加到隊列就會立即執行。如果隊列前面還有其他任務,那么就要等這些任務執行完再執行。

簡單來講,這里的毫秒延時不是指何時這些代碼會執行,而是指到時候會把回調添加到任務隊列。如果添加到隊列后,主線程還被其他任務占用,那么回調就不會立即執行。

知道何時繪制下一幀是創造平滑動畫的關鍵,所以 setInterval()setTimeout() 的不精確是個大問題。

瀏覽器自身計時器的精度讓這個問題雪上加霜。瀏覽器計時器的精度不足毫秒,最厲害的 Chrome 計時器精度為 4ms。更麻煩的是,瀏覽器又開始對切換到后臺或不活躍的標簽頁中的計時器執行限流,因此即使將時間間隔設為最優,也免不了只能得到近似的結果。

屏幕刷新率

一般計算機顯示器的屏幕刷新率都是 60HZ,基本上意味著每秒需要重繪 60 次。大多數瀏覽器會限制重繪頻率,使其不超過屏幕的刷新率,因為超過屏幕刷新率用戶也感知不到。

所以,實現平滑動畫最佳的重繪時間間隔為 1000ms/60,大約 17 ms。以這個速度重繪可以實現最平滑的動畫,因為這已經是瀏覽器的極限了。

requestAnimationFrame

requestAnimationFrame() 這個方法可以通知瀏覽器某些 JavaScript 代碼要執行動畫了,這樣瀏覽器就可以在運行某些代碼后進行適當的優化。

requestAnimationFrame() 這個方法接收一個參數,該參數是一個要在重繪屏幕前調用的函數。這個函數就是修改 DOM 樣式以反映下一次重繪有什么變化的地方。為了實現動畫循環,可以把多個 requestAnimationFrame() 調用串聯起來,就像以前使用 setTimeout() 一樣:

function updateProgress() {
  var div = document.getElementById("status");
  div.style.width = parseInt(div.style.width, 10) + 5 + "%";
  if (div.style.left != "100%") {
    requestAnimationFrame(updateProgress);
  }
}
requestAnimationFrame(updateProgress);

因為 requestAnimationFrame() 只會調用一次傳入的函數,所以每次更新用戶界面時需要再手動調用它一次。同時,也需要控制動畫何時停止。結果就會得到非常平滑的動畫。

requestAnimationFrame() 已經解決了瀏覽器不知道 JavaScript 動畫何時開始的問題,以及最佳間隔時間是多少的問題。但是,如果我們想知道自己的代碼實際的執行時間呢?同樣有解決方案。

傳給 requestAnimationFrame() 的函數實際上可以接收一個參數,該參數表示下次重繪的時間。這一點非常重要:requestAnimationFrame() 實際上把重繪任務安排在了未來一個已知的時間點上,而且通過這個參數告訴了開發者,那么基于這個參數,就可以更好地決定如何調優動畫了:

function foo(t) {
  console.log(t);
  requestAnimationFrame(foo);
}
requestAnimationFrame(foo);

cancelAnimationFrame

const requestID = window.requestAnimationFrame((t) => {
  console.log(t);
});
window.cancelAnimationFrame(requestID);

通過 requestAnimationFrame 節流

支持這個方法的瀏覽器實際上會暴露出作為鉤子的回調隊列。所謂鉤子,就是瀏覽器在執行下一次重繪之前的一個點。這個回調隊列是一個可修改的函數列表,包含應該在重繪之前調用的函數。每次調用 requestAnimationFrame() 都會在隊列上推入一個回調函數,隊列的長度沒有限制。

這個回調隊列的行為不一定跟動畫有關。通過 requestAnimationFrame() 遞歸地向隊列中加入回調函數,可以保證每次重繪最多只調用一次回調函數,這是一個非常好的節流工具。在頻繁執行影響頁面外觀的代碼時(比如滾動事件監聽器),可以利用這個回調隊列進行節流。

先看一個原生實現,其中的滾動事件監聽器每次觸發都會調用名為 expensiveOperation()(耗時操作) 的函數。當向下滾動網頁時,這個事件很快就會被觸發并執行成百上千次:

function expensiveOperation() {
  console.log("Invoked at", Date.now());
}
window.addEventListener("scroll", () => {
  expensiveOperation();
});

如果想把事件處理程序的調用限制在每次重繪之前,那么就可以把它封裝到 requestAnimationFrame() 調用中:

function expensiveOperation() {
  console.log("Invoked at", Date.now());
}
window.addEventListener("scroll", () => {
  window.requestAnimationFrame(expensiveOperation);
});

這樣會把所有回調的執行集中在重繪鉤子,但不會過濾掉每次重繪的多余調用。我們可以定義一個標志變量,在回調中設置其狀態,就能將多余的調用屏蔽:

let enqueued = false;
function expensiveOperation() {
  console.log("Invoked at", Date.now());
  enqueued = false;
}
window.addEventListener("scroll", () => {
  if (!enqueued) {
    enqueued = true;
    window.requestAnimationFrame(expensiveOperation);
  }
});

因為重繪是非常頻繁的操作,所以這算不上是真正的節流。更好的方法是配合使用一個計時器來限制操作執行的頻率。這樣,計時器可以限制實際的操作執行間隔,而 requestAnimationFrame() 控制在瀏覽器的哪個渲染周期中執行:

let enabled = true;
function expensiveOperation() {
  console.log("Invoked at", Date.now());
}
window.addEventListener("scroll", () => {
  if (enabled) {
    enqueued = false;
    window.requestAnimationFrame(expensiveOperation);
    window.setTimeout(() => (enabled = true), 50);
  }
});

上面的例子將回調限制為大約 50ms 執行一次。

以上就是requestAnimationFrame定時動畫屏幕刷新率節流示例淺析的詳細內容,更多關于requestAnimationFrame刷新節流的資料請關注其它相關文章!

標簽: JavaScript
主站蜘蛛池模板: 小程序开发公司_APP开发多少钱_软件开发定制_微信小程序制作_客户销售管理软件-济南小溪畅流网络科技有限公司 | 新中天检测有限公司青岛分公司-山东|菏泽|济南|潍坊|泰安防雷检测验收 | 透平油真空滤油机-变压器油板框滤油机-滤油车-华之源过滤设备 | 四川成都干燥设备_回转筒干燥机_脉冲除尘器_输送设备_热风炉_成都川工星科机电设备有限公司 | 德州网站制作 - 网站建设设计 - seo排名优化 -「两山建站」 | 真空泵厂家_真空泵机组_水环泵_旋片泵_罗茨泵_耐腐蚀防爆_中德制泵 | 【中联邦】增稠剂_增稠粉_水性增稠剂_涂料增稠剂_工业增稠剂生产厂家 | 自动螺旋上料机厂家价格-斗式提升机定制-螺杆绞龙输送机-杰凯上料机 | 气动隔膜阀_气动隔膜阀厂家_卫生级隔膜阀价格_浙江浙控阀门有限公司 | 沈阳网站建设_沈阳网站制作_沈阳网页设计-做网站就找示剑新零售 沈阳缠绕膜价格_沈阳拉伸膜厂家_沈阳缠绕膜厂家直销 | 柔性测斜仪_滑动测斜仪-广州杰芯科技有限公司 | 派克防爆伺服电机品牌|国产防爆伺服电机|高低温伺服电机|杭州摩森机电科技有限公司 | 广东机电安装工程_中央空调工程_东莞装饰装修-广东粤标建设有限公司 | 等离子空气净化器_医用空气消毒机_空气净化消毒机_中央家用新风系统厂家_利安达官网 | 中山东港家具集团-酒店-办公-医养家具定制厂家 | 电磁流量计_智能防腐防爆管道式计量表-金湖凯铭仪表有限公司 | 热闷罐-高温罐-钢渣热闷罐-山东鑫泰鑫智能热闷罐厂家 | 色油机-色母机-失重|称重式混料机-称重机-米重机-拌料机-[东莞同锐机械]精密计量科技制造商 | 最新电影-好看的电视剧大全-朝夕电影网 | 耐高温风管_耐高温软管_食品级软管_吸尘管_钢丝软管_卫生级软管_塑料波纹管-东莞市鑫翔宇软管有限公司 | 机构创新组合设计实验台_液压实验台_气动实训台-戴育教仪厂 | 药品仓库用除湿机-变电站用防爆空调-油漆房用防爆空调-杭州特奥环保科技有限公司 | 工业淬火油烟净化器,北京油烟净化器厂家,热处理油烟净化器-北京众鑫百科 | 台湾阳明固态继电器-奥托尼克斯光电传感器-接近开关-温控器-光纤传感器-编码器一级代理商江苏用之宜电气 | 商标转让-购买商标专业|放心的商标交易网-蜀易标商标网 | 安徽集装箱厂-合肥国彩钢结构板房工程有限公司 | 东莞市海宝机械有限公司-不锈钢分选机-硅胶橡胶-生活垃圾-涡电流-静电-金属-矿石分选机 | 安徽免检低氮锅炉_合肥燃油锅炉_安徽蒸汽发生器_合肥燃气锅炉-合肥扬诺锅炉有限公司 | 太空舱_民宿太空舱厂家_移动房屋太空舱价格-豪品建筑 | 细沙回收机-尾矿干排脱水筛设备-泥石分离机-建筑垃圾分拣机厂家-青州冠诚重工机械有限公司 | 深圳善跑体育产业集团有限公司_塑胶跑道_人造草坪_运动木地板 | 安徽控制器-合肥船用空调控制器-合肥家电控制器-合肥迅驰电子厂 安徽净化板_合肥岩棉板厂家_玻镁板厂家_安徽科艺美洁净科技有限公司 | 今日娱乐圈——影视剧集_八卦娱乐_明星八卦_最新娱乐八卦新闻 | 大倾角皮带机-皮带输送机-螺旋输送机-矿用皮带输送机价格厂家-河南坤威机械 | 高尔夫球杆_高尔夫果岭_高尔夫用品-深圳市新高品体育用品有限公司 | 橡胶电子拉力机-塑料-微电脑电子拉力试验机厂家-江苏天源 | 广东健伦体育发展有限公司-体育工程配套及销售运动器材的体育用品服务商 | 金属回收_废铜废铁回收_边角料回收_废不锈钢回收_废旧电缆线回收-广东益夫金属回收公司 | 空气弹簧|橡胶气囊|橡胶空气弹簧-上海松夏减震器有限公司 | 驾驶人在线_专业学车门户网站 | 手板-手板模型-手板厂-手板加工-生产厂家,[东莞创域模型] |