summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorParsa Ghadimi <me@qti3e.com>2018-05-23 23:23:41 +0430
committerRyan Dahl <ry@tinyclouds.org>2018-05-23 17:07:20 -0400
commitcb222ceb227f5a7f5307085bcbebfa3cdb049598 (patch)
tree312f3a1c46af2c668d68881ea62f56ac27d99b9d
parent3171ba4c3ff4046aaca0d70321f1dfec4c0728bb (diff)
Adds setInterval, clearInterval, clearTimeout.
-rw-r--r--globals.ts7
-rw-r--r--msg.proto3
-rw-r--r--testdata/004_set_timeout.ts6
-rw-r--r--testdata/010_set_interval.ts7
-rw-r--r--testdata/010_set_interval.ts.out2
-rw-r--r--timers.go72
-rw-r--r--timers.ts48
7 files changed, 126 insertions, 19 deletions
diff --git a/globals.ts b/globals.ts
index f25cc710b..d38fbf47d 100644
--- a/globals.ts
+++ b/globals.ts
@@ -1,4 +1,4 @@
-import { setTimeout } from "./timers";
+import * as timer from "./timers";
// If you use the eval function indirectly, by invoking it via a reference
// other than eval, as of ECMAScript 5 it works in the global scope rather than
@@ -14,7 +14,10 @@ export const _global = globalEval("this");
_global["window"] = _global; // Create a window object.
import "./url";
-_global["setTimeout"] = setTimeout;
+_global["setTimeout"] = timer.setTimeout;
+_global["setInterval"] = timer.setInterval;
+_global["clearTimeout"] = timer.clearTimer;
+_global["clearInterval"] = timer.clearTimer;
const print = V8Worker2.print;
diff --git a/msg.proto b/msg.proto
index 081b2df8c..68ff52255 100644
--- a/msg.proto
+++ b/msg.proto
@@ -16,6 +16,7 @@ message Msg {
ExitMsg exit = 14;
TimerStartMsg timer_start = 15;
TimerReadyMsg timer_ready = 16;
+ TimerClearMsg timer_clear = 17;
}
}
@@ -60,3 +61,5 @@ message TimerReadyMsg {
optional int32 id = 1;
optional bool done = 2;
}
+
+message TimerClearMsg { optional int32 id = 1; }
diff --git a/testdata/004_set_timeout.ts b/testdata/004_set_timeout.ts
index fe55e31ba..cc55bf76f 100644
--- a/testdata/004_set_timeout.ts
+++ b/testdata/004_set_timeout.ts
@@ -3,3 +3,9 @@ setTimeout(function() {
}, 10);
console.log("Hello");
+
+const id = setTimeout(function() {
+ console.log("Not printed");
+}, 10000);
+
+clearTimeout(id);
diff --git a/testdata/010_set_interval.ts b/testdata/010_set_interval.ts
new file mode 100644
index 000000000..e013d00bc
--- /dev/null
+++ b/testdata/010_set_interval.ts
@@ -0,0 +1,7 @@
+const id = setInterval(function() {
+ console.log("test")
+}, 200);
+
+setTimeout(function() {
+ clearInterval(id)
+}, 500)
diff --git a/testdata/010_set_interval.ts.out b/testdata/010_set_interval.ts.out
new file mode 100644
index 000000000..dec2cbe1f
--- /dev/null
+++ b/testdata/010_set_interval.ts.out
@@ -0,0 +1,2 @@
+test
+test
diff --git a/timers.go b/timers.go
index f9fe28608..6a395adac 100644
--- a/timers.go
+++ b/timers.go
@@ -5,6 +5,16 @@ import (
"time"
)
+type Timer struct {
+ Id int32
+ Done bool
+ Cleared bool
+ Interval bool
+ Duration int32 // In milliseconds
+}
+
+var timers = make(map[int32]*Timer)
+
func InitTimers() {
Sub("timers", func(buf []byte) []byte {
msg := &Msg{}
@@ -12,28 +22,62 @@ func InitTimers() {
switch msg.Payload.(type) {
case *Msg_TimerStart:
payload := msg.GetTimerStart()
- return HandleTimerStart(*payload.Id, *payload.Interval,
- *payload.Duration)
+ timers[*payload.Id] = &Timer{
+ Id: *payload.Id,
+ Done: false,
+ Interval: *payload.Interval,
+ Duration: *payload.Duration,
+ Cleared: false,
+ }
+ timers[*payload.Id].StartTimer()
+ return nil
+ case *Msg_TimerClear:
+ payload := msg.GetTimerClear()
+ // TODO maybe need mutex here.
+ timer := timers[*payload.Id]
+ timer.Clear()
+ return nil
default:
panic("[timers] Unexpected message " + string(buf))
}
})
}
-func HandleTimerStart(id int32, interval bool, duration int32) []byte {
+func (t *Timer) Clear() {
+ if !t.Cleared {
+ wg.Done()
+ t.Cleared = true
+ delete(timers, t.Id)
+ }
+ t.Done = true
+}
+
+func (t *Timer) StartTimer() {
wg.Add(1)
go func() {
- defer wg.Done()
- time.Sleep(time.Duration(duration) * time.Millisecond)
- payload, err := proto.Marshal(&Msg{
- Payload: &Msg_TimerReady{
- TimerReady: &TimerReadyMsg{
- Id: &id,
+ defer t.Clear()
+ for {
+ time.Sleep(time.Duration(t.Duration) * time.Millisecond)
+ if !t.Interval {
+ t.Done = true
+ }
+ pubMsg(&Msg{
+ Payload: &Msg_TimerReady{
+ TimerReady: &TimerReadyMsg{
+ Id: &t.Id,
+ Done: &t.Done,
+ },
},
- },
- })
- check(err)
- Pub("timers", payload)
+ })
+ if t.Done {
+ return
+ }
+ }
}()
- return nil
+}
+
+func pubMsg(msg *Msg) {
+ payload, err := proto.Marshal(msg)
+ check(err)
+ Pub("timers", payload)
}
diff --git a/timers.ts b/timers.ts
index f5f039f1c..5407c63b0 100644
--- a/timers.ts
+++ b/timers.ts
@@ -4,12 +4,14 @@ import * as dispatch from "./dispatch";
let nextTimerId = 1;
// tslint:disable-next-line:no-any
-type TimerCallback = (...args: any[]) => void;
+export type TimerCallback = (...args: any[]) => void;
interface Timer {
id: number;
cb: TimerCallback;
interval: boolean;
+ // tslint:disable-next-line:no-any
+ args: any[];
duration: number; // milliseconds
}
@@ -23,17 +25,26 @@ function onMessage(payload: Uint8Array) {
const msg = pb.Msg.decode(payload);
const { id, done } = msg.timerReady;
const timer = timers.get(id);
- timer.cb();
+ if (!timer) {
+ return;
+ }
+ timer.cb(...timer.args);
if (done) {
timers.delete(id);
}
}
-export function setTimeout(cb: TimerCallback, duration: number): number {
+export function setTimeout(
+ cb: TimerCallback,
+ duration: number,
+ // tslint:disable-next-line:no-any
+ ...args: any[]
+): number {
const timer = {
id: nextTimerId++,
interval: false,
duration,
+ args,
cb
};
timers.set(timer.id, timer);
@@ -46,3 +57,34 @@ export function setTimeout(cb: TimerCallback, duration: number): number {
});
return timer.id;
}
+
+// TODO DRY with setTimeout
+export function setInterval(
+ cb: TimerCallback,
+ repeat: number,
+ // tslint:disable-next-line:no-any
+ ...args: any[]
+): number {
+ const timer = {
+ id: nextTimerId++,
+ interval: true,
+ duration: repeat,
+ args,
+ cb
+ };
+ timers.set(timer.id, timer);
+ dispatch.sendMsg("timers", {
+ timerStart: {
+ id: timer.id,
+ interval: true,
+ duration: repeat
+ }
+ });
+ return timer.id;
+}
+
+export function clearTimer(id: number) {
+ dispatch.sendMsg("timers", {
+ timerClear: { id }
+ });
+}