Class: Dommy::Scheduler

Inherits:
Object
  • Object
show all
Defined in:
lib/dommy/scheduler.rb

Overview

Deterministic host-side scheduler for timers, rAF, and microtasks. Time advances only when the host explicitly calls ‘advance_time`.

Defined Under Namespace

Classes: Timer

Constant Summary collapse

FRAME_MS =
16

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeScheduler

Returns a new instance of Scheduler.



11
12
13
14
15
16
# File 'lib/dommy/scheduler.rb', line 11

def initialize
  @now_ms = 0
  @next_id = 1
  @timers = {}
  @microtasks = []
end

Instance Attribute Details

#now_msObject (readonly)

Returns the value of attribute now_ms.



18
19
20
# File 'lib/dommy/scheduler.rb', line 18

def now_ms
  @now_ms
end

Instance Method Details

#advance_time(delta_ms) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/dommy/scheduler.rb', line 62

def advance_time(delta_ms)
  target = @now_ms + [delta_ms.to_i, 0].max
  while next_due_timer_at && next_due_timer_at <= target
    @now_ms = next_due_timer_at
    run_due_timers
    drain_microtasks
  end

  @now_ms = target
  drain_microtasks
  nil
end

#cancel_animation_frame(id) ⇒ Object



44
45
46
# File 'lib/dommy/scheduler.rb', line 44

def cancel_animation_frame(id)
  cancel_timer(id)
end

#clear_interval(id) ⇒ Object



33
34
35
# File 'lib/dommy/scheduler.rb', line 33

def clear_interval(id)
  cancel_timer(id)
end

#clear_timeout(id) ⇒ Object



24
25
26
# File 'lib/dommy/scheduler.rb', line 24

def clear_timeout(id)
  cancel_timer(id)
end

#drain_microtasksObject



53
54
55
56
57
58
59
60
# File 'lib/dommy/scheduler.rb', line 53

def drain_microtasks
  until @microtasks.empty?
    callback = @microtasks.shift
    invoke_callback(callback, [@now_ms])
  end

  nil
end

#drain_timers(advance: 0) ⇒ Object



75
76
77
# File 'lib/dommy/scheduler.rb', line 75

def drain_timers(advance: 0)
  advance_time(advance)
end

#next_due_timer_atObject

Public accessor for eval-time auto-drain: keep advancing the clock until no timers remain (or a safety budget runs out).



81
82
83
# File 'lib/dommy/scheduler.rb', line 81

def next_due_timer_at
  @timers.values.select(&:active).map(&:due_at).min
end

#queue_microtask(callback) ⇒ Object



48
49
50
51
# File 'lib/dommy/scheduler.rb', line 48

def queue_microtask(callback)
  @microtasks << callback
  nil
end

#request_animation_frame(callback) ⇒ Object



37
38
39
40
41
42
# File 'lib/dommy/scheduler.rb', line 37

def request_animation_frame(callback)
  frames = ((@now_ms / FRAME_MS) + 1) * FRAME_MS
  id = next_id
  @timers[id] = Timer.new(id, :raf, callback, frames, nil, true)
  id
end

#set_interval(callback, interval_ms) ⇒ Object



28
29
30
31
# File 'lib/dommy/scheduler.rb', line 28

def set_interval(callback, interval_ms)
  ms = [interval_ms.to_i, 0].max
  register_timer(:interval, callback, ms, ms)
end

#set_timeout(callback, delay_ms) ⇒ Object



20
21
22
# File 'lib/dommy/scheduler.rb', line 20

def set_timeout(callback, delay_ms)
  register_timer(:timeout, callback, delay_ms.to_i, nil)
end