Copyright 2017-2025 Moddable Tech, Inc.
Revised: August 4, 2025
The Timer class provides both time-based callbacks and a delay function.
import Timer from "timer";Timer callbacks are invoked with this set to globalThis. Use an arrow function or Function.prototype.bind to bind the callback's this to another value.
Each timer has two intervals: the initial interval and a repeat interval. The intervals are in milliseconds. The initial interval is the time until the callback is first invoked. The repeat interval is the time between successive invocations of the callback after the initial interval. The API reference that follows indicates how each API modifies the initial and repeat intervals.
If the repeat interval is zero when the timer's callback returns, the timer is automatically cleared and can no longer be used. The repeat interval may be changed by the callback using Timer.schedule.
The Timer.set and Timer.repeat functions create a new timer and return a timer instance. Timer instances have no methods and are only useful for passing to Timer functions.
Timer callbacks can provide the basic behaviors of setImmediate, setTimeout and setInterval. The timers example shows how to do this.
The set function requests a function be called once after a certain period. Timer.set returns a new timer instance.
An immediate timer is called on the next cycle through the run loop. To set an immediate timer, call set with only the callback function.
Timer.set(() => trace("immediate fired\n"));A one shot timer is called once after a specified number of milliseconds. If the number of milliseconds is zero, a one shot timer is equivalent to an immediate timer.
Timer.set(() => trace("one shot fired\n"), 1000);Calling set with a repeat is equivalent to a repeating timer with the first callback triggered after the interval.
Timer.set(() => trace("repeat fired\n"), 1000, 100);The callback function receives the timer instance as the first argument.
- If
Timer.setis called without the initial interval and repeat interval, it is an immediate one-shot timer (initial and repeat intervals are set to 0). - If
Timer.setis called with only an initial interval, it is a one-shot timer (repeat interval is set to 0). - If
Timer.setis called with both an initial and a non-zero repeat interval, it is a repeating timer.
A repeating timer is called continuously until stopped using the Timer.clear function. Timer.repeat returns a new timer instance.
Timer.repeat(() => trace("repeat fired\n"), 1000);The callback function receives the timer instance as the first argument.
This function sets both the initial interval and repeat interval to the value specified by repeatInterval. Use Timer.set to create a timer with an initial interval that is different from the repeat interval.
The schedule function reschedules or unschedules an existing timer.
- If called with an initial interval but no repeat interval, the timer behaves like a one shot timer created with
Timer.set. - If called with both an initial interval and non-zero repeat interval, it behaves like a repeating timer created with
Timer.setwith both initial interval and repeat interval arguments. - If called without interval arguments, the timer is unscheduled and will not trigger until rescheduled using
Timer.schedule(an unscheduled timer is considered to have infinite initial and repeat intervals).
In the following example, the callback function is triggered twice at one second intervals and then rescheduled to once every two seconds.
let state = 0;
Timer.repeat(timer => {
if (0 === state)
state = 1;
else if (1 === state) {
state = 2;
Timer.schedule(timer, 2000, 2000);
}
}, 1000);When Timer.schedule is used to set the initial interval, the callback is next invoked after the new initial interval has elapsed.
Note: If the next trigger time is unknown, unscheduling a timer is preferred to scheduling for a long time in the future. Unscheduling and rescheduling a timer can more efficient than clearing a timer and later allocating a new one.
The clear function cancels a timer. The Timer.set and Timer.repeat functions returns a timer instance, which is then passed to clear.
let aTimer = Timer.set(() => trace("one shot\n"), 1000);
Timer.clear(aTimer);Note: Immediate and one shot timers are automatically cleared after invoking their callback function. There is no need to call
clearexcept to cancel the timer before it fires.
Note: If
Timer.clearis passed a value ofundefinedornullfor the timer, no exception is generated.
The delay function delays execution for the specified number of milliseconds.
Timer.delay(500); // delay 1/2 secondNote: In general, the preferred style of JavaScript programming is to avoid long delays that block execution. Timer.delay is provided because in embedded development it is common to need short delays when interacting with hardware. For longer delays, using an alternative such as a Timer callback or asynchronous execution with Promises may be more appropriate.
- Source code: time
- Source code: time
- Relevant Examples: sntp, ntpclient, ios-time-sync
The Time class provides time functions and a tick counter.
import Time from "time";The set function sets the system time. The seconds argument corresponds to the number of seconds elapsed since January 1, 1970, i.e. Unix time.
The timezone property is set to the time zone offset in seconds from UTC.
Time.timezone = +9 * 60 * 60; // Set time zone to UTC+09:00The dst property is set to the daylight saving time (DST) offset in seconds.
Time.dst = 60 * 60; // Set DSTThe ticks property returns the value of a millisecond counter. The value returned does not correspond to the time of day. The milliseconds are used to calculate time differences.
const start = Time.ticks;
for (let i = 0; i < 1000; i++)
;
const stop = Time.ticks;
trace(`Operation took ${Time.delta(start, stop)} milliseconds\n`);On devices that supports multiple concurrent JavaScript virtual machines (for example, using Workers), the clock used to determine the value of the ticks property is the same across all virtual machines. This allows tick values created in one machine to be compared with values from another.
The range of the value depends on the host. On most microcontrollers, the value is a signed 32-bit integer. On the simulator, it is a positive 64-bit floating point value. To determine the difference between two ticks values, use Time.delta() which is guaranteed to give a correct result for the host.
The delta function calculates the difference between two values returned by Time.ticks. It is guaranteed to return a correct result even when the value rolls over. If the optional end argument is omitted the current value of Time.ticks is used.
The microseconds property returns the value of a microseconds counter. The value returned does not correspond to the time of day. The microseconds are used to calculate time differences.
To use the microseconds property, include its manifest in the project manifest:
"include": [
...
"$(MODDABLE)/modules/base/microseconds/manifest.json",
],
The microseconds property is used in the same way as the ticks property. Like the ticks property, a single time source is used when there multiple concurrent virtual machines. The range of the microseconds property is a 64-bit floating point value.
Unlike Time.ticks, the values returned by Time.microseconds may always be subtracted from one another to calculate intervals.
const start = Time.microseconds;
for (let i = 0; i < 1000; i++)
;
const stop = Time.microseconds;
trace(`Operation took ${stop - start} microseconds\n`);Note: Not all hosts implement microseconds. Hosts that do not implement microseconds generate an error at build time.
- Source code: debug
The Debug class provides functions that are useful during the development process.
import Debug from "debug";The gc function can be used to turn the JavaScript garbage collector on and off, as well as to run the garbage collector on-demand.
Calling Debug.gc with no arguments runs the garbage collector immediately.
Debug.gc();Calling Debug.gc with a single boolean argument enables or disables the garbage collector.
Debug.gc(true) // enable garbage collector
Debug.gc(false); // disable garbage collector- Source code: uuid
The UUID class provides a single function to generate a UUID string.
import UUID from "uuid";Note: Generating a truly unique UUID requires that the device running this function have a unique MAC address and the valid time. Neither of these is guaranteed on all microcontrollers. For production software release, check your device configuration.
The UUID function returns a new UUID formatted as a string.
let value = UUID(); // 1080B49C-59FC-4A32-A38B-DE7E80117842The deepEqual function implements a deep comparison between two JavaScript object.
import deepEqual from "deepEqual";There is no standard algorithm for deeply comparing two objects in JavaScript, and there are many possible correct approaches. The Moddable SDK adopts the behavior of assert.deepEqual and assert.deepStrictEqual from Node.js for its implementation of deepEqual.
The deepEqual function has an optional third parameter, an options object. By default the deepEqual comparison is not-strict, similar to using == for comparisons. Passing {strict: true} for the options object uses strict comparison, similar to using === for comparisons.
const a = {a: 1, b: 0, c: "str"};
const b = {a: 1, b: "0", c: "str"};
deepEqual(a, b); // true
deepEqual(a, b, {strict: true}); // falseThe known differences between the Moddable SDK implementation and Node.js will not impact most uses:
WeakMapandWeakSetusing read-only objects as keys- XS does not call
valueOfto compare boxed primitives
- Source code: structuredClone
- Tests: structuredClone
The structuredClone function creates a deep copy of a JavaScript object.
import structuredClone from "structuredClone";The structuredClone function in the Moddable SDK implements the algorithm defined by WHATWG for the web platform as much as practical, including circular references and the transferables option.
const a = {a: 1, b: Uint8Array.of(1, 2, 3)}
const aCopy = structuredClone(a);The Moddable SDK implementation of structuredClone implements all supported types that are part of the JavaScript language standard. It does not, of course, clone object types that are part of the web platform and not present on embedded systems such as DOMException.
- Source code: instrumentation
- Relevant Examples: instrumentation, xsuse
The Instrumentation class returns statistics on the behavior of the runtime, including memory use, open file count, and rendering frame rate.
import Instrumentation from "instrumentation";The get function returns the value of the instrumented item at the index specified by the what parameter. Instrumented items are consecutively numbered starting at index 1.
let pixelsDrawn = Instrumentation.get(1);The index of instrumentation items depends on the host and varies between different devices based on the supported features. Use Instrumentation.map() to determine the index of a specific instrumentation on the running host.
The map function returns the instrumentation index for a name.
let pixelsDrawnIndex = Instrumentation.map("Pixels Drawn");
let pixelsDrawn = Instrumentation.get(pixelsDrawnIndex);If the instrumentation item named is unavailable, map returns undefined.
The name function returns the name of the instrumentation item at the specified index. It can be used to iterate through all available instrumentation items.
for (let i = 1; true; i++) {
const name = Instrumentation.name(i);
if (!name)
break;
trace(`${name}: ${Instrumentation.get(i)}\n`);
}The table below describes the instrumented items that are available. The following instrumented items are reset at one second intervals: Pixels Drawn, Frames Drawn, Poco Display List Used, Piu Command List Used, Network Bytes Read, Network Bytes Written, and Garbage Collection Count.
| Name | Long Description |
|---|---|
Pixels Drawn |
The total number of pixels rendered to by Poco during the current interval. This value includes pixels drawn to a display device and pixels rendered offscreen. |
Frames Drawn |
The total number of frames rendered by Poco during the most recent interval. Frames are counted by calls to Poco.prototype.end() and by Piu frame updates. |
Network Bytes Read |
The total number of bytes received by the Socket module during the current interval. This includes bytes received over TCP and UDP. |
Network Bytes Written |
The total number of bytes send by the Socket module during the current interval. This includes bytes sent using TCP and UDP. |
Network Sockets |
The total number of active network sockets created by the Socket module. This includes TCP sockets, TCP listeners, and UDP sockets. |
Timers |
The number of allocated timers created by the Timer module. |
Files |
The number of open files and directory iterators created the File module. |
Poco Display List Used |
The peak size in bytes of the Poco display list in the current interval. |
Piu Command List Used |
The peak size in bytes of the Piu command list in the current interval. |
Turns |
The number of times the event loop has run in the current interval. |
CPU 0 |
The load on CPU 0 during the current interval. |
CPU 1 |
The load on CPU 1 during the current interval. |
System Free Memory |
The number of free bytes in the system memory heap. This value is not available in the simulator. |
XS Slot Heap Used |
Number of bytes in use in the slot heap of the primary XS machine. Some of these bytes may be freed when the garbage collector next runs. |
XS Chunk Heap Used |
Number of bytes in use in the chunk heap of the primary XS machine. Some of these bytes may be freed when the garbage collector next runs. |
XS Keys Used |
Number of runtime keys allocated by the primary XS machine. Once allocated keys are never deallocated. |
XS Garbage Collection Count |
The number of times the garbage collector has run in the current interval. |
XS Modules Loaded |
The number of JavaScript modules that are currently loaded in the primary XS machine. This number does not include modules which are preloaded. |
XS Stack Used |
The maximum depth in bytes of the stack of the primary XS virtual machine during the current interval. |
XS Promises Settled |
The number of Promises settled. This is useful as a measure of Promisee/async/await activity. |
The Console class implements a serial terminal for debugging and diagnostic purposes. The Console module uses CLI modules to implement the terminal commands.
The CLI class is a plug-in interface for commands used in a command line interface. CLI classes implement commands for use by the Console module (serial command line) and Telnet module (network command line).
See the Worker documentation for information about the Worker class.