mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
First pass at setTimeout
This commit is contained in:
parent
360c50b52e
commit
0a46a3e35b
8 changed files with 117 additions and 2 deletions
1
Makefile
1
Makefile
|
@ -4,6 +4,7 @@ TS_FILES = \
|
||||||
msg.pb.js \
|
msg.pb.js \
|
||||||
os.ts \
|
os.ts \
|
||||||
runtime.ts \
|
runtime.ts \
|
||||||
|
timers.ts \
|
||||||
util.ts
|
util.ts
|
||||||
|
|
||||||
deno: assets.go msg.pb.go main.go
|
deno: assets.go msg.pb.go main.go
|
||||||
|
|
49
main.go
49
main.go
|
@ -9,8 +9,13 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var resChan chan *Msg
|
||||||
|
|
||||||
func SourceCodeHash(filename string, sourceCodeBuf []byte) string {
|
func SourceCodeHash(filename string, sourceCodeBuf []byte) string {
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
h.Write([]byte(filename))
|
h.Write([]byte(filename))
|
||||||
|
@ -70,6 +75,22 @@ func HandleSourceCodeCache(filename string, sourceCode string,
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HandleTimerStart(id int32, interval bool, duration int32) []byte {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
time.Sleep(time.Duration(duration) * time.Millisecond)
|
||||||
|
resChan <- &Msg{
|
||||||
|
Payload: &Msg_TimerReady{
|
||||||
|
TimerReady: &TimerReadyMsg{
|
||||||
|
Id: id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func UserHomeDir() string {
|
func UserHomeDir() string {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
||||||
|
@ -121,7 +142,11 @@ func recv(buf []byte) []byte {
|
||||||
return HandleSourceCodeFetch(payload.Filename)
|
return HandleSourceCodeFetch(payload.Filename)
|
||||||
case *Msg_SourceCodeCache:
|
case *Msg_SourceCodeCache:
|
||||||
payload := msg.GetSourceCodeCache()
|
payload := msg.GetSourceCodeCache()
|
||||||
return HandleSourceCodeCache(payload.Filename, payload.SourceCode, payload.OutputCode)
|
return HandleSourceCodeCache(payload.Filename, payload.SourceCode,
|
||||||
|
payload.OutputCode)
|
||||||
|
case *Msg_TimerStart:
|
||||||
|
payload := msg.GetTimerStart()
|
||||||
|
return HandleTimerStart(payload.Id, payload.Interval, payload.Duration)
|
||||||
default:
|
default:
|
||||||
panic("Unexpected message")
|
panic("Unexpected message")
|
||||||
}
|
}
|
||||||
|
@ -137,6 +162,9 @@ func main() {
|
||||||
cwd, err := os.Getwd()
|
cwd, err := os.Getwd()
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
|
resChan = make(chan *Msg)
|
||||||
|
doneChan := make(chan bool)
|
||||||
|
|
||||||
out, err := proto.Marshal(&Msg{
|
out, err := proto.Marshal(&Msg{
|
||||||
Payload: &Msg_Start{
|
Payload: &Msg_Start{
|
||||||
Start: &StartMsg{
|
Start: &StartMsg{
|
||||||
|
@ -151,4 +179,23 @@ func main() {
|
||||||
os.Stderr.WriteString(err.Error())
|
os.Stderr.WriteString(err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In a goroutine, we wait on for all goroutines to complete (for example
|
||||||
|
// timers). We use this to signal to the main thread to exit.
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
doneChan <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case msg := <-resChan:
|
||||||
|
out, err := proto.Marshal(msg)
|
||||||
|
err = worker.SendBytes(out)
|
||||||
|
check(err)
|
||||||
|
case <-doneChan:
|
||||||
|
// All goroutines have completed. Now we can exit main().
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
4
main.ts
4
main.ts
|
@ -1,6 +1,7 @@
|
||||||
import { main as pb } from "./msg.pb";
|
import { main as pb } from "./msg.pb";
|
||||||
import "./util";
|
import "./util";
|
||||||
import * as runtime from "./runtime";
|
import * as runtime from "./runtime";
|
||||||
|
import * as timers from "./timers";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
function start(cwd: string, argv: string[]): void {
|
function start(cwd: string, argv: string[]): void {
|
||||||
|
@ -17,6 +18,9 @@ V8Worker2.recv((ab: ArrayBuffer) => {
|
||||||
case "start":
|
case "start":
|
||||||
start(msg.start.cwd, msg.start.argv);
|
start(msg.start.cwd, msg.start.argv);
|
||||||
break;
|
break;
|
||||||
|
case "timerReady":
|
||||||
|
timers.timerReady(msg.timerReady.id, msg.timerReady.done);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log("Unknown message", msg);
|
console.log("Unknown message", msg);
|
||||||
break;
|
break;
|
||||||
|
|
13
msg.proto
13
msg.proto
|
@ -10,6 +10,8 @@ message Msg {
|
||||||
SourceCodeFetchResMsg source_code_fetch_res = 12;
|
SourceCodeFetchResMsg source_code_fetch_res = 12;
|
||||||
SourceCodeCacheMsg source_code_cache = 13;
|
SourceCodeCacheMsg source_code_cache = 13;
|
||||||
ExitMsg exit = 14;
|
ExitMsg exit = 14;
|
||||||
|
TimerStartMsg timer_start = 15;
|
||||||
|
TimerReadyMsg timer_ready = 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,3 +35,14 @@ message SourceCodeCacheMsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
message ExitMsg { int32 code = 1; }
|
message ExitMsg { int32 code = 1; }
|
||||||
|
|
||||||
|
message TimerStartMsg {
|
||||||
|
int32 id = 1;
|
||||||
|
bool interval = 2;
|
||||||
|
int32 duration = 3; // In milliseconds.
|
||||||
|
}
|
||||||
|
|
||||||
|
message TimerReadyMsg {
|
||||||
|
int32 id = 1;
|
||||||
|
bool done = 2;
|
||||||
|
}
|
||||||
|
|
2
os.ts
2
os.ts
|
@ -35,7 +35,7 @@ function typedArrayToArrayBuffer(ta: TypedArray): ArrayBuffer {
|
||||||
return ab as ArrayBuffer;
|
return ab as ArrayBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendMsgFromObject(obj: pb.IMsg): null | pb.Msg {
|
export function sendMsgFromObject(obj: pb.IMsg): null | pb.Msg {
|
||||||
const msg = pb.Msg.fromObject(obj);
|
const msg = pb.Msg.fromObject(obj);
|
||||||
const ui8 = pb.Msg.encode(msg).finish();
|
const ui8 = pb.Msg.encode(msg).finish();
|
||||||
const ab = typedArrayToArrayBuffer(ui8);
|
const ab = typedArrayToArrayBuffer(ui8);
|
||||||
|
|
5
testdata/004_set_timeout.ts
vendored
Normal file
5
testdata/004_set_timeout.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
setTimeout(function() {
|
||||||
|
console.log("World");
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
console.log("Hello");
|
2
testdata/004_set_timeout.ts.out
vendored
Normal file
2
testdata/004_set_timeout.ts.out
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Hello
|
||||||
|
World
|
43
timers.ts
Normal file
43
timers.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import { _global } from "./util";
|
||||||
|
import { sendMsgFromObject } from "./os";
|
||||||
|
|
||||||
|
let nextTimerId = 1;
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
type TimerCallback = (...args: any[]) => void;
|
||||||
|
|
||||||
|
interface Timer {
|
||||||
|
id: number;
|
||||||
|
cb: TimerCallback;
|
||||||
|
interval: boolean;
|
||||||
|
duration: number; // milliseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
const timers = new Map<number, Timer>();
|
||||||
|
|
||||||
|
export function setTimeout(cb: TimerCallback, duration: number): number {
|
||||||
|
const timer = {
|
||||||
|
id: nextTimerId++,
|
||||||
|
interval: false,
|
||||||
|
duration,
|
||||||
|
cb
|
||||||
|
};
|
||||||
|
timers.set(timer.id, timer);
|
||||||
|
sendMsgFromObject({
|
||||||
|
timerStart: {
|
||||||
|
id: timer.id,
|
||||||
|
interval: false,
|
||||||
|
duration
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return timer.id;
|
||||||
|
}
|
||||||
|
_global["setTimeout"] = setTimeout;
|
||||||
|
|
||||||
|
export function timerReady(id: number, done: boolean): void {
|
||||||
|
const timer = timers.get(id);
|
||||||
|
timer.cb();
|
||||||
|
if (done) {
|
||||||
|
timers.delete(id);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue