A lightweight, high-performance alternative to RxJS
Built for modern apps that need reactive streams without the complexity
ð Why Streamix? â
Streamix gives you all the power of reactive programming with 90% less complexity than RxJS. At just 11 KB zipped, it's perfect for modern applications that need performance without bloat.
âĻ Key Benefits â
- ðŠķ Ultra Lightweight â Only 9 KB zipped (vs RxJS's ~40 KB)
- ⥠High Performance â Pull-based execution means values are only computed when needed
- ðŊ Easy to Learn â Familiar API if you know RxJS, simpler if you don't
- ð Generator-Powered â Built on async generators for natural async flow
- ð HTTP Ready â Optional HTTP client (~3 KB) for seamless API integration
- ð§ Computation-Friendly â Perfect for heavy processing tasks
- ðïļ Native DOM Observation â Built-in streams for intersection, resize, and mutation events
ðĶ Installation â
# npm
npm install @actioncrew/streamix
# yarn
yarn add @actioncrew/streamix
# pnpm
pnpm add @actioncrew/streamix
ðââïļ Quick Start â
Basic Stream Operations â
import { eachValueFrom, range, map, filter, take } from '@actioncrew/streamix';
// Create a stream of numbers, transform them, and consume
const stream = range(1, 100)
.pipe(
map(x => x * 2), // Double each number
filter(x => x % 3 === 0), // Keep only multiples of 3
take(5) // Take first 5 results
);
// Consume the stream
for await (const value of eachValueFrom(stream)) {
console.log(value); // 6, 12, 18, 24, 30
}
Handling User Events â
import { eachValueFrom, fromEvent, debounce, map } from '@actioncrew/streamix';
// Debounced search as user types
const searchInput = document.getElementById('search');
const searchStream = fromEvent(searchInput, 'input')
.pipe(
map(event => event.target.value),
debounce(300), // Wait 300ms after user stops typing
filter(text => text.length > 2)
);
for await (const searchTerm of eachValueFrom(searchStream)) {
console.log('Searching for:', searchTerm);
// Perform search...
}
ð§ Core Concepts â
Streams â
Streams are sequences of values over time, implemented as async generators:
// Creating a custom stream
async function* numberStream() {
for (let i = 0; i < 10; i++) {
yield i;
await new Promise(resolve => setTimeout(resolve, 100));
}
}
const stream = createStream('numberStream', numberStream);
Operators â
Transform, filter, and combine streams with familiar operators:
import { map, filter, mergeMap, combineLatest } from '@actioncrew/streamix';
const processedStream = sourceStream
.pipe(
map(x => x * 2),
filter(x => x > 10),
mergeMap(x => fetchDataFor(x))
);
Subjects â
Manually control stream emissions:
import { eachValueFrom, Subject, createSubject } from '@actioncrew/streamix';
const subject = createSubject<string>();
// Subscribe to the subject
for await (const value of eachValueFrom(subject)) {
console.log('Received:', value);
}
// Emit values
subject.next('Hello');
subject.next('World');
subject.complete();
ð HTTP Client â
Streamix includes a powerful HTTP client perfect for reactive applications:
import { eachValueFrom, map, retry } from '@actioncrew/streamix';
import {
createHttpClient,
readJson,
useBase,
useLogger,
useTimeout
} from '@actioncrew/streamix/http';
// Setup client with middleware
const client = createHttpClient().withDefaults(
useBase("https://api.example.com"),
useLogger(),
useTimeout(5000)
);
// Make reactive HTTP requests
const dataStream = retry(() => client.get("/users", readJson), 3)
.pipe(
map(users => users.filter(user => user.active))
);
for await (const activeUsers of eachValueFrom(dataStream)) {
console.log('Active users:', activeUsers);
}
ðŊ Real-World Example â
Here's how to build a live search with API calls and error handling:
import {
eachValueFrom,
fromEvent,
fromPromise,
debounce,
map,
filter,
switchMap,
catchError,
startWith
} from '@actioncrew/streamix';
const searchInput = document.getElementById('search');
const resultsDiv = document.getElementById('results');
const searchResults = fromEvent(searchInput, 'input')
.pipe(
map(e => e.target.value.trim()),
debounce(300),
filter(query => query.length > 2),
switchMap(query => fromPromise(
fetch(`/api/search?q=${query}`)
.then(r => r.json())
.catch(err => ({ error: 'Search failed', query })))
),
startWith({ results: [], query: '' })
);
for await (const result of eachValueFrom(searchResults)) {
if (result.error) {
resultsDiv.innerHTML = `<p class="error">${result.error}</p>`;
} else {
resultsDiv.innerHTML = result.results
.map(item => `<div class="result">${item.title}</div>`)
.join('');
}
}
ð Available Operators â
Streamix includes all the operators you need:
Transformation â
map
- Transform each valuescan
- Accumulate values over timebuffer
- Collect values into arrays
Filtering â
filter
- Keep values that match criteriatake
- Take first N valuestakeWhile
- Take while condition is trueskip
- Skip first N valuesdistinct
- Remove duplicates
Combination â
mergeMap
- Merge multiple streamsswitchMap
- Switch to latest streamcombineLatest
- Combine latest valuesconcat
- Connect streams sequentially
Utility â
tap
- Side effects without changing streamdelay
- Add delays between emissionsretry
- Retry failed operationsfinalize
- Cleanup when stream completesdebounce
- Limit emission rate
ðŪ Live Demos â
Try Streamix in action:
- ð Simple Animation - Smooth animations with streams
- âïļ Heavy Computation - Mandelbrot set generation
- âïļ Travel Blog - Real-world app example
ð Generator-Based Architecture â
Unlike RxJS's push-based approach, Streamix uses pull-based async generators:
// Values are only computed when requested
async function* expensiveStream() {
for (let i = 0; i < 1000000; i++) {
yield expensiveComputation(i); // Only runs when needed!
}
}
// Memory efficient - processes one value at a time
const stream = createStream('expensiveStream', expensiveStream)
.pipe(take(10)); // Only computes first 10 values
This means:
- Better performance - No wasted computations
- Lower memory usage - Process one value at a time
- Natural backpressure - Consumer controls the flow
ð Streamix vs RxJS â
Feature | Streamix | RxJS |
---|---|---|
Bundle Size | 9 KB | ~40 KB |
Learning Curve | Gentle | Steep |
Performance | Pull-based (efficient) | Push-based |
API Complexity | Simple | Complex |
Async/Await Support | Native | Limited |
Memory Usage | Low | Higher |
ð Documentation & Resources â
- ð API Documentation
- ð° Blog: Exploring Streamix
- ð Streamix 2.0 Updates
- ðŊ Reactive Programming Guide
ðĪ Contributing â
We'd love your help making Streamix even better! Whether it's:
- ð Bug reports - Found something broken?
- ðĄ Feature requests - Have a great idea?
- ð Documentation - Help others learn
- ð§ Code contributions - Submit a PR
ð Share your feedback - Tell us how you're using Streamix!
ð License â
MIT License - use Streamix however you need!
Ready to stream? Get started with Streamix today! ð
Install from NPM âĒ View on GitHub âĒ Give Feedback
API Reference â
Check the detailed API Reference here.