Make m.redraw() strictly asynchronous
This commit is contained in:
parent
38956e119b
commit
b004c20f0c
11 changed files with 281 additions and 111 deletions
|
|
@ -16,6 +16,6 @@ module.exports = function(redrawService) {
|
|||
redrawService.render(root, Vnode(component))
|
||||
}
|
||||
redrawService.subscribe(root, run)
|
||||
redrawService.redraw()
|
||||
run()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,26 +4,23 @@ var coreRenderer = require("../render/render")
|
|||
|
||||
function throttle(callback) {
|
||||
//60fps translates to 16.6ms, round it down since setTimeout requires int
|
||||
var time = 16
|
||||
var delay = 16
|
||||
var last = 0, pending = null
|
||||
var timeout = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout
|
||||
return function() {
|
||||
var now = Date.now()
|
||||
if (last === 0 || now - last >= time) {
|
||||
last = now
|
||||
callback()
|
||||
}
|
||||
else if (pending === null) {
|
||||
var elapsed = Date.now() - last
|
||||
if (pending === null) {
|
||||
pending = timeout(function() {
|
||||
pending = null
|
||||
callback()
|
||||
last = Date.now()
|
||||
}, time - (now - last))
|
||||
}, delay - elapsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function($window) {
|
||||
module.exports = function($window, throttleMock) {
|
||||
var _throttle = throttleMock || throttle
|
||||
var renderService = coreRenderer($window)
|
||||
renderService.setEventCallback(function(e) {
|
||||
if (e.redraw !== false) redraw()
|
||||
|
|
@ -32,7 +29,7 @@ module.exports = function($window) {
|
|||
var callbacks = []
|
||||
function subscribe(key, callback) {
|
||||
unsubscribe(key)
|
||||
callbacks.push(key, throttle(callback))
|
||||
callbacks.push(key, _throttle(callback))
|
||||
}
|
||||
function unsubscribe(key) {
|
||||
var index = callbacks.indexOf(key)
|
||||
|
|
|
|||
|
|
@ -11,9 +11,14 @@ module.exports = function($window, redrawService) {
|
|||
var render, component, attrs, currentPath, lastUpdate
|
||||
var route = function(root, defaultRoute, routes) {
|
||||
if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined")
|
||||
var run = function() {
|
||||
function run() {
|
||||
if (render != null) redrawService.render(root, render(Vnode(component, attrs.key, attrs)))
|
||||
}
|
||||
var redraw = function() {
|
||||
run()
|
||||
redraw = redrawService.redraw
|
||||
}
|
||||
redrawService.subscribe(root, run)
|
||||
var bail = function(path) {
|
||||
if (path !== defaultRoute) routeService.setPath(defaultRoute, null, {replace: true})
|
||||
else throw new Error("Could not resolve default route " + defaultRoute)
|
||||
|
|
@ -24,7 +29,7 @@ module.exports = function($window, redrawService) {
|
|||
component = comp != null && (typeof comp.view === "function" || typeof comp === "function")? comp : "div"
|
||||
attrs = params, currentPath = path, lastUpdate = null
|
||||
render = (routeResolver.render || identity).bind(routeResolver)
|
||||
run()
|
||||
redraw()
|
||||
}
|
||||
if (payload.view || typeof payload === "function") update({}, payload)
|
||||
else {
|
||||
|
|
@ -36,7 +41,6 @@ module.exports = function($window, redrawService) {
|
|||
else update(payload, "div")
|
||||
}
|
||||
}, bail)
|
||||
redrawService.subscribe(root, run)
|
||||
}
|
||||
route.set = function(path, data, options) {
|
||||
if (lastUpdate != null) options = {replace: true}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
var o = require("../../ospec/ospec")
|
||||
var components = require("../../test-utils/components")
|
||||
var domMock = require("../../test-utils/domMock")
|
||||
var throttleMocker = require("../../test-utils/throttleMock")
|
||||
|
||||
var m = require("../../render/hyperscript")
|
||||
var coreRenderer = require("../../render/render")
|
||||
|
|
@ -11,18 +12,22 @@ var apiMounter = require("../../api/mount")
|
|||
|
||||
o.spec("mount", function() {
|
||||
var FRAME_BUDGET = Math.floor(1000 / 60)
|
||||
var $window, root, redrawService, mount, render
|
||||
var $window, root, redrawService, mount, render, throttleMock
|
||||
|
||||
o.beforeEach(function() {
|
||||
$window = domMock()
|
||||
throttleMock = throttleMocker()
|
||||
|
||||
root = $window.document.body
|
||||
|
||||
redrawService = apiRedraw($window)
|
||||
redrawService = apiRedraw($window, throttleMock.throttle)
|
||||
mount = apiMounter(redrawService)
|
||||
render = coreRenderer($window).render
|
||||
})
|
||||
|
||||
o.afterEach(function() {
|
||||
o(throttleMock.queueLength()).equals(0)
|
||||
})
|
||||
|
||||
o("throws on invalid component", function() {
|
||||
var threw = false
|
||||
try {
|
||||
|
|
@ -69,7 +74,7 @@ o.spec("mount", function() {
|
|||
o(root.childNodes.length).equals(0)
|
||||
})
|
||||
|
||||
o("redraws on events", function(done) {
|
||||
o("redraws on events", function() {
|
||||
var onupdate = o.spy()
|
||||
var oninit = o.spy()
|
||||
var onclick = o.spy()
|
||||
|
|
@ -97,17 +102,12 @@ o.spec("mount", function() {
|
|||
o(onclick.args[0].type).equals("click")
|
||||
o(onclick.args[0].target).equals(root.firstChild)
|
||||
|
||||
// Wrapped to give time for the rate-limited redraw to fire
|
||||
setTimeout(function() {
|
||||
o(onupdate.callCount).equals(1)
|
||||
throttleMock.fire()
|
||||
|
||||
done()
|
||||
}, FRAME_BUDGET)
|
||||
o(onupdate.callCount).equals(1)
|
||||
})
|
||||
|
||||
o("redraws several mount points on events", function(done, timeout) {
|
||||
timeout(60)
|
||||
|
||||
o("redraws several mount points on events", function() {
|
||||
var onupdate0 = o.spy()
|
||||
var oninit0 = o.spy()
|
||||
var onclick0 = o.spy()
|
||||
|
|
@ -154,26 +154,26 @@ o.spec("mount", function() {
|
|||
o(onclick0.callCount).equals(1)
|
||||
o(onclick0.this).equals(root.childNodes[0].firstChild)
|
||||
|
||||
setTimeout(function() {
|
||||
throttleMock.fire()
|
||||
|
||||
o(onupdate0.callCount).equals(1)
|
||||
o(onupdate1.callCount).equals(1)
|
||||
|
||||
root.childNodes[1].firstChild.dispatchEvent(e)
|
||||
|
||||
o(onclick1.callCount).equals(1)
|
||||
o(onclick1.this).equals(root.childNodes[1].firstChild)
|
||||
|
||||
setTimeout(function() {
|
||||
throttleMock.fire()
|
||||
|
||||
o(onupdate0.callCount).equals(2)
|
||||
o(onupdate1.callCount).equals(2)
|
||||
|
||||
done()
|
||||
}, FRAME_BUDGET)
|
||||
}, FRAME_BUDGET)
|
||||
|
||||
})
|
||||
|
||||
o("event handlers can skip redraw", function(done) {
|
||||
var onupdate = o.spy()
|
||||
o("event handlers can skip redraw", function() {
|
||||
var onupdate = o.spy(function(){
|
||||
throw new Error("This shouldn't have been called")
|
||||
})
|
||||
var oninit = o.spy()
|
||||
var e = $window.document.createEvent("MouseEvents")
|
||||
|
||||
|
|
@ -195,15 +195,12 @@ o.spec("mount", function() {
|
|||
|
||||
o(oninit.callCount).equals(1)
|
||||
|
||||
// Wrapped to ensure no redraw fired
|
||||
setTimeout(function() {
|
||||
o(onupdate.callCount).equals(0)
|
||||
throttleMock.fire()
|
||||
|
||||
done()
|
||||
}, FRAME_BUDGET)
|
||||
o(onupdate.callCount).equals(0)
|
||||
})
|
||||
|
||||
o("redraws when the render function is run", function(done) {
|
||||
o("redraws when the render function is run", function() {
|
||||
var onupdate = o.spy()
|
||||
var oninit = o.spy()
|
||||
|
||||
|
|
@ -221,17 +218,12 @@ o.spec("mount", function() {
|
|||
|
||||
redrawService.redraw()
|
||||
|
||||
// Wrapped to give time for the rate-limited redraw to fire
|
||||
setTimeout(function() {
|
||||
o(onupdate.callCount).equals(1)
|
||||
throttleMock.fire()
|
||||
|
||||
done()
|
||||
}, FRAME_BUDGET)
|
||||
o(onupdate.callCount).equals(1)
|
||||
})
|
||||
|
||||
o("throttles", function(done, timeout) {
|
||||
timeout(200)
|
||||
|
||||
o("throttles", function() {
|
||||
var i = 0
|
||||
mount(root, createComponent({view: function() {i++}}))
|
||||
var before = i
|
||||
|
|
@ -243,12 +235,11 @@ o.spec("mount", function() {
|
|||
|
||||
var after = i
|
||||
|
||||
setTimeout(function(){
|
||||
throttleMock.fire()
|
||||
|
||||
o(before).equals(1) // mounts synchronously
|
||||
o(after).equals(1) // throttles rest
|
||||
o(i).equals(2)
|
||||
done()
|
||||
},40)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
var o = require("../../ospec/ospec")
|
||||
var domMock = require("../../test-utils/domMock")
|
||||
var throttleMocker = require("../../test-utils/throttleMock")
|
||||
var apiRedraw = require("../../api/redraw")
|
||||
|
||||
o.spec("redrawService", function() {
|
||||
|
|
@ -17,7 +18,9 @@ o.spec("redrawService", function() {
|
|||
redrawService.redraw()
|
||||
})
|
||||
|
||||
o("should run a single renderer entry", function(done) {
|
||||
o("honours throttleMock", function() {
|
||||
var throttleMock = throttleMocker()
|
||||
redrawService = apiRedraw(domMock(), throttleMock.throttle)
|
||||
var spy = o.spy()
|
||||
|
||||
redrawService.subscribe(root, spy)
|
||||
|
|
@ -26,15 +29,27 @@ o.spec("redrawService", function() {
|
|||
|
||||
redrawService.redraw()
|
||||
|
||||
o(spy.callCount).equals(0)
|
||||
|
||||
throttleMock.fire()
|
||||
|
||||
o(spy.callCount).equals(1)
|
||||
})
|
||||
|
||||
o("should run a single renderer entry", function(done) {
|
||||
var spy = o.spy()
|
||||
|
||||
redrawService.subscribe(root, spy)
|
||||
|
||||
o(spy.callCount).equals(0)
|
||||
|
||||
redrawService.redraw()
|
||||
redrawService.redraw()
|
||||
redrawService.redraw()
|
||||
|
||||
o(spy.callCount).equals(1)
|
||||
o(spy.callCount).equals(0)
|
||||
setTimeout(function() {
|
||||
o(spy.callCount).equals(2)
|
||||
o(spy.callCount).equals(1)
|
||||
|
||||
done()
|
||||
}, 20)
|
||||
|
|
@ -54,27 +69,29 @@ o.spec("redrawService", function() {
|
|||
|
||||
redrawService.redraw()
|
||||
|
||||
o(spy1.callCount).equals(1)
|
||||
o(spy2.callCount).equals(1)
|
||||
o(spy3.callCount).equals(1)
|
||||
o(spy1.callCount).equals(0)
|
||||
o(spy2.callCount).equals(0)
|
||||
o(spy3.callCount).equals(0)
|
||||
|
||||
redrawService.redraw()
|
||||
|
||||
o(spy1.callCount).equals(0)
|
||||
o(spy2.callCount).equals(0)
|
||||
o(spy3.callCount).equals(0)
|
||||
|
||||
setTimeout(function() {
|
||||
o(spy1.callCount).equals(1)
|
||||
o(spy2.callCount).equals(1)
|
||||
o(spy3.callCount).equals(1)
|
||||
|
||||
setTimeout(function() {
|
||||
o(spy1.callCount).equals(2)
|
||||
o(spy2.callCount).equals(2)
|
||||
o(spy3.callCount).equals(2)
|
||||
|
||||
done()
|
||||
}, 20)
|
||||
})
|
||||
|
||||
o("should stop running after unsubscribe", function() {
|
||||
var spy = o.spy()
|
||||
o("should stop running after unsubscribe", function(done) {
|
||||
var spy = o.spy(function() {
|
||||
throw new Error("This shouldn't have been called")
|
||||
})
|
||||
|
||||
redrawService.subscribe(root, spy)
|
||||
redrawService.unsubscribe(root, spy)
|
||||
|
|
@ -82,9 +99,14 @@ o.spec("redrawService", function() {
|
|||
redrawService.redraw()
|
||||
|
||||
o(spy.callCount).equals(0)
|
||||
setTimeout(function() {
|
||||
o(spy.callCount).equals(0)
|
||||
|
||||
done()
|
||||
}, 20)
|
||||
})
|
||||
|
||||
o("does nothing on invalid unsubscribe", function() {
|
||||
o("does nothing on invalid unsubscribe", function(done) {
|
||||
var spy = o.spy()
|
||||
|
||||
redrawService.subscribe(root, spy)
|
||||
|
|
@ -92,6 +114,10 @@ o.spec("redrawService", function() {
|
|||
|
||||
redrawService.redraw()
|
||||
|
||||
setTimeout(function() {
|
||||
o(spy.callCount).equals(1)
|
||||
|
||||
done()
|
||||
}, 20)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
var o = require("../../ospec/ospec")
|
||||
var callAsync = require("../../test-utils/callAsync")
|
||||
var browserMock = require("../../test-utils/browserMock")
|
||||
var throttleMocker = require("../../test-utils/throttleMock")
|
||||
|
||||
var m = require("../../render/hyperscript")
|
||||
var callAsync = require("../../test-utils/callAsync")
|
||||
|
|
@ -15,18 +16,23 @@ o.spec("route", function() {
|
|||
void ["#", "?", "", "#!", "?!", "/foo"].forEach(function(prefix) {
|
||||
o.spec("using prefix `" + prefix + "` starting on " + env.protocol + "//" + env.hostname, function() {
|
||||
var FRAME_BUDGET = Math.floor(1000 / 60)
|
||||
var $window, root, redrawService, route
|
||||
var $window, root, redrawService, route, throttleMock
|
||||
|
||||
o.beforeEach(function() {
|
||||
$window = browserMock(env)
|
||||
throttleMock = throttleMocker()
|
||||
|
||||
root = $window.document.body
|
||||
|
||||
redrawService = apiRedraw($window)
|
||||
redrawService = apiRedraw($window, throttleMock.throttle)
|
||||
route = apiRouter($window, redrawService)
|
||||
route.prefix(prefix)
|
||||
})
|
||||
|
||||
o.afterEach(function() {
|
||||
o(throttleMock.queueLength()).equals(0)
|
||||
})
|
||||
|
||||
o("throws on invalid `root` DOM node", function() {
|
||||
var threw = false
|
||||
try {
|
||||
|
|
@ -50,7 +56,7 @@ o.spec("route", function() {
|
|||
o(root.firstChild.nodeName).equals("DIV")
|
||||
})
|
||||
|
||||
o("routed mount points can redraw synchronously (POJO component)", function() {
|
||||
o("routed mount points only redraw asynchronously (POJO component)", function() {
|
||||
var view = o.spy()
|
||||
|
||||
$window.location.href = prefix + "/"
|
||||
|
|
@ -60,11 +66,14 @@ o.spec("route", function() {
|
|||
|
||||
redrawService.redraw()
|
||||
|
||||
o(view.callCount).equals(2)
|
||||
o(view.callCount).equals(1)
|
||||
|
||||
throttleMock.fire()
|
||||
|
||||
o(view.callCount).equals(2)
|
||||
})
|
||||
|
||||
o("routed mount points can redraw synchronously (constructible component)", function() {
|
||||
o("routed mount points only redraw asynchronously (constructible component)", function() {
|
||||
var view = o.spy()
|
||||
|
||||
var Cmp = function(){}
|
||||
|
|
@ -77,11 +86,14 @@ o.spec("route", function() {
|
|||
|
||||
redrawService.redraw()
|
||||
|
||||
o(view.callCount).equals(2)
|
||||
o(view.callCount).equals(1)
|
||||
|
||||
throttleMock.fire()
|
||||
|
||||
o(view.callCount).equals(2)
|
||||
})
|
||||
|
||||
o("routed mount points can redraw synchronously (closure component)", function() {
|
||||
o("routed mount points only redraw asynchronously (closure component)", function() {
|
||||
var view = o.spy()
|
||||
|
||||
function Cmp() {return {view: view}}
|
||||
|
|
@ -93,8 +105,11 @@ o.spec("route", function() {
|
|||
|
||||
redrawService.redraw()
|
||||
|
||||
o(view.callCount).equals(2)
|
||||
o(view.callCount).equals(1)
|
||||
|
||||
throttleMock.fire()
|
||||
|
||||
o(view.callCount).equals(2)
|
||||
})
|
||||
|
||||
o("default route doesn't break back button", function(done) {
|
||||
|
|
@ -160,11 +175,12 @@ o.spec("route", function() {
|
|||
o(oninit.callCount).equals(1)
|
||||
|
||||
redrawService.redraw()
|
||||
throttleMock.fire()
|
||||
|
||||
o(onupdate.callCount).equals(1)
|
||||
})
|
||||
|
||||
o("redraws on events", function(done) {
|
||||
o("redraws on events", function() {
|
||||
var onupdate = o.spy()
|
||||
var oninit = o.spy()
|
||||
var onclick = o.spy()
|
||||
|
|
@ -194,12 +210,9 @@ o.spec("route", function() {
|
|||
o(onclick.args[0].type).equals("click")
|
||||
o(onclick.args[0].target).equals(root.firstChild)
|
||||
|
||||
// Wrapped to give time for the rate-limited redraw to fire
|
||||
callAsync(function() {
|
||||
o(onupdate.callCount).equals(1)
|
||||
|
||||
done()
|
||||
})
|
||||
throttleMock.fire()
|
||||
o(onupdate.callCount).equals(1)
|
||||
})
|
||||
|
||||
o("event handlers can skip redraw", function(done) {
|
||||
|
|
@ -500,7 +513,10 @@ o.spec("route", function() {
|
|||
o(oninit.callCount).equals(1)
|
||||
route.set("/def")
|
||||
callAsync(function() {
|
||||
throttleMock.fire()
|
||||
|
||||
o(oninit.callCount).equals(2)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
|
@ -536,23 +552,28 @@ o.spec("route", function() {
|
|||
route(root, "/a", {
|
||||
"/a" : {
|
||||
render: function() {
|
||||
return m("div")
|
||||
return m("div", m('p'))
|
||||
},
|
||||
},
|
||||
"/b" : {
|
||||
render: function() {
|
||||
return m("div")
|
||||
return m("div", m('a'))
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
var dom = root.firstChild
|
||||
var child = dom.firstChild
|
||||
|
||||
o(root.firstChild.nodeName).equals("DIV")
|
||||
|
||||
route.set("/b")
|
||||
|
||||
callAsync(function() {
|
||||
throttleMock.fire()
|
||||
|
||||
o(root.firstChild).equals(dom)
|
||||
o(root.firstChild.firstChild).notEquals(child)
|
||||
|
||||
done()
|
||||
})
|
||||
|
|
@ -586,6 +607,7 @@ o.spec("route", function() {
|
|||
o(renderCount).equals(1)
|
||||
|
||||
redrawService.redraw()
|
||||
throttleMock.fire()
|
||||
|
||||
o(matchCount).equals(1)
|
||||
o(renderCount).equals(2)
|
||||
|
|
@ -621,6 +643,7 @@ o.spec("route", function() {
|
|||
o(renderCount).equals(1)
|
||||
|
||||
redrawService.redraw()
|
||||
throttleMock.fire()
|
||||
|
||||
o(matchCount).equals(1)
|
||||
o(renderCount).equals(2)
|
||||
|
|
@ -815,10 +838,14 @@ o.spec("route", function() {
|
|||
})
|
||||
|
||||
callAsync(function() {
|
||||
route.set("/b")
|
||||
throttleMock.fire()
|
||||
|
||||
route.set('/b')
|
||||
callAsync(function() {
|
||||
callAsync(function() {
|
||||
callAsync(function() {
|
||||
throttleMock.fire()
|
||||
|
||||
o(render.callCount).equals(0)
|
||||
o(component.view.callCount).equals(2)
|
||||
|
||||
|
|
@ -939,6 +966,7 @@ o.spec("route", function() {
|
|||
o(onmatch.callCount).equals(1)
|
||||
|
||||
redrawService.redraw()
|
||||
throttleMock.fire()
|
||||
|
||||
o(view.callCount).equals(2)
|
||||
o(onmatch.callCount).equals(1)
|
||||
|
|
@ -1017,6 +1045,8 @@ o.spec("route", function() {
|
|||
})
|
||||
|
||||
callAsync(function() {
|
||||
throttleMock.fire()
|
||||
|
||||
o(onmatch.callCount).equals(1)
|
||||
o(render.callCount).equals(1)
|
||||
|
||||
|
|
@ -1024,6 +1054,8 @@ o.spec("route", function() {
|
|||
|
||||
callAsync(function() {
|
||||
callAsync(function() {
|
||||
throttleMock.fire()
|
||||
|
||||
o(onmatch.callCount).equals(2)
|
||||
o(render.callCount).equals(2)
|
||||
|
||||
|
|
@ -1074,9 +1106,15 @@ o.spec("route", function() {
|
|||
route.set("/b")
|
||||
|
||||
callAsync(function() {
|
||||
route.set("/a")
|
||||
throttleMock.fire()
|
||||
|
||||
o(root.firstChild.nodeName).equals("B")
|
||||
|
||||
route.set('/a')
|
||||
|
||||
callAsync(function() {
|
||||
throttleMock.fire()
|
||||
|
||||
o(root.firstChild.nodeName).equals("A")
|
||||
|
||||
done()
|
||||
|
|
@ -1141,7 +1179,9 @@ o.spec("route", function() {
|
|||
|
||||
route.set("/b")
|
||||
|
||||
// setting the route is asynchronous
|
||||
callAsync(function() {
|
||||
throttleMock.fire()
|
||||
o(spy.callCount).equals(1)
|
||||
|
||||
done()
|
||||
|
|
@ -1181,9 +1221,7 @@ o.spec("route", function() {
|
|||
})
|
||||
})
|
||||
|
||||
o("throttles", function(done, timeout) {
|
||||
timeout(200)
|
||||
|
||||
o("throttles", function() {
|
||||
var i = 0
|
||||
$window.location.href = prefix + "/"
|
||||
route(root, "/", {
|
||||
|
|
@ -1197,12 +1235,11 @@ o.spec("route", function() {
|
|||
redrawService.redraw()
|
||||
var after = i
|
||||
|
||||
setTimeout(function() {
|
||||
throttleMock.fire()
|
||||
|
||||
o(before).equals(1) // routes synchronously
|
||||
o(after).equals(2) // redraws synchronously
|
||||
o(i).equals(3) // throttles rest
|
||||
done()
|
||||
}, FRAME_BUDGET * 2)
|
||||
o(after).equals(1) // redraws asynchronously
|
||||
o(i).equals(2)
|
||||
})
|
||||
|
||||
o("m.route.param is available outside of route handlers", function(done) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ You DON'T need to call it if data is modified within the execution context of an
|
|||
|
||||
You DO need to call it in `setTimeout`/`setInterval`/`requestAnimationFrame` callbacks, or callbacks from 3rd party libraries.
|
||||
|
||||
Typically, `m.redraw` triggers an asynchronous redraws, but it may trigger synchronously if Mithril detects it's possible to improve performance by doing so (i.e. if no redraw was requested within the last animation frame). You should write code assuming that it always redraws asynchronously.
|
||||
`m.redraw` always triggers an asynchronous redraws.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ Argument | Type | Required | D
|
|||
|
||||
##### m.route.set
|
||||
|
||||
Redirects to a matching route, or to the default route if no matching routes can be found.
|
||||
Redirects to a matching route, or to the default route if no matching routes can be found. Triggers an asynchronous redraw off all mount points.
|
||||
|
||||
`m.route.set(path, data, options)`
|
||||
|
||||
|
|
|
|||
89
test-utils/tests/test-throttleMock.js
Normal file
89
test-utils/tests/test-throttleMock.js
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
var o = require("../../ospec/ospec")
|
||||
var throttleMocker = require("../../test-utils/throttleMock")
|
||||
|
||||
o.spec("throttleMock", function() {
|
||||
o("works with one callback", function() {
|
||||
var throttleMock = throttleMocker()
|
||||
var spy = o.spy()
|
||||
|
||||
o(throttleMock.queueLength()).equals(0)
|
||||
|
||||
var throttled = throttleMock.throttle(spy)
|
||||
|
||||
o(throttleMock.queueLength()).equals(0)
|
||||
o(spy.callCount).equals(0)
|
||||
|
||||
throttled()
|
||||
|
||||
o(throttleMock.queueLength()).equals(1)
|
||||
o(spy.callCount).equals(0)
|
||||
|
||||
throttled()
|
||||
|
||||
o(throttleMock.queueLength()).equals(1)
|
||||
o(spy.callCount).equals(0)
|
||||
|
||||
throttleMock.fire()
|
||||
|
||||
o(throttleMock.queueLength()).equals(0)
|
||||
o(spy.callCount).equals(1)
|
||||
|
||||
throttleMock.fire()
|
||||
|
||||
o(spy.callCount).equals(1)
|
||||
})
|
||||
o("works with two callbacks", function() {
|
||||
var throttleMock = throttleMocker()
|
||||
var spy1 = o.spy()
|
||||
var spy2 = o.spy()
|
||||
|
||||
o(throttleMock.queueLength()).equals(0)
|
||||
|
||||
var throttled1 = throttleMock.throttle(spy1)
|
||||
|
||||
o(throttleMock.queueLength()).equals(0)
|
||||
o(spy1.callCount).equals(0)
|
||||
o(spy2.callCount).equals(0)
|
||||
|
||||
throttled1()
|
||||
|
||||
o(throttleMock.queueLength()).equals(1)
|
||||
o(spy1.callCount).equals(0)
|
||||
o(spy2.callCount).equals(0)
|
||||
|
||||
throttled1()
|
||||
|
||||
o(throttleMock.queueLength()).equals(1)
|
||||
o(spy1.callCount).equals(0)
|
||||
o(spy2.callCount).equals(0)
|
||||
|
||||
var throttled2 = throttleMock.throttle(spy2)
|
||||
|
||||
o(throttleMock.queueLength()).equals(1)
|
||||
o(spy1.callCount).equals(0)
|
||||
o(spy2.callCount).equals(0)
|
||||
|
||||
throttled2()
|
||||
|
||||
o(throttleMock.queueLength()).equals(2)
|
||||
o(spy1.callCount).equals(0)
|
||||
o(spy2.callCount).equals(0)
|
||||
|
||||
throttled2()
|
||||
|
||||
o(throttleMock.queueLength()).equals(2)
|
||||
o(spy1.callCount).equals(0)
|
||||
o(spy2.callCount).equals(0)
|
||||
|
||||
throttleMock.fire()
|
||||
|
||||
o(throttleMock.queueLength()).equals(0)
|
||||
o(spy1.callCount).equals(1)
|
||||
o(spy2.callCount).equals(1)
|
||||
|
||||
throttleMock.fire()
|
||||
|
||||
o(spy1.callCount).equals(1)
|
||||
o(spy2.callCount).equals(1)
|
||||
})
|
||||
})
|
||||
24
test-utils/throttleMock.js
Normal file
24
test-utils/throttleMock.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
module.exports = function() {
|
||||
var queue = []
|
||||
return {
|
||||
throttle: function(fn) {
|
||||
var pending = false
|
||||
return function() {
|
||||
if (!pending) {
|
||||
queue.push(function(){
|
||||
pending = false
|
||||
fn()
|
||||
})
|
||||
pending = true
|
||||
}
|
||||
}
|
||||
},
|
||||
fire: function() {
|
||||
queue.forEach(function(fn) {fn()})
|
||||
queue.length = 0
|
||||
},
|
||||
queueLength: function(){
|
||||
return queue.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -163,8 +163,10 @@ o.spec("api", function() {
|
|||
var count = 0
|
||||
var root = window.document.createElement("div")
|
||||
m.mount(root, createComponent({view: function() {count++}}))
|
||||
setTimeout(function() {
|
||||
o(count).equals(1)
|
||||
m.redraw()
|
||||
o(count).equals(1)
|
||||
setTimeout(function() {
|
||||
|
||||
o(count).equals(2)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue