From db609b91424bea2b7b94183a06861d94c3533e94 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Tue, 17 May 2016 14:49:48 -0700 Subject: [PATCH] Frame-rate limiter for m.mount/m.route --- limiter.js | 35 +++++++++++++++++++++++++++++ mithril.js | 51 ++++++++++++++++++++++++++++++++++++++----- mount.js | 11 +++++----- router.js | 6 +++-- test-redraw.html | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 limiter.js create mode 100644 test-redraw.html diff --git a/limiter.js b/limiter.js new file mode 100644 index 00000000..a7575789 --- /dev/null +++ b/limiter.js @@ -0,0 +1,35 @@ +var FRAME_BUDGET = 16 // 60 frames per second = 1 call per 16 ms + +module.exports = function($window, render) { + var rAF = $window.requestAnimationFrame || $window.setTimeout + var cAF = $window.cancelAnimationFrame || $window.clearTimeout + + var last = 0 + var pending + + return function() { + var now = new Date() + + // First render, OR if the time since the last render is greater + // than the frame budget + // just immediately render + if(!last || now - last > FRAME_BUDGET) { + last = now; + + return render() + } + + // Redraw already pending, abort + if(pending) { + return + } + + // Schedule a redraw for the next tick + pending = rAF(function() { + render() + + last = new Date() + pending = null + }, FRAME_BUDGET - (now - last)) + } +} diff --git a/mithril.js b/mithril.js index c920b2d5..17e2a7bd 100644 --- a/mithril.js +++ b/mithril.js @@ -575,21 +575,58 @@ var createRenderer = function($window) { return {render: render, setEventCallback: setEventCallback} } +var FRAME_BUDGET = 16 // 60 frames per second = 1 call per 16 ms + +var limiter = function($window, render) { + var rAF = $window.requestAnimationFrame || $window.setTimeout + var cAF = $window.cancelAnimationFrame || $window.clearTimeout + + var last = 0 + var pending + + return function() { + var now = new Date() + + // First render, OR if the time since the last render is greater + // than the frame budget + // just immediately render + if(!last || now - last > FRAME_BUDGET) { + last = now; + + return render() + } + + // Redraw already pending, abort + if(pending) { + return + } + + // Schedule a redraw for the next tick + pending = rAF(function() { + render() + + last = new Date() + pending = null + }, FRAME_BUDGET - (now - last)) + } +} +; var createMounter = function($window, redraw) { return function(root, component) { var renderer = createRenderer($window) - renderer.setEventCallback(draw) - - function draw() { + var draw = limiter($window, function draw() { renderer.render(root, {tag: component}) - } + }) + renderer.setEventCallback(draw) + redraw.run = draw draw() } } + var buildQueryString = function buildQueryString(object) { if (Object.prototype.toString.call(object) !== "[object Object]") return "" @@ -758,15 +795,17 @@ var createRouter = function($window) { return {setPrefix: setPrefix, getPath: getPath, setPath: setPath, defineRoutes: defineRoutes, link: link} } + var createRouterInstance = function($window, redraw) { var renderer = createRenderer($window) var router = createRouter($window) var route = function(root, defaultRoute, routes) { - var replay = router.defineRoutes(routes, function(component, args) { + var replay = limiter($window, router.defineRoutes(routes, function(component, args) { renderer.render(root, {tag: component, attrs: args}) }, function() { router.setPath(defaultRoute) - }) + })) + renderer.setEventCallback(replay) redraw.run = replay } diff --git a/mount.js b/mount.js index 3a389ba0..cf633938 100644 --- a/mount.js +++ b/mount.js @@ -1,15 +1,16 @@ var createRenderer = require("./render/render") +var limiter = require("./limiter"); module.exports = function($window, redraw) { return function(root, component) { var renderer = createRenderer($window) - renderer.setEventCallback(draw) - - function draw() { + var draw = limiter($window, function draw() { renderer.render(root, {tag: component}) - } + }) + renderer.setEventCallback(draw) + redraw.run = draw draw() } -} \ No newline at end of file +} diff --git a/router.js b/router.js index 25701196..5a3f5f62 100644 --- a/router.js +++ b/router.js @@ -1,15 +1,17 @@ var createRenderer = require("./render/render") var createRouter = require("./router/router") +var limiter = require("./limiter") module.exports = function($window, redraw) { var renderer = createRenderer($window) var router = createRouter($window) var route = function(root, defaultRoute, routes) { - var replay = router.defineRoutes(routes, function(component, args) { + var replay = limiter($window, router.defineRoutes(routes, function(component, args) { renderer.render(root, {tag: component, attrs: args}) }, function() { router.setPath(defaultRoute) - }) + })) + renderer.setEventCallback(replay) redraw.run = replay } diff --git a/test-redraw.html b/test-redraw.html new file mode 100644 index 00000000..bffd0396 --- /dev/null +++ b/test-redraw.html @@ -0,0 +1,57 @@ + + + + + +
+ + + + +