src/platforms/wasm/js_fetch_readme.md
This module provides a simple, fluent HTTP fetch API for FastLED WASM applications using native JavaScript fetch() with async callbacks to C++. The implementation allows JavaScript to handle HTTP requests and call back into async C++ functions when responses arrive.
fl/fetch.h header works on WASM and Arduino platformsfl::fetch(url, callback) - no platform-specific code neededfetch.get(url).response(callback) interface for WASM buildsfetch() for maximum compatibility#include "fl/fetch.h"
void setup() {
// Simple cross-platform fetch - works on WASM and Arduino!
fl::fetch("https://httpbin.org/json", [](const fl::response& resp) {
if (resp.ok()) {
FL_WARN("✅ Success: " << resp.text());
} else {
FL_WARN("❌ Error: " << resp.text());
}
});
}
void loop() {
// FastLED loop continues normally
// On WASM: Fetch responses are handled asynchronously via JavaScript
// On Arduino: Immediate error response (no network blocking)
}
#include "platforms/wasm/js_fetch.h" // WASM only
void setup() {
// WASM-only fluent API
fl::fetch.get("https://httpbin.org/json")
.response([](const fl::response& resp) {
FL_WARN("Response received: " << resp.text());
});
}
void setup() {
// Multiple requests can be made simultaneously - each gets a unique ID
fl::fetch.get("https://httpbin.org/json")
.response([](const fl::response& resp) {
FL_WARN("Request 1 completed: " << resp.text());
});
fl::fetch.get("https://fastled.io")
.response([](const fl::response& resp) {
FL_WARN("Request 2 completed: " << resp.text());
});
fl::fetch.get("https://httpbin.org/uuid")
.response([](const fl::response& resp) {
FL_WARN("Request 3 completed: " << resp.text());
});
// All three requests run concurrently - responses can arrive in any order
// No race conditions or lost callbacks!
}
fl::fetch.get("https://invalid-url-that-fails.com/test")
.response([](const fl::response& resp) {
if (!resp.ok()) {
FL_WARN("Request failed: " << resp.text());
} else {
FL_WARN("Request succeeded: " << resp.text());
}
});
fl::fetch.get(url).response(callback) stores callback and calls JavaScriptEM_JS function uses native fetch() APIjs_fetch.h: Header with fluent API classes (Fetch, FetchRequest)js_fetch.cpp: Implementation with EM_JS bridge and C++ callbacksjs_fetch_async(): EM_JS function that performs JavaScript fetch with request IDjs_fetch_success_callback(): C++ function called by JavaScript on success (with request ID)js_fetch_error_callback(): C++ function called by JavaScript on error (with request ID)The fetch system uses a unique request ID approach with a singleton callback manager to enable multiple simultaneous requests:
fetch.get().response() call generates a unique uint32_t request IDFetchCallbackManager singleton handles all callback storage using fl::Singleton<T>fl::hash_map<uint32_t, FetchResponseCallback> with move semanticstakeCallback() atomically moves and returns the callback via fl::optional, preventing race conditions// Internal singleton class for managing fetch callbacks (private to .cpp file)
class FetchCallbackManager {
public:
uint32_t generateRequestId();
void storeCallback(uint32_t request_id, FetchResponseCallback callback); // move semantics
fl::optional<FetchResponseCallback> takeCallback(uint32_t request_id); // move semantics
private:
fl::hash_map<uint32_t, FetchResponseCallback> mPendingCallbacks; // direct storage
fl::mutex mCallbacksMutex;
uint32_t mNextRequestId;
};
// Accessed via: fl::Singleton<FetchCallbackManager>::instance()
Benefits over Global Callback:
The implementation uses these key patterns:
// EM_JS function in C++
EM_JS(void, js_fetch_async, (const char* url), {
fetch(UTF8ToString(url))
.then(response => response.text())
.then(text => {
// Call back to C++
Module._js_fetch_success_callback(stringToUTF8OnStack(text));
})
.catch(error => {
Module._js_fetch_error_callback(stringToUTF8OnStack(error.message));
});
});
// C++ callback functions exported to JavaScript
extern "C" EMSCRIPTEN_KEEPALIVE void js_fetch_success_callback(const char* content);
extern "C" EMSCRIPTEN_KEEPALIVE void js_fetch_error_callback(const char* error_message);
The following Emscripten flags are required in build_flags.toml:
# Export callback functions for JavaScript
"-sEXPORTED_FUNCTIONS=[..., '_js_fetch_success_callback', '_js_fetch_error_callback']"
# Threading support for background worker execution
"-pthread"
"-sUSE_PTHREADS=1"
"-sPROXY_TO_PTHREAD"
Note: Asyncify flags are NOT required. FastLED WASM uses dedicated Web Workers (PROXY_TO_PTHREAD) for background execution, providing true threading without Asyncify's async emulation. Asyncify was removed in 2025-01 to reduce binary size (44.4% reduction) and fix audio reactive mode issues.
fetch() supportexamples/Asio/Client/Client.ino: Comprehensive network testing with multiple fetch scenariosAll errors are delivered to the same callback with "Fetch Error:" prefix for easy identification.
FL_WARN for troubleshooting