Globals and Built-ins
These are the global APIs that Mikro.js adds on top of the standard QuickJS environment. For standard JavaScript built-ins (Array, Object, Promise, Map, Set, etc.), see the QuickJS-NG documentation.
Timers
function setTimeout(callback: (...args: any[]) => void, ms?: number): number
function clearTimeout(id: number): void
function setInterval(callback: (...args: any[]) => void, ms?: number): number
function clearInterval(id: number): voidStandard timer functions. These drive the Mikro.js event loop.
console
const console: {
log(...args: unknown[]): void
info(...args: unknown[]): void
warn(...args: unknown[]): void
error(...args: unknown[]): void
}Logs to the serial console on device, or stdout in the simulator.
btoa / atob
function btoa(data: string): string
function atob(data: string): stringBase64 encoding and decoding. btoa encodes a binary (latin1) string to base64. atob decodes a base64 string back.
btoa('Hello') // "SGVsbG8="
atob('SGVsbG8=') // "Hello"btoa throws a RangeError if the string contains characters outside the latin1 range. atob throws a SyntaxError on invalid base64 input.
TextEncoder / TextDecoder
class TextEncoder {
encode(input?: string): Uint8Array
}
class TextDecoder {
decode(input?: ArrayBufferView | ArrayBuffer): string
}UTF-8 encoding and decoding.
AbortController / AbortSignal
class AbortController {
readonly signal: AbortSignal
abort(reason?: unknown): void
}
class AbortSignal {
readonly aborted: boolean
readonly reason: unknown
throwIfAborted(): void
onabort: (() => void) | null
addEventListener(type: 'abort', fn: () => void): void
removeEventListener(type: 'abort', fn: () => void): void
static abort(reason?: unknown): AbortSignal
static timeout(ms: number): AbortSignal
static any(signals: AbortSignal[]): AbortSignal
}Cooperative cancellation. Most useful with fetch for request timeouts:
import {fetch} from 'mikrojs/fetch'
// Cancel if no response within 5 seconds
const result = await fetch('https://api.example.com/data', {
signal: AbortSignal.timeout(5000),
})
if (!result.ok && result.error.name === 'Aborted') {
console.error('Request timed out')
}Manual cancellation:
const controller = new AbortController()
setTimeout(() => controller.abort(), 3000)
const result = await fetch('https://slow.example.com', {
signal: controller.signal,
})On ESP32, aborting a fetch cancels the underlying HTTP task and frees its TLS buffers immediately, which can reclaim 16-40 KB of heap.
AbortError / TimeoutError
The default abort reason is an AbortError, and AbortSignal.timeout() uses a TimeoutError. Both are Error subclasses:
const signal = AbortSignal.abort()
signal.reason instanceof AbortError // true
signal.reason.name // "AbortError"
const timeout = AbortSignal.timeout(1000)
// after timeout fires:
timeout.reason instanceof TimeoutError // true
timeout.reason.name // "TimeoutError"Difference from web standard
Browsers use DOMException with name: "AbortError" and name: "TimeoutError". Mikro.js uses dedicated AbortError and TimeoutError classes instead, because DOMException is a DOM API with a large spec surface that doesn't belong on a microcontroller. Code that checks error.name === "AbortError" works the same way in both environments.
AbortSignal.any() combines multiple signals:
const timeout = AbortSignal.timeout(10000)
const manual = new AbortController()
const result = await fetch(url, {
signal: AbortSignal.any([timeout.signal, manual.signal]),
})import.meta
Available inside ES modules:
| Property | Type | Description |
|---|---|---|
import.meta.url | string | URL of the current module |
import.meta.main | boolean | Whether this is the entry module |
import.meta.dirname | string | Directory of the current module |
import.meta.basename | string | Filename of the current module |
import.meta.path | string | Full path of the current module |
import.meta.env | Record<string, string> | Environment variables (from NVS on device) |
dirname, basename, path, and env are only available for file-based modules (not built-in mik: modules).
Why isn't fetch a global?
In browsers and Node.js, fetch is a global function. In Mikro.js, you import it from mikrojs/fetch instead. This is because Mikro.js's fetch returns a Result instead of throwing on network errors, so the signature is different from the standard fetch. Making it a global would be misleading since it doesn't behave the same way.
import {fetch} from 'mikrojs/fetch'
const result = await fetch('https://example.com')
if (!result.ok) {
// network error, not an exception
}WinterTC compatibility
Mikro.js is not WinterTC compatible, and full compliance is not a goal. Where feasible, we align with WinterTC APIs (e.g., fetch, TextEncoder, TextDecoder, AbortSignal, timers), but the runtime is designed for microcontrollers, not server-side JavaScript, and some APIs don't make sense in this context.