System Design And Data Structures
async-queue
An AsyncQueue
class that processes asynchronous tasks in sequence. Each task is a function returning a
Promise, and tasks are executed one after another in the order they were added.
Useful for controlling async flows like background jobs, rate-limited API calls, or sequential workflows.
class AsyncQueue {
constructor() {
this.queue = [];
}
enqueue(task) {
if (typeof task !== "function") {
throw new Error("Task must be a function returning a promise");
}
this.queue.push(task);
}
async process() {
const results = [];
for (const task of this.queue) {
const result = await task();
results.push(result);
}
return results;
}
}
const queue = new AsyncQueue();
queue.enqueue(
() =>
new Promise((resolve) => {
setTimeout(() => resolve("Task 1"), 1000);
}),
);
queue.enqueue(
() =>
new Promise((resolve) => {
setTimeout(() => resolve("Task 2"), 500);
}),
);
queue.process().then((results) => console.log(results));
// ['Task 1', 'Task 2']
Queue
A simple Queue
class that follows the FIFO (First In, First Out) principle. Elements are added to the end and removed from the front.
Commonly used in scheduling, task queues, and breadth-first search algorithms.
class Queue {
constructor() {
this.collection = [];
}
enqueue(element) {
this.collection.push(element);
return this;
}
dequeue() {
this.collection.shift();
return this;
}
front() {
return this.collection[0];
}
get size() {
return this.collection.length;
}
isEmpty() {
return this.collection.length === 0;
}
}
const queue = new Queue();
queue.enqueue("one").enqueue("two");
// [ 'one', 'two' ]
queue.dequeue(); // [ 'two' ]
queue.enqueue("three").enqueue("four");
// [ 'two', 'three', 'four' ]
queue.front(); // two
queue.size; // 3
queue.isEmpty(); // false
Redux
An implementation of the Redux pattern using vanilla JavaScript. This custom Store
class manages state using a reducer and supports dispatching actions and subscribing to state changes.
Redux is commonly used for predictable state management in frontend applications like React.
class Store {
constructor(reducer, initialState) {
this.reducer = reducer;
this.state = initialState;
this.listeners = [];
}
getState() {
return this.state;
}
dispatch(action) {
this.state = this.reducer(this.state, action);
this.listeners.forEach((listener) => listener());
}
subscribe(listener) {
this.listeners.push(listener);
return () => {
console.log("unsubscribed");
this.listeners = this.listeners.filter((l) => l !== listener);
};
}
}
// Example reducer function
const reducer = (state, action) => {
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "DECREMENT":
return { ...state, count: state.count - 1 };
default:
return state;
}
};
const initialState = { count: 0 };
const store = new Store(reducer, initialState);
// Subscribe to state changes
const unsubscribe = store.subscribe(() => {
console.log(store.getState());
});
// Dispatch actions
console.log(store.getState());
store.dispatch({ type: "INCREMENT" });
store.dispatch({ type: "INCREMENT" });
store.dispatch({ type: "DECREMENT" });
// Unsubscribe from state changes
unsubscribe();
// { count: 0 }
// { count: 1 }
// { count: 2 }
// { count: 1 }
// unsubscribed
Stack Palindrome
This function uses a stack to check if a given word is a palindrome. It pushes each character onto the stack, then pops them in reverse order to compare with the original string.
function isPalindrome(word) {
const letters = []; // this is our stack
let reversedWord = "";
// put letters of word into stack
for (let i = 0; i < word.length; i++) {
letters.push(word[i]);
}
// pop off the stack in reverse order
for (let i = 0; i < word.length; i++) {
reversedWord += letters.pop();
}
return reversedWord === word;
}
console.log(isPalindrome("racecar")); // true
console.log(isPalindrome("cheatsheet")); // false
Stack
A basic Stack
class implementation that follows LIFO (Last In, First Out) behavior.
Includes common methods such as push
, pop
, peek
, and size
.
Useful for:
- Undo functionality
- Recursion
- Reversing data
class Stack {
constructor() {
this.storage = [];
}
push(value) {
this.storage.push(value);
return this;
}
pop() {
this.storage.pop();
return this;
}
size() {
return this.storage.length;
}
peek() {
return this.storage[this.storage.length - 1];
}
}
const myStack = new Stack();
myStack.push(1).push(2).push(3);
console.log(myStack.peek()); // 3
myStack.pop();
console.log(myStack.peek()); // 2
myStack.push("js-cheatsheet");
console.log(myStack.size()); // 3
console.log(myStack.peek()); // js-cheatsheet
A simplified simulation of Twitter's core features using JavaScript classes. Implements functionality for posting tweets, following/unfollowing users, and generating a personalized news feed.
Key features:
postTweet(userId, tweetId)
– Posts a tweet for a user.follow(followerId, followeeId)
– Allows one user to follow another.unfollow(followerId, followeeId)
– Allows a user to unfollow someone (except themselves).getNewsFeed(userId)
– Returns the 10 most recent tweets from the user and users they follow.
Demonstrates how to work with Map
, Set
, arrays, and sorting for feed generation.
class Twitter {
constructor() {
this.follows = new Map();
this.tweets = new Map();
this.timestamp = 0;
}
postTweet(userId, tweetId) {
if (!this.tweets.has(userId)) {
this.tweets.set(userId, []);
}
this.tweets.get(userId).unshift({ tweetId, timestamp: this.timestamp++ });
if (!this.follows.has(userId)) {
this.follows.set(userId, new Set());
// User follows themselves
this.follows.get(userId).add(userId);
}
}
getNewsFeed(userId) {
if (!this.follows.has(userId)) return [];
const followed = this.follows.get(userId);
const feed = [];
for (const followeeId of followed) {
if (this.tweets.has(followeeId)) {
feed.push(...this.tweets.get(followeeId));
}
}
feed.sort((a, b) => b.timestamp - a.timestamp);
return feed.map((tweet) => tweet.tweetId);
}
follow(followerId, followeeId) {
if (!this.follows.has(followerId)) {
this.follows.set(followerId, new Set());
// User follows themselves
this.follows.get(followerId).add(followerId);
}
this.follows.get(followerId).add(followeeId);
}
unfollow(followerId, followeeId) {
// Cannot unfollow oneself
if (followerId === followeeId) return;
if (this.follows.has(followerId)) {
this.follows.get(followerId).delete(followeeId);
}
}
}
const twitter = new Twitter();
// User 1 posts a tweet with ID 5
twitter.postTweet(1, 5);
// User 1 retrieves their news feed (should contain only tweet 5)
console.log(twitter.getNewsFeed(1)); // [5]
// User 1 follows User 2
twitter.follow(1, 2);
// User 2 posts a tweet with ID 6
twitter.postTweet(2, 6);
// User 1 retrieves their news feed (should contain tweets 6 and 5, most recent first)
console.log(twitter.getNewsFeed(1)); // [6, 5]
// User 1 unfollows User 2
twitter.unfollow(1, 2);
// User 1 retrieves their news feed (should only contain their own tweet, 5)
console.log(twitter.getNewsFeed(1)); // [5]