All Projects → helins → timer.cljs

helins / timer.cljs

Licence: MPL-2.0 License
Scheduling async operations in Clojurescript

Programming Languages

clojure
4091 projects
shell
77523 projects
HTML
75241 projects

Projects that are alternatives of or similar to timer.cljs

croner
Trigger functions and/or evaluate cron expressions in JavaScript. No dependencies. Most features. All environments.
Stars: ✭ 169 (+668.18%)
Mutual labels:  task, timer, scheduling
Flipdown
⏰ A lightweight and performant flip styled countdown clock
Stars: ✭ 136 (+518.18%)
Mutual labels:  clock, timer
Uicircularprogressring
A circular progress bar for iOS written in Swift
Stars: ✭ 1,658 (+7436.36%)
Mutual labels:  clock, timer
Clock
A low consumption, low latency support for frequent updates of large capcity timing manage
Stars: ✭ 161 (+631.82%)
Mutual labels:  clock, timer
Flip Clock
A flip clock, timer and countdown made with Polymer
Stars: ✭ 69 (+213.64%)
Mutual labels:  clock, timer
Use Timer
A timer hook for React
Stars: ✭ 113 (+413.64%)
Mutual labels:  clock, timer
Aospdeskclock
Fork of aosp deskclock: alarm,clock, timer,stopwatch
Stars: ✭ 28 (+27.27%)
Mutual labels:  clock, timer
Simple Clock
Combination of a beautiful clock with widget, alarm, stopwatch & timer, no ads
Stars: ✭ 257 (+1068.18%)
Mutual labels:  clock, timer
Laravel S
LaravelS is an out-of-the-box adapter between Swoole and Laravel/Lumen.
Stars: ✭ 3,479 (+15713.64%)
Mutual labels:  task, timer
Ects
Elastic Crontab System 简单易用的分布式定时任务管理系统
Stars: ✭ 156 (+609.09%)
Mutual labels:  task, timer
Rhine
Haskell Functional Reactive Programming framework with type-level clocks
Stars: ✭ 69 (+213.64%)
Mutual labels:  clock, scheduling
tm
timers and timeline
Stars: ✭ 31 (+40.91%)
Mutual labels:  clock, timer
React Countdown
React Component showing a countdown to certain date and time.
Stars: ✭ 58 (+163.64%)
Mutual labels:  clock, timer
React Timer Hook
React timer hook
Stars: ✭ 118 (+436.36%)
Mutual labels:  clock, timer
Peaclock
A responsive and customizable clock, timer, and stopwatch for the terminal.
Stars: ✭ 314 (+1327.27%)
Mutual labels:  clock, timer
Amazing Time Picker
Timepicker (Clock Picker) for Angular 2, Angular 4 and Angular 5, Angular 6, Angular 7 - Compatible with Angular Material
Stars: ✭ 142 (+545.45%)
Mutual labels:  clock, timer
new-clock
The best clock app there is
Stars: ✭ 24 (+9.09%)
Mutual labels:  clock, timer
Hgcircularslider
A custom reusable circular / progress slider control for iOS application.
Stars: ✭ 2,240 (+10081.82%)
Mutual labels:  clock, timer
Clock
一个简单的计时器程序💡/A sample clock⏰
Stars: ✭ 15 (-31.82%)
Mutual labels:  clock, timer
vue-circular-count-down-timer
a count down timer library for vue.js
Stars: ✭ 45 (+104.55%)
Mutual labels:  clock, timer

Timers

Clojars Project

Cljdoc

Scheduling asynchronous operations in Clojurescript can be tedious. There exists quite a few ways depending on what is needed and they often have pitfalls (eg. infamous .setInterval is clamped to run at most once per second when the tab is not focused).

This library aims to clarify the various existing ways of async scheduling while solving such problems.

Usage

After reading the following overview, see the API.

Let us require the library:

(require '[helins.timer :as timer])

"Macro" tasks

Or simply "tasks", are units of computations enqueued in the event loop.

At some point in the future

A task can be scheduled to run in, say, 2000 milliseconds:

(timer/in timer/main-thread
          2000
          (fn my-task []
            (println "Hello world!")))

Or every 2000 milliseconds:

(timer/every timer/main-thread
             2000
             (fn repeated-task []
               (println "Hello... again, and again..."))
             (fn on-lag [delta]
               ;; Optional
               ))
               

This periodic execution will run some drift protection, trying to ensure as precisely as possible that there will be a consistent time difference of 2000 milliseconds between each call, in this instance. If a run takes more time than what has been requested, then the whole process is running late and nothing can be done. In consequence, the execution stops and the optional on-lag function is called with a value expressing how late it is running (eg. -143 means "143 milliseconds late"). The user can then decide what to do.

Both in and every return a token which can be used to cancel what has been scheduled:

(timer/cancel timer/main-thread
              my-token)

There is a caveat. Such timers scheduled on the main thread, as we did, may exhibit unwanted behavior. For instance, as previously mentioned, intervals are clamped to at least 1000 milliseconds while the tab is inactive. A solution is to use a worker:

(timer/worker)

;; Instead of

timer/main-thread

Using a worker, scheduling happens via a Web Worker and is typically more reliable. However, the execution itself still happens on the main thread. Using a worker in such a fashion is surprisingly robust, enough to handle time-sensitive operation such as generating music. Usually, one worker per application is more than enough as all it does is scheduling.

As soon as possible

A task can be simply enqueued to the event loop and it will be executed when it is its turn. One benefit of doing so would be to divide a long running computation into more granular units as to not hog the main thread for too long.

(timer/task (fn my-task []
              (println "Cool!")))

On the next frame

Especially useful for animation, a function can be scheduled to run prior to the next screen refresh in order to compute what is needed for the next frame. Anything scheduled will not run while the tab is not focused as there is nothing to see, hence no frame to generate. The timestamp provided to the function must be used for all time-dependent computations.

(def token
     (timer/frame (fn on-frame [timestamp]
                    ;; Computes and draws the next frame
                    )))

;; If needed

(timer/cancel-frame token)

It is more common to run a loop in order to animate a series of frames. The plural form is then useful, a cancelling function being provided as well:

(def cancel
     (timer/frames (fn on-frame [timestamp cancel]
                     ;; Number crunching, animating
                     )))

;; When done
(cancel)

For the drawing itself, on canvas, we recommend io.helins/canvas.

Micro tasks

In between 2 regular tasks in the event loop (what has been discussed up to this point), the Javascript engine runs the "micro task queue". A micro task can schedule another micro task which will be appended to that same queue. Only when that queue is empty will the engine proceed to the next regular task.

Micro tasks are useful for scheduling high-priority asynchronous operations garanteed to execute in order of scheduling before the next regular task. While this sounds esoteric, it can be particularly useful. For instance, the ubiquitous Promise is actually implemented using micro tasks.

(timer/micro-task (fn my-micro-task []
                    (println "Pretty dope.")))

See this guide for a complete breakdown of the differences between micro tasks and regular ones.

Miscellaneous

When it comes to music, there are yet corners to explore.

The Web Audio and Web MIDI APIs provides accurate timers for specific tasks such as generating a sound or sending a MIDI event. However, those events are scheduled for a precise moment, and sometimes, once scheduled, cannot be canceled. A proven method is to combine those precise, specific timers with this library (using above-mentioned workers) in order the gain very fine control. This idea is not new, it has already been described back in 2013 in this article. We like to call it "look ahead scheduling", or "double scheduling".

License

Copyright © 2020 Adam Helinski

Licensed under the term of the Mozilla Public License 2.0, see LICENSE.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].