Skip to content

Commit a9b8b6d

Browse files
committed
JS functions clearTimeout() and clearInterval() checking for positive jobId's before trying to find the job (issue #1141)
1 parent 9b6854e commit a9b8b6d

2 files changed

Lines changed: 55 additions & 16 deletions

File tree

src/changes/changes.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
<body>
1010
<release version="5.3.0" date="July xx, 2026" description="Bugfixes">
11+
<action type="update" dev="rbri">
12+
JS functions clearTimeout() and clearInterval() checking for positive jobId's before trying
13+
to find the job (job id's are always positive).
14+
</action>
1115
<action type="fix" dev="rbri" issue="#1141">
1216
Remove the 'cancelledJobs_' list from JavaScriptJobManagerImpl; this is not needed at all and
1317
the root of a memory leak for some web pages.

src/main/java/org/htmlunit/javascript/host/Window.java

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -532,34 +532,69 @@ public static Object setInterval(final Context context, final VarScope scope,
532532
}
533533

534534
/**
535-
* Cancels a time-out previously set with the
536-
* {@link #setTimeout(Context, VarScope, Scriptable, Object[], Function)} method.
535+
* Cancels a one-time timeout that was previously established by a call to
536+
* {@link #setTimeout(Context, VarScope, Scriptable, Object[], Function)}.
537537
*
538-
* @param timeoutId identifier for the timeout to clear
539-
* as returned by {@link #setTimeout(Context, VarScope, Scriptable, Object[], Function)}
538+
* <p>If {@code timeoutId} is {@code 0} or negative, this method does nothing,
539+
* since valid job IDs are always positive integers. This matches browser behavior
540+
* where {@code clearTimeout(0)} is a safe no-op, commonly used when {@code 0}
541+
* is employed as a sentinel value to indicate "no active timeout".</p>
542+
*
543+
* <p>If the given ID does not correspond to any active timeout (e.g. it has
544+
* already fired or been cancelled), this method returns silently without
545+
* throwing an error, consistent with the HTML Living Standard.</p>
546+
*
547+
* @param timeoutId the ID of the timeout to cancel, as returned by
548+
* {@link #setTimeout(Context, VarScope, Scriptable, Object[], Function)};
549+
* values of {@code 0} or less are ignored
550+
* @see #setTimeout(Context, VarScope, Scriptable, Object[], Function)
551+
* @see #clearInterval(int)
552+
* @see <a href="https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-cleartimeout">
553+
* HTML Living Standard – clearTimeout</a>
554+
* @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout">
555+
* MDN Web Docs – clearTimeout</a>
540556
*/
541557
@JsxFunction
542558
public void clearTimeout(final int timeoutId) {
543-
if (LOG.isDebugEnabled()) {
544-
LOG.debug("clearTimeout(" + timeoutId + ")");
559+
if (timeoutId > 0) {
560+
if (LOG.isDebugEnabled()) {
561+
LOG.debug("clearTimeout(" + timeoutId + ")");
562+
}
563+
getWebWindow().getJobManager().removeJob(timeoutId);
545564
}
546-
getWebWindow().getJobManager().removeJob(timeoutId);
547565
}
548566

549567
/**
550-
* Cancels the interval previously started using the
551-
* {@link #setInterval(Context, VarScope, Scriptable, Object[], Function)} method.
552-
* Current implementation does nothing.
553-
* @param intervalID specifies the interval to cancel as returned by the
554-
* {@link #setInterval(Context, VarScope, Scriptable, Object[], Function)} method
555-
* @see <a href="http://msdn.microsoft.com/en-us/library/ms536353.aspx">MSDN documentation</a>
568+
* Cancels a repeating interval that was previously established by a call to
569+
* {@link #setInterval(Context, VarScope, Scriptable, Object[], Function)}.
570+
*
571+
* <p>If {@code intervalID} is {@code 0} or negative, this method does nothing,
572+
* since valid job IDs are always positive integers. This matches browser behavior
573+
* where {@code clearInterval(0)} is a safe no-op, commonly used when {@code 0}
574+
* is employed as a sentinel value to indicate "no active interval".</p>
575+
*
576+
* <p>If the given ID does not correspond to any active interval (e.g. it has
577+
* already fired or been cancelled), this method returns silently without
578+
* throwing an error, consistent with the HTML Living Standard.</p>
579+
*
580+
* @param intervalID the ID of the interval to cancel, as returned by
581+
* {@link #setInterval(Context, VarScope, Scriptable, Object[], Function)};
582+
* values of {@code 0} or less are ignored
583+
* @see #setInterval(Context, VarScope, Scriptable, Object[], Function)
584+
* @see #clearTimeout(int)
585+
* @see <a href="https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-clearinterval">
586+
* HTML Living Standard – clearInterval</a>
587+
* @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/clearInterval">
588+
* MDN Web Docs – clearInterval</a>
556589
*/
557590
@JsxFunction
558591
public void clearInterval(final int intervalID) {
559-
if (LOG.isDebugEnabled()) {
560-
LOG.debug("clearInterval(" + intervalID + ")");
592+
if (intervalID > 0) {
593+
if (LOG.isDebugEnabled()) {
594+
LOG.debug("clearInterval(" + intervalID + ")");
595+
}
596+
getWebWindow().getJobManager().removeJob(intervalID);
561597
}
562-
getWebWindow().getJobManager().removeJob(intervalID);
563598
}
564599

565600
/**

0 commit comments

Comments
 (0)