forked from swiftwasm/JavaScriptKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJSTimer.swift
More file actions
68 lines (64 loc) · 3.22 KB
/
JSTimer.swift
File metadata and controls
68 lines (64 loc) · 3.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/** This timer is an abstraction over [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval)
/ [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval) and
[`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout)
/ [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout)
JavaScript functions. It intentionally doesn't match the JavaScript API, as a special care is
needed to hold a reference to the timer closure and to call `JSClosure.release()` on it when the
timer is deallocated. As a user, you have to hold a reference to a `JSTimer` instance for it to stay
valid. The `JSTimer` API is also intentionally trivial, the timer is started right away, and the
only way to invalidate the timer is to bring the reference count of the `JSTimer` instance to zero.
For invalidation you should either store the timer in an optional property and assign `nil` to it,
or deallocate the object that owns the timer.
*/
public final class JSTimer {
/// Indicates whether this timer instance calls its callback repeatedly at a given delay.
public let isRepeating: Bool
private let closure: JSClosureProtocol
/** Node.js and browser APIs are slightly different. `setTimeout`/`setInterval` return an object
in Node.js, while browsers return a number. Fortunately, clearTimeout and clearInterval take
corresponding types as their arguments, and we can store either as JSValue, so we can treat both
cases uniformly.
*/
private let value: JSValue
private let global = JSObject.global
/**
Creates a new timer instance that calls `setInterval` or `setTimeout` JavaScript functions for you
under the hood.
- Parameters:
- millisecondsDelay: the amount of milliseconds before the `callback` closure is executed.
- isRepeating: when `true` the `callback` closure is executed repeatedly at given
`millisecondsDelay` intervals indefinitely until the timer is deallocated.
- callback: the closure to be executed after a given `millisecondsDelay` interval.
*/
public init(millisecondsDelay: Double, isRepeating: Bool = false, callback: @escaping () -> ()) {
if isRepeating {
closure = JSClosure { _ in
callback()
return .undefined
}
} else {
closure = JSOneshotClosure { _ in
callback()
return .undefined
}
}
self.isRepeating = isRepeating
if isRepeating {
value = global.setInterval.function!(closure, millisecondsDelay)
} else {
value = global.setTimeout.function!(closure, millisecondsDelay)
}
}
/** Makes a corresponding `clearTimeout` or `clearInterval` call, depending on whether this timer
instance is repeating. The `closure` instance is released manually here, as it is required for
bridged closure instances.
*/
deinit {
if isRepeating {
global.clearInterval.function!(value)
} else {
global.clearTimeout.function!(value)
}
closure.release()
}
}