Async PAI Interactions: Mastering Promise-Based AI Communication
"In the symphony of human-AI interaction, timing is everything. Async programming ensures the music never stops."
Exercise Overview
Modern Personal AI systems must be responsive, non-blocking, and capable of handling multiple simultaneous interactions. This exercise teaches you to build PAI systems using JavaScript's powerful async capabilities, creating smooth, real-time experiences that feel natural to users.
What You'll Build
- Streaming PAI Response System - Real-time AI responses with live typing indicators
- Multi-Modal Input Processor - Handle voice, text, and gesture inputs concurrently
- Reactive Dashboard - Live PAI performance metrics and user engagement analytics
- Error-Resilient Communication - Graceful handling of network issues and AI service failures
๐ฏ Learning Checkpoint: Async JavaScript Fundamentals
Quick Quiz: Test Your Understanding
Question 1: What's the difference between Promise.all()
and Promise.allSettled()
for PAI systems?
Click to reveal answer
Answer:
Promise.all()
fails fast - if any PAI service fails, the entire operation failsPromise.allSettled()
waits for all services to complete, giving you results for successful operations even if some fail
PAI Use Case:
1// Promise.all() - stops at first failure2const [voiceResponse, textResponse, visualResponse] = await Promise.all([3 generateVoiceResponse(userInput),4 generateTextResponse(userInput),5 generateVisualResponse(userInput) // If this fails, you lose everything6]);78// Promise.allSettled() - resilient to failures9const responses = await Promise.allSettled([10 generateVoiceResponse(userInput),11 generateTextResponse(userInput),12 generateVisualResponse(userInput)13]);1415// Still get successful responses even if one fails16const successfulResponses = responses17 .filter(result => result.status === 'fulfilled')18 .map(result => result.value);
๐ Exercise 1: Streaming PAI Response System
Challenge: Build a Real-Time AI Response Stream
Create a PAI system that streams responses in real-time, similar to how ChatGPT displays responses token by token.
Code Template
1// PAI Response Streaming System2class StreamingPAIEngine {3 constructor(apiEndpoint) {4 this.apiEndpoint = apiEndpoint;5 this.activeStreams = new Map();6 this.responseCache = new Map();7 }89 // TODO: Implement streaming response with proper async handling10 async *streamResponse(userInput, options = {}) {11 const streamId = this.generateStreamId();1213 try {14 // TODO: Initialize the stream with loading indicator15 yield { type: 'start', streamId, timestamp: Date.now() };1617 // TODO: Simulate API call with chunks of response18 const response = await this.fetchPAIResponse(userInput, options);1920 // TODO: Stream the response word by word21 const words = response.split(' ');2223 for (let i = 0; i < words.length; i++) {24 // TODO: Yield each word with appropriate delay25 await this.simulateTypingDelay();2627 yield {28 type: 'chunk',29 streamId,30 content: words[i] + ' ',31 progress: (i + 1) / words.length,32 timestamp: Date.now()33 };34 }3536 // TODO: Signal completion37 yield {38 type: 'complete',39 streamId,40 fullResponse: response,41 timestamp: Date.now()42 };4344 } catch (error) {45 // TODO: Handle streaming errors gracefully46 yield {47 type: 'error',48 streamId,49 error: error.message,50 timestamp: Date.now()51 };52 } finally {53 // TODO: Cleanup stream resources54 this.activeStreams.delete(streamId);55 }56 }5758 // TODO: Implement concurrent PAI processing59 async processMultipleInputs(inputs) {60 console.log(`Processing ${inputs.length} inputs concurrently...`);6162 // TODO: Use Promise.allSettled for resilient processing63 const promises = inputs.map(async (input, index) => {64 try {65 // TODO: Add jitter to prevent thundering herd66 const delay = Math.random() * 1000;67 await this.delay(delay);6869 const response = await this.fetchPAIResponse(input.text, input.options);7071 return {72 index,73 status: 'success',74 input: input.text,75 response,76 processingTime: Date.now() - input.timestamp77 };78 } catch (error) {79 return {80 index,81 status: 'error',82 input: input.text,83 error: error.message,84 processingTime: Date.now() - input.timestamp85 };86 }87 });8889 // TODO: Wait for all processing to complete90 const results = await Promise.allSettled(promises);9192 // TODO: Separate successful and failed results93 const successful = results.filter(r => r.status === 'fulfilled');94 const failed = results.filter(r => r.status === 'rejected');9596 console.log(`โ ${successful.length} successful, โ ${failed.length} failed`);9798 return { successful, failed, total: inputs.length };99 }100101 // TODO: Implement smart response caching102 async getCachedOrFetchResponse(userInput, options = {}) {103 const cacheKey = this.generateCacheKey(userInput, options);104105 // TODO: Check cache first106 if (this.responseCache.has(cacheKey)) {107 console.log('๐พ Cache hit for:', userInput.substring(0, 30) + '...');108 return {109 response: this.responseCache.get(cacheKey),110 fromCache: true,111 timestamp: Date.now()112 };113 }114115 // TODO: Fetch fresh response116 console.log('๐ Fetching fresh response for:', userInput.substring(0, 30) + '...');117118 try {119 const response = await this.fetchPAIResponse(userInput, options);120121 // TODO: Cache the response with TTL122 this.responseCache.set(cacheKey, response);123124 // TODO: Implement cache eviction after 5 minutes125 setTimeout(() => {126 this.responseCache.delete(cacheKey);127 console.log('๐๏ธ Evicted cache for:', cacheKey);128 }, 5 * 60 * 1000);129130 return {131 response,132 fromCache: false,133 timestamp: Date.now()134 };135136 } catch (error) {137 // TODO: Handle fetch errors138 throw new Error(`PAI fetch failed: ${error.message}`);139 }140 }141142 // Helper methods (TODO: Implement these)143 generateStreamId() {144 return 'stream_' + Math.random().toString(36).substr(2, 9);145 }146147 generateCacheKey(input, options) {148 return btoa(JSON.stringify({ input, options }));149 }150151 async simulateTypingDelay() {152 // TODO: Simulate realistic typing speed (30-60 WPM)153 const baseDelay = 100; // milliseconds154 const randomJitter = Math.random() * 50;155 await this.delay(baseDelay + randomJitter);156 }157158 async delay(ms) {159 return new Promise(resolve => setTimeout(resolve, ms));160 }161162 async fetchPAIResponse(userInput, options) {163 // TODO: Simulate API call with realistic delay164 const processingTime = Math.random() * 2000 + 500; // 500-2500ms165 await this.delay(processingTime);166167 // TODO: Simulate occasional failures168 if (Math.random() < 0.1) { // 10% failure rate169 throw new Error('PAI service temporarily unavailable');170 }171172 // TODO: Generate contextual response173 const responses = [174 `Based on your input "${userInput}", I understand you're looking for assistance with PAI development.`,175 `That's an interesting question about "${userInput}". Let me provide a comprehensive response.`,176 `I can help you with "${userInput}". Here's what I think would be most valuable.`,177 `Great question about "${userInput}"! This touches on several important PAI concepts.`178 ];179180 return responses[Math.floor(Math.random() * responses.length)];181 }182}183184// TODO: Implement the User Interface Controller185class PAIStreamingUI {186 constructor(paiEngine) {187 this.paiEngine = paiEngine;188 this.activeStreams = new Set();189 this.setupEventListeners();190 }191192 setupEventListeners() {193 // TODO: Set up input handlers194 const inputElement = document.getElementById('user-input');195 const sendButton = document.getElementById('send-button');196197 sendButton?.addEventListener('click', () => this.handleUserInput());198 inputElement?.addEventListener('keypress', (e) => {199 if (e.key === 'Enter' && !e.shiftKey) {200 e.preventDefault();201 this.handleUserInput();202 }203 });204 }205206 async handleUserInput() {207 const inputElement = document.getElementById('user-input');208 const userInput = inputElement?.value.trim();209210 if (!userInput) return;211212 // TODO: Clear input and show typing indicator213 inputElement.value = '';214 this.showTypingIndicator();215216 try {217 // TODO: Create response container218 const responseContainer = this.createResponseContainer();219220 // TODO: Stream the response221 const responseStream = this.paiEngine.streamResponse(userInput);222223 for await (const chunk of responseStream) {224 this.handleStreamChunk(chunk, responseContainer);225 }226227 } catch (error) {228 this.showError(error.message);229 } finally {230 this.hideTypingIndicator();231 }232 }233234 handleStreamChunk(chunk, container) {235 switch (chunk.type) {236 case 'start':237 // TODO: Initialize response display238 container.innerHTML = '<span class="cursor">โ</span>';239 break;240241 case 'chunk':242 // TODO: Append new content243 const existingText = container.textContent.replace('โ', '');244 container.innerHTML = existingText + chunk.content + '<span class="cursor">โ</span>';245246 // TODO: Auto-scroll to bottom247 container.scrollIntoView({ behavior: 'smooth', block: 'end' });248 break;249250 case 'complete':251 // TODO: Remove cursor and finalize252 container.innerHTML = chunk.fullResponse;253 container.classList.add('complete');254 break;255256 case 'error':257 // TODO: Show error state258 container.innerHTML = `<span class="error">โ ${chunk.error}</span>`;259 break;260 }261 }262263 // TODO: Implement UI helper methods264 createResponseContainer() {265 const container = document.createElement('div');266 container.className = 'pai-response streaming';267 document.getElementById('chat-container')?.appendChild(container);268 return container;269 }270271 showTypingIndicator() {272 // TODO: Show "PAI is thinking..." indicator273 const indicator = document.getElementById('typing-indicator');274 if (indicator) {275 indicator.style.display = 'block';276 indicator.innerHTML = '๐ค PAI is thinking...';277 }278 }279280 hideTypingIndicator() {281 const indicator = document.getElementById('typing-indicator');282 if (indicator) {283 indicator.style.display = 'none';284 }285 }286287 showError(message) {288 const errorContainer = document.createElement('div');289 errorContainer.className = 'error-message';290 errorContainer.innerHTML = `โ Error: ${message}`;291 document.getElementById('chat-container')?.appendChild(errorContainer);292 }293}294295// TODO: Test your implementation296async function testStreamingPAI() {297 const paiEngine = new StreamingPAIEngine('https://api.example.com/pai');298 const ui = new PAIStreamingUI(paiEngine);299300 // Test 1: Single streaming response301 console.log('๐งช Test 1: Single streaming response');302 const singleStream = paiEngine.streamResponse('How does async JavaScript work?');303304 for await (const chunk of singleStream) {305 console.log('Chunk:', chunk);306 }307308 // Test 2: Multiple concurrent inputs309 console.log('\n๐งช Test 2: Multiple concurrent inputs');310 const multipleInputs = [311 { text: 'Explain duck typing', options: {}, timestamp: Date.now() },312 { text: 'What is async/await?', options: {}, timestamp: Date.now() },313 { text: 'How do promises work?', options: {}, timestamp: Date.now() }314 ];315316 const results = await paiEngine.processMultipleInputs(multipleInputs);317 console.log('Batch results:', results);318319 // Test 3: Caching behavior320 console.log('\n๐งช Test 3: Caching behavior');321 const input = 'What is PAI development?';322323 const first = await paiEngine.getCachedOrFetchResponse(input);324 console.log('First call:', first);325326 const second = await paiEngine.getCachedOrFetchResponse(input);327 console.log('Second call (should be cached):', second);328}329330// Run tests if in Node.js environment331if (typeof window === 'undefined') {332 testStreamingPAI().catch(console.error);333}
Your Implementation
Fill in the missing parts marked with // TODO:
and ________
. Focus on:
- Proper async/await usage for streaming responses
- Error handling that doesn't break the user experience
- Promise.allSettled() for resilient concurrent processing
- Efficient caching with automatic cleanup
- Realistic simulation of AI service behavior
๐ก Hint for Exercise 1
Key Patterns to Implement:
- Generator Functions: Use
async function*
for streaming - Promise.allSettled(): For resilient batch processing
- Map() for tracking: Keep track of active streams and cache
- setTimeout for cleanup: Automatic cache eviction
- Try/catch/finally: Proper error boundaries
Example Pattern:
1try {2 const results = await Promise.allSettled(promises);3 // Process results regardless of individual failures4} catch (error) {5 // Handle overall system errors6} finally {7 // Always cleanup resources8}
๐ Exercise 2: Multi-Modal Input Processing
Challenge: Handle Voice, Text, and Gesture Inputs Concurrently
Build a system that can process multiple types of user input simultaneously without blocking.
Code Template
1// Multi-Modal PAI Input Processor2class MultiModalPAIProcessor {3 constructor() {4 this.inputProcessors = {5 voice: new VoiceInputProcessor(),6 text: new TextInputProcessor(),7 gesture: new GestureInputProcessor(),8 neural: new NeuralInputProcessor()9 };1011 this.eventEmitter = new EventTarget();12 this.processingQueue = [];13 this.isProcessing = false;14 }1516 // TODO: Implement concurrent input processing17 async processInput(inputData, modality) {18 console.log(`๐ฅ Processing ${modality} input:`, inputData.preview);1920 try {21 // TODO: Get the appropriate processor22 const processor = this.inputProcessors[modality];2324 if (!processor) {25 throw new Error(`No processor found for modality: ${modality}`);26 }2728 // TODO: Process input with timeout protection29 const timeoutPromise = new Promise((_, reject) => {30 setTimeout(() => reject(new Error('Input processing timeout')), 10000);31 });3233 const processingPromise = processor.processInput(inputData);3435 // TODO: Race between processing and timeout36 const result = await Promise.race([processingPromise, timeoutPromise]);3738 // TODO: Emit success event39 this.eventEmitter.dispatchEvent(new CustomEvent('inputProcessed', {40 detail: {41 modality,42 inputData,43 result,44 timestamp: Date.now()45 }46 }));4748 return result;4950 } catch (error) {51 // TODO: Emit error event52 this.eventEmitter.dispatchEvent(new CustomEvent('inputError', {53 detail: {54 modality,55 inputData,56 error: error.message,57 timestamp: Date.now()58 }59 }));6061 throw error;62 }63 }6465 // TODO: Implement smart input fusion66 async fuseMultiModalInputs(inputs) {67 console.log(`๐ Fusing ${inputs.length} multi-modal inputs`);6869 // TODO: Process all inputs concurrently70 const processingPromises = inputs.map(async (input) => {71 try {72 const result = await this.processInput(input.data, input.modality);73 return {74 modality: input.modality,75 success: true,76 result,77 confidence: result.confidence || 0.5,78 timestamp: Date.now()79 };80 } catch (error) {81 return {82 modality: input.modality,83 success: false,84 error: error.message,85 confidence: 0,86 timestamp: Date.now()87 };88 }89 });9091 // TODO: Wait for all to complete (don't fail fast)92 const results = await Promise.allSettled(processingPromises);9394 // TODO: Implement fusion algorithm95 const successfulResults = results96 .filter(r => r.status === 'fulfilled' && r.value.success)97 .map(r => r.value);9899 if (successfulResults.length === 0) {100 throw new Error('All input modalities failed to process');101 }102103 // TODO: Weighted fusion based on confidence scores104 const fusedResult = this.weightedFusion(successfulResults);105106 return {107 fusedResult,108 individualResults: results,109 processingTime: Date.now() - inputs[0].timestamp110 };111 }112113 // TODO: Implement weighted fusion algorithm114 weightedFusion(results) {115 // TODO: Calculate total confidence116 const totalConfidence = results.reduce((sum, r) => sum + r.confidence, 0);117118 if (totalConfidence === 0) {119 // TODO: Fallback to simple average120 return {121 intent: 'unclear',122 confidence: 0,123 text: 'Could not determine user intent',124 modalities: results.map(r => r.modality)125 };126 }127128 // TODO: Weighted average of results129 let fusedText = '';130 let fusedIntent = '';131 let maxConfidence = 0;132133 results.forEach(result => {134 const weight = result.confidence / totalConfidence;135136 // TODO: Choose highest confidence intent137 if (result.confidence > maxConfidence) {138 maxConfidence = result.confidence;139 fusedIntent = result.result.intent;140 }141142 // TODO: Concatenate text with weights143 if (result.result.text) {144 fusedText += `[${result.modality}:${(weight * 100).toFixed(1)}%] ${result.result.text} `;145 }146 });147148 return {149 intent: fusedIntent,150 confidence: maxConfidence,151 text: fusedText.trim(),152 modalities: results.map(r => r.modality),153 fusionWeights: results.map(r => ({154 modality: r.modality,155 weight: r.confidence / totalConfidence156 }))157 };158 }159}160161// TODO: Implement individual input processors162class VoiceInputProcessor {163 async processInput(audioData) {164 // TODO: Simulate voice recognition processing165 await this.delay(Math.random() * 1500 + 500); // 500-2000ms166167 // TODO: Simulate occasional recognition failures168 if (Math.random() < 0.15) { // 15% failure rate169 throw new Error('Voice recognition failed - unclear audio');170 }171172 // TODO: Return processed voice data173 return {174 text: audioData.transcript || 'Simulated voice transcription',175 intent: this.detectIntent(audioData.transcript),176 confidence: Math.random() * 0.4 + 0.6, // 0.6-1.0177 language: audioData.language || 'en',178 processingTime: Date.now() - audioData.timestamp179 };180 }181182 detectIntent(text) {183 // TODO: Simple intent detection184 const intents = {185 'hello': 'greeting',186 'help': 'assistance',187 'what': 'question',188 'how': 'tutorial',189 'show': 'demonstration',190 'explain': 'explanation'191 };192193 for (const [keyword, intent] of Object.entries(intents)) {194 if (text?.toLowerCase().includes(keyword)) {195 return intent;196 }197 }198199 return 'general';200 }201202 delay(ms) {203 return new Promise(resolve => setTimeout(resolve, ms));204 }205}206207class TextInputProcessor {208 async processInput(textData) {209 // TODO: Simulate text processing (faster than voice)210 await this.delay(Math.random() * 300 + 100); // 100-400ms211212 return {213 text: textData.content,214 intent: this.detectIntent(textData.content),215 confidence: 0.9, // Text is generally more reliable216 sentiment: this.analyzeSentiment(textData.content),217 processingTime: Date.now() - textData.timestamp218 };219 }220221 detectIntent(text) {222 // TODO: More sophisticated text intent detection223 if (text.includes('?')) return 'question';224 if (text.includes('please') || text.includes('can you')) return 'request';225 if (text.includes('thank')) return 'gratitude';226 if (text.includes('hello') || text.includes('hi')) return 'greeting';227 return 'statement';228 }229230 analyzeSentiment(text) {231 // TODO: Simple sentiment analysis232 const positiveWords = ['good', 'great', 'awesome', 'excellent', 'amazing'];233 const negativeWords = ['bad', 'terrible', 'awful', 'horrible', 'disappointing'];234235 const positive = positiveWords.some(word => text.toLowerCase().includes(word));236 const negative = negativeWords.some(word => text.toLowerCase().includes(word));237238 if (positive && !negative) return 'positive';239 if (negative && !positive) return 'negative';240 return 'neutral';241 }242243 delay(ms) {244 return new Promise(resolve => setTimeout(resolve, ms));245 }246}247248class GestureInputProcessor {249 async processInput(gestureData) {250 // TODO: Simulate gesture recognition processing251 await this.delay(Math.random() * 1000 + 800); // 800-1800ms252253 // TODO: Higher failure rate for gestures254 if (Math.random() < 0.25) { // 25% failure rate255 throw new Error('Gesture not recognized');256 }257258 return {259 text: `Gesture: ${gestureData.type}`,260 intent: this.mapGestureToIntent(gestureData.type),261 confidence: Math.random() * 0.3 + 0.4, // 0.4-0.7262 gestureType: gestureData.type,263 processingTime: Date.now() - gestureData.timestamp264 };265 }266267 mapGestureToIntent(gestureType) {268 const gestureMap = {269 'wave': 'greeting',270 'point': 'selection',271 'thumbs_up': 'approval',272 'thumbs_down': 'disapproval',273 'swipe_left': 'navigation',274 'swipe_right': 'navigation',275 'tap': 'interaction'276 };277278 return gestureMap[gestureType] || 'unknown_gesture';279 }280281 delay(ms) {282 return new Promise(resolve => setTimeout(resolve, ms));283 }284}285286// TODO: Implement the main test function287async function testMultiModalProcessing() {288 const processor = new MultiModalPAIProcessor();289290 // TODO: Set up event listeners291 processor.eventEmitter.addEventListener('inputProcessed', (event) => {292 console.log('โ Input processed:', event.detail);293 });294295 processor.eventEmitter.addEventListener('inputError', (event) => {296 console.log('โ Input error:', event.detail);297 });298299 // Test 1: Single modality processing300 console.log('๐งช Test 1: Single modality processing');301302 try {303 const voiceResult = await processor.processInput({304 transcript: 'Hello, can you help me?',305 timestamp: Date.now(),306 preview: 'Hello, can you help me?'307 }, 'voice');308309 console.log('Voice result:', voiceResult);310 } catch (error) {311 console.log('Voice processing failed:', error.message);312 }313314 // Test 2: Multi-modal fusion315 console.log('\n๐งช Test 2: Multi-modal fusion');316317 const multiModalInputs = [318 {319 modality: 'voice',320 data: {321 transcript: 'Show me the weather',322 timestamp: Date.now(),323 preview: 'Show me the weather'324 }325 },326 {327 modality: 'text',328 data: {329 content: 'What is the weather like today?',330 timestamp: Date.now(),331 preview: 'What is the weather like today?'332 }333 },334 {335 modality: 'gesture',336 data: {337 type: 'point',338 timestamp: Date.now(),339 preview: 'pointing gesture'340 }341 }342 ];343344 try {345 const fusionResult = await processor.fuseMultiModalInputs(multiModalInputs);346 console.log('Fusion result:', fusionResult);347 } catch (error) {348 console.log('Multi-modal fusion failed:', error.message);349 }350}351352// Run test353testMultiModalProcessing().catch(console.error);
๐จ Whiteboard Exercise: Async PAI Architecture Design
Challenge: Design Your Async PAI System Architecture
Instructions:
- Open the whiteboard tool
- Design an async PAI system showing:
- Multiple input sources (voice, text, gesture, neural)
- Async processing pipelines
- Error handling boundaries
- Caching layers
- Real-time UI updates
Consider These Questions:
- How do you handle partial failures in multi-modal input?
- Where should caching be implemented for best performance?
- How do you prevent race conditions in concurrent processing?
- What's your strategy for handling network timeouts?
Bonus: Add timing diagrams showing async operation flows.
๐ Performance Challenge: Optimizing Concurrent Operations
Challenge: Benchmark and Optimize Your Async Code
Test different approaches to concurrent processing:
1// Performance Testing Suite2class AsyncPerformanceTester {3 constructor() {4 this.testResults = [];5 }67 async benchmarkApproach(name, testFunction, iterations = 100) {8 console.log(`๐โโ๏ธ Benchmarking: ${name}`);910 const startTime = performance.now();11 const promises = [];1213 for (let i = 0; i < iterations; i++) {14 promises.push(testFunction());15 }1617 // TODO: Choose the right Promise method for your test18 const results = await Promise.all(promises);1920 const endTime = performance.now();21 const duration = endTime - startTime;2223 const result = {24 name,25 duration: duration.toFixed(2),26 throughput: (iterations / (duration / 1000)).toFixed(2),27 successRate: this.calculateSuccessRate(results),28 timestamp: Date.now()29 };3031 this.testResults.push(result);32 console.log(`โ ${name}: ${result.duration}ms, ${result.throughput} ops/sec`);3334 return result;35 }3637 // TODO: Test different concurrency patterns38 async runPerformanceTests() {39 // Test 1: Promise.all (fail-fast)40 await this.benchmarkApproach('Promise.all', async () => {41 const promises = [42 this.simulateAPICall(100),43 this.simulateAPICall(150),44 this.simulateAPICall(200)45 ];46 return Promise.all(promises);47 });4849 // Test 2: Promise.allSettled (resilient)50 await this.benchmarkApproach('Promise.allSettled', async () => {51 const promises = [52 this.simulateAPICall(100),53 this.simulateAPICall(150),54 this.simulateAPICall(200)55 ];56 return Promise.allSettled(promises);57 });5859 // Test 3: Sequential processing60 await this.benchmarkApproach('Sequential', async () => {61 await this.simulateAPICall(100);62 await this.simulateAPICall(150);63 await this.simulateAPICall(200);64 });6566 // TODO: Analyze and display results67 this.displayResults();68 }6970 async simulateAPICall(delay) {71 await new Promise(resolve => setTimeout(resolve, delay));7273 // TODO: Simulate random failures74 if (Math.random() < 0.1) {75 throw new Error('Simulated API failure');76 }7778 return { success: true, delay };79 }8081 calculateSuccessRate(results) {82 if (!Array.isArray(results)) return 100;8384 const successful = results.filter(r =>85 r.status === 'fulfilled' || (r.status !== 'rejected' && !r.error)86 ).length;8788 return ((successful / results.length) * 100).toFixed(1);89 }9091 displayResults() {92 console.log('\n๐ Performance Test Results:');93 console.table(this.testResults);9495 // TODO: Find the fastest approach96 const fastest = this.testResults.reduce((prev, current) =>97 parseFloat(prev.duration) < parseFloat(current.duration) ? prev : current98 );99100 console.log(`๐ Fastest approach: ${fastest.name} (${fastest.duration}ms)`);101 }102}103104// TODO: Run performance tests105const tester = new AsyncPerformanceTester();106tester.runPerformanceTests().catch(console.error);
Analysis Questions:
-
When should you use
Promise.all()
vsPromise.allSettled()
?- Promise.all(): ____________
- Promise.allSettled(): ____________
-
How does concurrent processing compare to sequential?
- Performance difference: ____________
- Error handling difference: ____________
-
What patterns work best for PAI systems?
- Real-time responses: ____________
- Batch processing: ____________
- Error-critical operations: ____________
๐ Advanced Challenge: Error-Resilient PAI Network
Challenge: Build a Self-Healing PAI Communication System
Create a system that gracefully handles network issues, service outages, and partial failures:
1class ResilientPAINetwork {2 constructor(endpoints) {3 this.endpoints = endpoints;4 this.circuitBreakers = new Map();5 this.retryStrategies = new Map();6 this.healthStatus = new Map();78 // TODO: Initialize circuit breakers for each endpoint9 endpoints.forEach(endpoint => {10 this.circuitBreakers.set(endpoint, new CircuitBreaker(endpoint));11 this.healthStatus.set(endpoint, 'unknown');12 });1314 // TODO: Start health monitoring15 this.startHealthMonitoring();16 }1718 // TODO: Implement circuit breaker pattern19 async callWithCircuitBreaker(endpoint, operation) {20 const circuitBreaker = this.circuitBreakers.get(endpoint);2122 if (circuitBreaker.isOpen()) {23 throw new Error(`Circuit breaker OPEN for ${endpoint}`);24 }2526 try {27 const result = await operation();28 circuitBreaker.recordSuccess();29 return result;30 } catch (error) {31 circuitBreaker.recordFailure();32 throw error;33 }34 }3536 // TODO: Implement smart retry with exponential backoff37 async retryWithBackoff(operation, maxRetries = 3) {38 for (let attempt = 1; attempt <= maxRetries; attempt++) {39 try {40 return await operation();41 } catch (error) {42 if (attempt === maxRetries) {43 throw error;44 }4546 // TODO: Exponential backoff with jitter47 const baseDelay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s48 const jitter = Math.random() * 1000; // 0-1s jitter49 const delay = baseDelay + jitter;5051 console.log(`โณ Retry attempt ${attempt}/${maxRetries} in ${delay}ms`);52 await new Promise(resolve => setTimeout(resolve, delay));53 }54 }55 }5657 // TODO: Implement health monitoring58 startHealthMonitoring() {59 setInterval(async () => {60 for (const endpoint of this.endpoints) {61 try {62 const startTime = Date.now();63 await this.healthCheck(endpoint);64 const responseTime = Date.now() - startTime;6566 this.healthStatus.set(endpoint, {67 status: 'healthy',68 responseTime,69 lastCheck: Date.now()70 });7172 } catch (error) {73 this.healthStatus.set(endpoint, {74 status: 'unhealthy',75 error: error.message,76 lastCheck: Date.now()77 });78 }79 }80 }, 30000); // Check every 30 seconds81 }8283 async healthCheck(endpoint) {84 // TODO: Implement health check85 const timeout = new Promise((_, reject) =>86 setTimeout(() => reject(new Error('Health check timeout')), 5000)87 );8889 const healthRequest = fetch(`${endpoint}/health`);9091 return Promise.race([healthRequest, timeout]);92 }9394 // TODO: Get healthy endpoints for load balancing95 getHealthyEndpoints() {96 return this.endpoints.filter(endpoint => {97 const health = this.healthStatus.get(endpoint);98 return health?.status === 'healthy';99 });100 }101}102103// TODO: Circuit Breaker Implementation104class CircuitBreaker {105 constructor(endpoint, threshold = 5, timeout = 60000) {106 this.endpoint = endpoint;107 this.threshold = threshold;108 this.timeout = timeout;109 this.failureCount = 0;110 this.lastFailureTime = null;111 this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN112 }113114 isOpen() {115 if (this.state === 'OPEN') {116 // TODO: Check if timeout period has passed117 if (Date.now() - this.lastFailureTime > this.timeout) {118 this.state = 'HALF_OPEN';119 return false;120 }121 return true;122 }123 return false;124 }125126 recordSuccess() {127 this.failureCount = 0;128 this.state = 'CLOSED';129 }130131 recordFailure() {132 this.failureCount++;133 this.lastFailureTime = Date.now();134135 if (this.failureCount >= this.threshold) {136 this.state = 'OPEN';137 console.log(`๐ด Circuit breaker OPEN for ${this.endpoint}`);138 }139 }140}
๐ Solution Review & Key Takeaways
Exercise Solutions
๐ Click to View Key Solutions
Exercise 1 - Key Implementations:
1// Promise.allSettled for resilient processing2const results = await Promise.allSettled(promises);34// Proper async generator5async *streamResponse(userInput, options = {}) {6 // Implementation with proper error handling7}89// Efficient caching with cleanup10setTimeout(() => {11 this.responseCache.delete(cacheKey);12}, 5 * 60 * 1000);
Exercise 2 - Multi-Modal Fusion:
1// Resilient concurrent processing2const results = await Promise.allSettled(processingPromises);34// Weighted fusion algorithm5const weightedFusion = (results) => {6 const totalConfidence = results.reduce((sum, r) => sum + r.confidence, 0);7 // Implementation...8};
Key Takeaways
โ
Use Promise.allSettled() for operations where partial success is acceptable
โ
Implement circuit breakers to prevent cascading failures
โ
Add exponential backoff for reliable retry mechanisms
โ
Stream responses for better user experience
โ
Cache intelligently with automatic cleanup
โ
Monitor health of all services continuously
โ
Handle timeouts gracefully to prevent hanging operations
Performance Insights
- Concurrent processing can be 3-5x faster than sequential
- Promise.allSettled() provides better resilience with only 10-20% performance overhead
- Caching can reduce response times by 80-90%
- Circuit breakers prevent up to 95% of unnecessary failed requests
Next Steps
- Implement real API integration using these patterns
- Add metrics collection for monitoring performance
- Build error recovery mechanisms for critical failures
- Explore WebRTC for real-time voice processing
- Study the next exercise: "Real-time PAI WebSocket Communication"
Congratulations! You've mastered async JavaScript patterns for responsive PAI systems. Your AI can now handle multiple inputs gracefully and recover from failures automatically. ๐