Frame-rate limiter for m.mount/m.route
This commit is contained in:
parent
5ec06e7c08
commit
db609b9142
5 changed files with 147 additions and 13 deletions
35
limiter.js
Normal file
35
limiter.js
Normal file
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
51
mithril.js
51
mithril.js
|
|
@ -575,21 +575,58 @@ var createRenderer = function($window) {
|
||||||
return {render: render, setEventCallback: setEventCallback}
|
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) {
|
var createMounter = function($window, redraw) {
|
||||||
return function(root, component) {
|
return function(root, component) {
|
||||||
var renderer = createRenderer($window)
|
var renderer = createRenderer($window)
|
||||||
renderer.setEventCallback(draw)
|
var draw = limiter($window, function draw() {
|
||||||
|
|
||||||
function draw() {
|
|
||||||
renderer.render(root, {tag: component})
|
renderer.render(root, {tag: component})
|
||||||
}
|
})
|
||||||
|
|
||||||
|
renderer.setEventCallback(draw)
|
||||||
|
|
||||||
redraw.run = draw
|
redraw.run = draw
|
||||||
draw()
|
draw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var buildQueryString = function buildQueryString(object) {
|
var buildQueryString = function buildQueryString(object) {
|
||||||
if (Object.prototype.toString.call(object) !== "[object Object]") return ""
|
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}
|
return {setPrefix: setPrefix, getPath: getPath, setPath: setPath, defineRoutes: defineRoutes, link: link}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var createRouterInstance = function($window, redraw) {
|
var createRouterInstance = function($window, redraw) {
|
||||||
var renderer = createRenderer($window)
|
var renderer = createRenderer($window)
|
||||||
var router = createRouter($window)
|
var router = createRouter($window)
|
||||||
var route = function(root, defaultRoute, routes) {
|
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})
|
renderer.render(root, {tag: component, attrs: args})
|
||||||
}, function() {
|
}, function() {
|
||||||
router.setPath(defaultRoute)
|
router.setPath(defaultRoute)
|
||||||
})
|
}))
|
||||||
|
|
||||||
renderer.setEventCallback(replay)
|
renderer.setEventCallback(replay)
|
||||||
redraw.run = replay
|
redraw.run = replay
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
mount.js
11
mount.js
|
|
@ -1,15 +1,16 @@
|
||||||
var createRenderer = require("./render/render")
|
var createRenderer = require("./render/render")
|
||||||
|
var limiter = require("./limiter");
|
||||||
|
|
||||||
module.exports = function($window, redraw) {
|
module.exports = function($window, redraw) {
|
||||||
return function(root, component) {
|
return function(root, component) {
|
||||||
var renderer = createRenderer($window)
|
var renderer = createRenderer($window)
|
||||||
renderer.setEventCallback(draw)
|
var draw = limiter($window, function draw() {
|
||||||
|
|
||||||
function draw() {
|
|
||||||
renderer.render(root, {tag: component})
|
renderer.render(root, {tag: component})
|
||||||
}
|
})
|
||||||
|
|
||||||
|
renderer.setEventCallback(draw)
|
||||||
|
|
||||||
redraw.run = draw
|
redraw.run = draw
|
||||||
draw()
|
draw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
var createRenderer = require("./render/render")
|
var createRenderer = require("./render/render")
|
||||||
var createRouter = require("./router/router")
|
var createRouter = require("./router/router")
|
||||||
|
var limiter = require("./limiter")
|
||||||
|
|
||||||
module.exports = function($window, redraw) {
|
module.exports = function($window, redraw) {
|
||||||
var renderer = createRenderer($window)
|
var renderer = createRenderer($window)
|
||||||
var router = createRouter($window)
|
var router = createRouter($window)
|
||||||
var route = function(root, defaultRoute, routes) {
|
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})
|
renderer.render(root, {tag: component, attrs: args})
|
||||||
}, function() {
|
}, function() {
|
||||||
router.setPath(defaultRoute)
|
router.setPath(defaultRoute)
|
||||||
})
|
}))
|
||||||
|
|
||||||
renderer.setEventCallback(replay)
|
renderer.setEventCallback(replay)
|
||||||
redraw.run = replay
|
redraw.run = replay
|
||||||
}
|
}
|
||||||
|
|
|
||||||
57
test-redraw.html
Normal file
57
test-redraw.html
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mount {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outer {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
height: 99999px;
|
||||||
|
background: #CCC;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div class="mount"></div>
|
||||||
|
<script src="./module/module.js"></script>
|
||||||
|
<script src="./mithril.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var m = require("./mithril")
|
||||||
|
|
||||||
|
var last = 0
|
||||||
|
|
||||||
|
m.mount(document.querySelector(".mount"), {
|
||||||
|
view : function() {
|
||||||
|
var now = performance.now()
|
||||||
|
console.log("draw", now - last)
|
||||||
|
last = now
|
||||||
|
|
||||||
|
return m(".outer", {
|
||||||
|
onscroll : function() {
|
||||||
|
// Unused except to trigger redraws
|
||||||
|
}
|
||||||
|
},
|
||||||
|
m(".inner",
|
||||||
|
m("p", "Scroll me")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue