zoukankan      html  css  js  c++  java
  • requestAnimationFrame

    最近打算研究一下canvas,然后就遇到要写动画,那么就遇到了requestAnimationFrame。

    requestAnimationFrame是什么?

    来自MDN的解释:window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行

    为什么存在?优点缺点?

    requestAnimationFrame是浏览器用于定时循环操作的一个接口,类似于setTimeout,主要用途是按帧对网页进行重绘。

    设置这个API的目的是为了让各种网页动画效果(DOM动画、Canvas动画、SVG动画、WebGL动画)能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。代码中使用这个API,就是告诉浏览器希望执行一个动画,让浏览器在下一个动画帧安排一次网页重绘。

    优点:在于充分利用显示器的刷新机制,比较节省系统资源。显示器有固定的刷新频率(60Hz或75Hz),也就是说,每秒最多只能重绘60次或75次,requestAnimationFrame的基本思想就是与这个刷新频率保持同步,利用这个刷新频率进行页面重绘。此外,使用这个API,一旦页面不处于浏览器的当前标签,就会自动停止刷新。这就节省了CPU、GPU和电力。

    缺点:requestAnimationFrame是在主线程上完成。这意味着,如果主线程非常繁忙,requestAnimationFrame的动画效果会大打折扣。

    requestAnimationFrame使用一个回调函数作为参数。这个回调函数会在浏览器重绘之前调用。

    怎么使用?

    语法

    window.requestAnimationFrame(callback);
    

    举个canvas中的例子

    const canvas = document.getElementById('canvas')
    const ctx = canvas.getContext('2d')
    let W = canvas.width = 800
    let H = canvas.height = 600
    
    const ball = new Ball({
        x: W/2,
        y: H/2,
        r: 50
    }).render(ctx)
    
    let angle = 0
    const SWING = 160;//振幅
    
    (function move() {
        window.requestAnimationFrame(move)
    
        ctx.clearRect(0, 0, W, H);
        ball.x = W/2 + Math.sin(angle) * SWING;
    
        angle += 0.05
        angle %= Math.PI * 2
        ball.render(ctx)
    
    })()
    

    polyfill

    优雅降级:由于兼容性问题,需要降级对接口进行封装,优先使用高级特性,再根据浏览器不同情况进行回退,直到只能使用settimeout,参考[GitHub](https://github.com/darius/requestAnimationFrame

    // Adapted from https://gist.github.com/paulirish/1579671 which derived from 
    // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
    // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
    
    // requestAnimationFrame polyfill by Erik Möller.
    // Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon
    
    // MIT license
    
    if (!Date.now)
        Date.now = function() { return new Date().getTime(); };
    
    (function() {
        'use strict';
        
        var vendors = ['webkit', 'moz'];
        for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
            var vp = vendors[i];
            window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];
            window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame']
                                       || window[vp+'CancelRequestAnimationFrame']);
        }
        if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy
            || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
            var lastTime = 0;
            window.requestAnimationFrame = function(callback) {
                var now = Date.now();
                var nextTime = Math.max(lastTime + 16, now);
                return setTimeout(function() { callback(lastTime = nextTime); },
                                  nextTime - now);
            };
            window.cancelAnimationFrame = clearTimeout;
        }
    }());
    

    总结

    实现动画效果的方法比较多,Javascript 中可以通过定时器 setTimeout 来实现,css3 可以使用 transition 和 animation 来实现,html5 中的 canvas 也可以实现。除此之外,html5 还提供一个专门用于请求动画的API,那就是 requestAnimationFrame,顾名思义就是请求动画帧。

    1. 屏幕刷新频率:屏幕每秒出现图像的次数。普通笔记本为60Hz

    2. 动画原理:计算机每16.7ms刷新一次,由于人眼的视觉停留,所以看起来是流畅的移动。

    3. setTimeout:通过设定间隔时间来不断改变图像位置,达到动画效果。但是容易出现卡顿、抖动的现象;原因是:1、settimeout任务被放入异步队列,只有当主线程任务执行完后才会执行队列中的任务,因此实际执行时间总是比设定时间要晚;2、settimeout的固定时间间隔不一定与屏幕刷新时间相同,会引起丢帧。

    4. requestAnimationFrame:优势:由系统决定回调函数的执行时机。60Hz的刷新频率,那么每次刷新的间隔中会执行一次回调函数,不会引起丢帧,不会卡顿

      使用:

    var progress = 0;
    //回调函数
    function render() {
     progress += 1; //修改图像的位置
     if (progress < 100) {
     //在动画没有结束前,递归渲染
     window.requestAnimationFrame(render);
     }
    }
    //第一帧渲染
    window.requestAnimationFrame(render);
    

    优势:
    CPU节能:使用setTimeout实现的动画,当页面被隐藏或最小化时,setTimeout 仍然在后台执行动画任务,由于此时页面处于不可见或不可用状态,刷新动画是没有意义的,完全是浪费CPU资源。而requestAnimationFrame则完全不同,当页面处理未激活的状态下,该页面的屏幕刷新任务也会被系统暂停,因此跟着系统步伐走的requestAnimationFrame也会停止渲染,当页面被激活时,动画就从上次停留的地方继续执行,有效节省了CPU开销。
    函数节流:在高频率事件(resize,scroll等)中,为了防止在一个刷新间隔内发生多次函数执行,使用requestAnimationFrame可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销。

  • 相关阅读:
    Retrofit 2使用要点梳理:小白进阶回忆录
    浅析Android动画(三),自定义Interpolator与TypeEvaluator
    浅析Android动画(二),属性动画高级实例探究
    浅析Android动画(一),View动画高级实例探究
    Retrofit 2使用要点梳理:浅析POST文件/表单上传
    AS历史代码记录,找回本地未提交代码
    注解基础篇:自定义Java Annotation
    注解提高篇:自定义注解处理器(APT)
    AndroidStudio快捷键大全
    VisualStudio2015常用快捷键
  • 原文地址:https://www.cnblogs.com/Jomsou/p/12542942.html
Copyright © 2011-2022 走看看