Fix "dropped" frames for text updates (#224, #339) using @timthelion's insights in #350

* Change the implementation of `notify` so that it does not have a
return value any more.

* Get rid of the only remaning use of the return value of `notify` in
the `every` function.

* Have a "lock" on each round to ensure that no library or runtime
calls `notify` synchronously, causing an update to happen half way
through another update, ultimately leading to a dropped frame.
This commit is contained in:
Evan Czaplicki 2013-11-18 17:22:36 +01:00
parent a49d381c09
commit 704da021b0
3 changed files with 29 additions and 14 deletions

View file

@ -34,13 +34,11 @@ Elm.Native.Time.make = function(elm) {
return A3( Signal.lift2, F2(f), isOn, ticker );
}
function everyWhen(t, isOn) {
function every(t) {
var clock = Signal.constant(Date.now());
var id = setInterval(function tellTime() {
if (!elm.notify(clock.id, Date.now())) {
clearInterval(id);
}
}, t);
setInterval(function() {
elm.notify(clock.id, Date.now());
}, t);
return clock;
}
@ -56,7 +54,7 @@ Elm.Native.Time.make = function(elm) {
return elm.Native.Time.values = {
fpsWhen : F2(fpsWhen),
fps : function(t) { return fpsWhen(t, Signal.constant(true)); },
every : function(t) { return everyWhen(t, Signal.constant(true)) },
every : every,
delay : NS.delay,
timestamp : NS.timestamp,
since : F2(since),

View file

@ -28,10 +28,21 @@ Elm.Native.Window.make = function(elm) {
height.defaultNumberOfKids = 0;
function resizeIfNeeded() {
// Do not trigger event if the dimensions have not changed.
// This should be most of the time.
var w = getWidth();
var h = getHeight();
if (dimensions.value._0 === w && dimensions.value._1 === h) return;
elm.notify(dimensions.id, Tuple2(w,h));
setTimeout(function () {
// Check again to see if the dimensions have changed.
// It is conceivable that the dimensions have changed
// again while some other event was being processed.
var w = getWidth();
var h = getHeight();
if (dimensions.value._0 === w && dimensions.value._1 === h) return;
elm.notify(dimensions.id, Tuple2(w,h));
}, 0);
}
elm.addListener([dimensions.id], window, 'resize', resizeIfNeeded);

View file

@ -31,14 +31,20 @@ function init(display, container, module, moduleToReplace) {
// defining state needed for an instance of the Elm RTS
var inputs = [];
var updateInProgress = false;
function notify(id, v) {
var timestep = Date.now();
var changed = false;
for (var i = inputs.length; i--; ) {
// order is important here to avoid short-circuiting
changed = inputs[i].recv(timestep, id, v) || changed;
if (updateInProgress) {
throw new Error(
'The notify function has been called synchronously!\n' +
'This can lead to frames being dropped.\n' +
'Definitely report this to <https://github.com/evancz/Elm/issues>\n');
}
return changed;
updateInProgress = true;
var timestep = Date.now();
for (var i = inputs.length; i--; ) {
inputs[i].recv(timestep, id, v);
}
updateInProgress = false;
}
var listeners = [];