From 1769de903392ab14ffb6c366ab86dc24b5289e81 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Thu, 19 Nov 2020 18:07:51 -0300 Subject: [PATCH] feat(android): setInterval closer to web spec (#9044) --- apps/automated/src/timer/timer-tests.ts | 34 +++++++++++++++++++++++++ packages/core/timer/index.android.ts | 8 ++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/apps/automated/src/timer/timer-tests.ts b/apps/automated/src/timer/timer-tests.ts index 99c633828..4f8f10bbb 100644 --- a/apps/automated/src/timer/timer-tests.ts +++ b/apps/automated/src/timer/timer-tests.ts @@ -171,6 +171,40 @@ export function test_setInterval_callbackCalledWithExtraArgs(done) { ); } +export function test_setInterval_callbackNotDelayedByBusyWork() { + let calls = 0; + + let firstCall = true; + const id = timer.setInterval(() => { + calls++; + if (firstCall) { + firstCall = false; + TKUnit.wait(0.025); + } + }, 50); + + TKUnit.wait(0.11); + timer.clearInterval(id); + TKUnit.assertEqual(calls, 2, 'Callback should be called multiple times with busy wait'); +} + +export function test_setInterval_callbackSkippedByBusyWork() { + let calls = 0; + + let firstCall = true; + const id = timer.setInterval(() => { + calls++; + if (firstCall) { + firstCall = false; + TKUnit.wait(0.051); + } + }, 50); + + TKUnit.wait(0.16); + timer.clearInterval(id); + TKUnit.assertEqual(calls, 2, 'Callback should be called skipped when it takes too long to process'); +} + export function test_setInterval_callbackShouldBeCleared(done) { const start = TKUnit.time(); // >> timer-set-interval diff --git a/packages/core/timer/index.android.ts b/packages/core/timer/index.android.ts index 06d42d958..8bf793113 100644 --- a/packages/core/timer/index.android.ts +++ b/packages/core/timer/index.android.ts @@ -58,12 +58,16 @@ export function setInterval(callback: Function, milliseconds = 0, ...args): numb const handler = timeoutHandler; const invoke = () => callback(...args); const zoneBound = zonedCallback(invoke); + const startOffset = milliseconds > 0 ? Date.now() % milliseconds : 0; + function nextCallMs() { + return milliseconds > 0 ? milliseconds - ((Date.now() - startOffset) % milliseconds) : milliseconds; + } const runnable = new java.lang.Runnable({ run: () => { zoneBound(); if (timeoutCallbacks[id]) { - handler.postDelayed(runnable, long(milliseconds)); + handler.postDelayed(runnable, long(nextCallMs())); } }, }); @@ -72,7 +76,7 @@ export function setInterval(callback: Function, milliseconds = 0, ...args): numb timeoutCallbacks[id] = runnable; } - timeoutHandler.postDelayed(runnable, long(milliseconds)); + timeoutHandler.postDelayed(runnable, long(nextCallMs())); return id; }