JavaScript Programming Labs

Master JavaScript through hands-on coding challenges. Write real code, get instant feedback, and build practical web development skills.

Generators, Async Iterators & Proxy - Module 10

Create custom iterables, stream async data with async generators, and intercept operations with Proxy/Reflect.

Lab 28: Generators & Iterables
Advanced
Coding Challenge
Your Task: Use generator functions to build sequences and define custom iterables using Symbol.iterator.

Detailed Requirements:

1. Create a generator function with function* that yields a few values and then returns.
function* idGenerator() { yield 1; yield 2; yield 3; return 4; // not iterated by for...of } const g = idGenerator(); console.log(g.next()); // { value: 1, done: false } console.log(g.next()); // { value: 2, done: false }
2. Iterate a generator with for...of and via manual next() calls.
for (const n of idGenerator()) { console.log(n); // 1, 2, 3 } const it = idGenerator(); console.log(it.next().value); // 1
3. Create a custom iterable object that implements [Symbol.iterator]() and returns an iterator with next(). const range = (start, end) => ({ start, end, [Symbol.iterator]() { let cur = this.start; return { next: () => ({ value: cur, done: cur++ > end }) }; } }); console.log([...range(1, 5)]); // [1,2,3,4,5]
4. Delegate iteration with yield* to compose generators.
function* letters() { yield* ['A', 'B', 'C']; } for (const ch of letters()) console.log(ch); // A B C
5. Early close a generator using return() and observe done: true. const gen = idGenerator(); console.log(gen.return('stop')); // { value: 'stop', done: true }
6. Spread generator results into an array: [...generator].

Requirements Checklist

Define a generator function (function*)
Use yield at least once
Consume a generator via next()
Iterate with for...of
Implement a custom iterable (Symbol.iterator)
Use spread to collect values
Console Output
// Click "Run Code" to analyze your JavaScript
Hints & Tips
• Generator: function* gen(){ yield 1; } then gen().next()
• Custom iterable: implement [Symbol.iterator]() returning an object with next()
• Delegate with yield* to another iterable
• Spread a generator: [...gen()]
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 29: Async Iterators & Async Generators
Advanced
Coding Challenge
Your Task: Stream asynchronous data using async function*, consume with for await...of, and implement Symbol.asyncIterator.

Detailed Requirements:

1. Create an async generator with async function* that awaits between yields. const delay = (ms) => new Promise(r => setTimeout(r, ms)); async function* asyncCounter(max) { for (let i = 1; i <= max; i++) { await delay(100); yield i; } }
2. Consume with for await...of to handle the yielded Promises. (async () => { for await (const n of asyncCounter(3)) { console.log('n =', n); } })();
3. Manual async iteration by calling next() and await its result. (async () => { const it = asyncCounter(2); console.log(await it.next()); // { value: 1, done: false } })();
4. Create a custom async iterable using [Symbol.asyncIterator](). const asyncRange = (start, end, step = 1) => ({ start, end, step, async *[Symbol.asyncIterator]() { for (let v = this.start; v <= this.end; v += this.step) { await delay(50); yield v; } } });
5. Handle errors in an async generator with try/catch. async function* risky() { try { yield 1; throw new Error('boom'); } catch (e) { yield 'handled:' + e.message; } }
6. Use for await with custom async iterable: for await (const v of asyncRange(...)).

Requirements Checklist

Define an async generator (async function*)
Use await inside the async generator
Consume with for await...of
Implement Symbol.asyncIterator
Manually await iterator.next()
Handle errors with try/catch
Console Output
// Click "Run Code" to analyze your JavaScript
Hints & Tips
• Async generator: async function* gen(){ await x; yield y; }
• Consume: for await (const x of gen()) { ... }
• Custom async iterable implements [Symbol.asyncIterator]()
• Manual step: await iterator.next()
• Use try/catch for error handling
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 30: Proxy & Reflect
Advanced
Coding Challenge
Your Task: Intercept operations on objects and functions using Proxy and use Reflect to forward operations safely.

Detailed Requirements:

1. Create a Proxy around an object to log reads/writes. const target = { role: 'user' }; const handler = { get(target, prop, receiver) { console.log('get', prop); return Reflect.get(target, prop, receiver); }, set(target, prop, value, receiver) { console.log('set', prop, value); return Reflect.set(target, prop, value, receiver); } }; const user = new Proxy(target, handler); user.name = 'Alice'; console.log(user.name);
2. Validate writes in set (e.g., ensure age is a number) and block invalid data. const validator = { set(obj, prop, value) { if (prop === 'age' && typeof value !== 'number') throw new TypeError('age must be number'); return Reflect.set(obj, prop, value); } }; const safeUser = new Proxy({}, validator); // safeUser.age = 'x' // throws
3. Intercept "in" checks with has trap and delete with deleteProperty. const audit = { has(t, p) { console.log('has', p); return Reflect.has(t, p); }, deleteProperty(t, p) { console.log('delete', p); return Reflect.deleteProperty(t, p); } }; const audited = new Proxy({ a: 1 }, audit); console.log('a' in audited); delete audited.a;
4. Proxy a function (use apply) or a constructor (construct). function sum(a, b) { return a + b; } const fnProxy = new Proxy(sum, { apply(target, thisArg, args) { console.log('apply', args); return Reflect.apply(target, thisArg, args); } }); console.log(fnProxy(2, 3)); // 5
5. Use Proxy.revocable() and show that operations fail after revoke(). const { proxy, revoke } = Proxy.revocable({ x: 1 }, {}); console.log(proxy.x); // 1 revoke(); try { console.log(proxy.x); } catch (e) { console.log('revoked'); }
6. Use Reflect methods (get, set, has, deleteProperty) inside traps.

Requirements Checklist

Create a Proxy
Implement get trap
Implement set trap with validation
Use has/deleteProperty traps
Use Proxy.revocable()
Use Reflect methods in traps
Console Output
// Click "Run Code" to analyze your JavaScript
Hints & Tips
• Basic: new Proxy(target, handler) with traps
• Validate in set, forward with Reflect.set()
• Intercept in with has(), deletes with deleteProperty()
• Functions: trap apply; constructors: trap construct
• Revocable: Proxy.revocable(target, handler)
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below