Prerequisites
- Understanding of Promise fundamentals ๐
- Experience with Promise.race and Promise.allSettled โก
- Basic error handling knowledge ๐ป
What you'll learn
- Master Promise.any for optimistic success scenarios ๐ฏ
- Build resilient fallback systems with multiple attempts ๐๏ธ
- Handle AggregateError exceptions properly ๐
- Create fault-tolerant applications with graceful degradation โจ
๐ฏ Introduction
Welcome to the world of optimistic Promise handling! ๐ While Promise.race gives you the first to finish (success or failure), and Promise.allSettled waits for everyone, Promise.any()
is the eternal optimist - it keeps trying until it finds that first success!
Think of Promise.any as your most encouraging friend ๐ - the one who keeps saying โDonโt worry, one of these will work!โ Itโs perfect for scenarios where you have multiple fallback options and you just need ONE to succeed.
By the end of this tutorial, youโll master the art of optimistic async programming, building systems that gracefully try multiple approaches until they find success. Letโs dive into the sunshine side of Promise handling! โ๏ธ
๐ Understanding Promise.any()
๐ค What is Promise.any()?
Think of Promise.any()
as a job interview where youโre applying to multiple companies ๐ผ. You donโt need ALL of them to say yes (like Promise.all), and you donโt care who responds first regardless of the answer (like Promise.race). You just need ONE โyesโ to celebrate! ๐
// ๐ Basic Promise.any example
const attempts = [
Promise.reject(new Error("First attempt failed ๐")),
Promise.reject(new Error("Second attempt failed ๐ข")),
Promise.resolve("Third time's the charm! ๐")
];
try {
const success = await Promise.any(attempts);
console.log(success); // "Third time's the charm! ๐"
} catch (error) {
console.log("All attempts failed:", error); // Won't reach here
}
๐ก Key Characteristics
- ๐ Success Focused: Resolves with the first successful result
- ๐ Keeps Trying: Ignores failures and waits for success
- ๐จ AggregateError: Only rejects if ALL promises fail
- โก Fast Success: Returns immediately when any promise succeeds
// ๐จ TypeScript's type inference with Promise.any
const optimistic = Promise.any([
Promise.reject("nope"),
Promise.resolve("success! ๐"), // This will be the result
Promise.resolve(42) // This comes later but doesn't matter
]);
// Type: Promise<string | number>
๐ Comparison with Other Promise Methods
// ๐ Promise.race - First to finish (success OR failure)
const raceResult = await Promise.race([
Promise.reject("Fast failure"), // โ This wins and race rejects
Promise.resolve("Slow success") // Never gets a chance
]);
// ๐ Promise.any - First SUCCESS only
const anyResult = await Promise.any([
Promise.reject("Fast failure"), // ๐ Ignored, keep trying
Promise.resolve("Slow success") // โ
This is what we get!
]);
// ๐ญ Promise.allSettled - ALL results, good and bad
const settledResults = await Promise.allSettled([
Promise.reject("failure"),
Promise.resolve("success")
]);
// Returns: [{ status: 'rejected', reason: "failure" }, { status: 'fulfilled', value: "success" }]
// ๐ฏ Promise.all - ALL must succeed
const allResults = await Promise.all([
Promise.reject("One failure ruins everything"), // โ This kills the whole thing
Promise.resolve("success")
]);
๐ง Basic Syntax and Usage
๐ Working with AggregateError
When ALL promises fail, Promise.any throws an AggregateError
:
// ๐จ Understanding AggregateError
async function demonstrateAggregateError() {
const allFailing = [
Promise.reject(new Error("Service A is down ๐ฅ")),
Promise.reject(new Error("Service B timeout โฐ")),
Promise.reject(new Error("Service C unavailable ๐ก"))
];
try {
const result = await Promise.any(allFailing);
console.log("Success:", result); // Won't reach here
} catch (aggregateError) {
console.log("๐ All attempts failed!");
console.log("Error type:", aggregateError.constructor.name); // "AggregateError"
console.log("Error count:", aggregateError.errors.length); // 3
// ๐ List all the individual errors
aggregateError.errors.forEach((error: Error, index: number) => {
console.log(` ${index + 1}. ${error.message}`);
});
}
}
๐ฏ Helper Functions for Promise.any
// ๐ ๏ธ Utility functions for working with Promise.any
class PromiseAnyHelper {
// ๐ Promise.any with timeout
static withTimeout<T>(
promises: Promise<T>[],
timeoutMs: number
): Promise<T> {
const timeoutPromise = new Promise<never>((_, reject) => {
setTimeout(() => {
reject(new Error(`โฐ No success within ${timeoutMs}ms`));
}, timeoutMs);
});
return Promise.any([...promises, timeoutPromise]);
}
// ๐ฏ Promise.any with detailed result info
static async withDetails<T>(
promises: Promise<T>[]
): Promise<{ result: T; successIndex: number; attemptCount: number }> {
const indexedPromises = promises.map((promise, index) =>
promise.then(
result => ({ success: true, result, index }),
error => ({ success: false, error, index })
)
);
// ๐ Use Promise.any on the transformed promises
try {
const winner = await Promise.any(
indexedPromises.filter(p =>
p.then(r => r.success).catch(() => false)
)
);
// This is a bit complex - let's use a simpler approach
return this.raceForSuccess(promises);
} catch (error) {
throw error;
}
}
// ๐โโ๏ธ Manual implementation for educational purposes
private static async raceForSuccess<T>(
promises: Promise<T>[]
): Promise<{ result: T; successIndex: number; attemptCount: number }> {
return new Promise((resolve, reject) => {
let settledCount = 0;
let errors: any[] = [];
promises.forEach((promise, index) => {
promise
.then(result => {
// โ
First success wins!
resolve({
result,
successIndex: index,
attemptCount: settledCount + 1
});
})
.catch(error => {
errors.push(error);
settledCount++;
// ๐จ If all failed, reject with AggregateError
if (settledCount === promises.length) {
const aggregateError = new AggregateError(
errors,
"All promises failed"
);
reject(aggregateError);
}
});
});
});
}
// ๐ Retry with exponential backoff
static async retryUntilSuccess<T>(
operation: () => Promise<T>,
maxAttempts: number = 5,
baseDelay: number = 1000
): Promise<T> {
const attempts = Array.from({ length: maxAttempts }, (_, i) => {
const delay = baseDelay * Math.pow(2, i);
return new Promise<T>((resolve, reject) => {
setTimeout(async () => {
try {
const result = await operation();
resolve(result);
} catch (error) {
reject(new Error(`Attempt ${i + 1} failed: ${error.message}`));
}
}, delay);
});
});
return Promise.any(attempts);
}
}
// ๐ฎ Demo helper functions
async function demonstrateHelpers() {
// ๐ Retry with timeout
const promises = [
new Promise<string>((_, reject) =>
setTimeout(() => reject(new Error("Too slow ๐")), 2000)
),
new Promise<string>(resolve =>
setTimeout(() => resolve("Just in time! โฐ"), 1500)
)
];
try {
const result = await PromiseAnyHelper.withTimeout(promises, 1800);
console.log("โ
Success:", result);
} catch (error) {
console.log("โ Timeout or all failed:", error.message);
}
}
๐ก Practical Examples
๐ Example 1: Multi-CDN Asset Loading
Letโs build a robust asset loading system with multiple CDN fallbacks:
// ๐ CDN and asset interfaces
interface CDNEndpoint {
name: string;
baseUrl: string;
priority: number;
region: string;
emoji: string;
}
interface AssetInfo {
path: string;
type: 'image' | 'script' | 'stylesheet' | 'font';
size?: number;
cacheable: boolean;
}
interface LoadResult {
asset: AssetInfo;
cdn: CDNEndpoint;
loadTime: number;
url: string;
success: boolean;
}
class MultiCDNLoader {
private cdns: CDNEndpoint[] = [
{ name: "CloudFlare", baseUrl: "https://cdn.cloudflare.com", priority: 1, region: "global", emoji: "โ๏ธ" },
{ name: "AWS CloudFront", baseUrl: "https://d123.cloudfront.net", priority: 2, region: "us-east", emoji: "๐ " },
{ name: "Google Cloud CDN", baseUrl: "https://cdn.googleapis.com", priority: 3, region: "global", emoji: "๐ก" },
{ name: "Azure CDN", baseUrl: "https://cdn.azure.com", priority: 4, region: "us-west", emoji: "๐ต" },
{ name: "Local Backup", baseUrl: "https://backup.oursite.com", priority: 5, region: "local", emoji: "๐ " }
];
// ๐ Load asset from single CDN
private async loadFromCDN(asset: AssetInfo, cdn: CDNEndpoint): Promise<LoadResult> {
const startTime = Date.now();
const url = `${cdn.baseUrl}/${asset.path}`;
try {
// ๐ Simulate CDN loading with realistic scenarios
await new Promise((resolve, reject) => {
// ๐ฒ Different CDNs have different characteristics
const baseLatency = {
"CloudFlare": 100, // Fast global CDN
"AWS CloudFront": 150, // Good performance
"Google Cloud CDN": 120, // Reliable
"Azure CDN": 180, // Decent
"Local Backup": 300 // Slower but reliable
}[cdn.name] || 200;
const latency = baseLatency + Math.random() * 200;
const failureRate = cdn.priority * 0.08; // Higher priority = lower failure rate
setTimeout(() => {
if (Math.random() < failureRate) {
const failures = [
"Network timeout ๐ก",
"DNS resolution failed ๐",
"Connection refused ๐ซ",
"SSL handshake failed ๐",
"Rate limit exceeded ๐ฆ"
];
reject(new Error(failures[Math.floor(Math.random() * failures.length)]));
} else {
resolve(undefined);
}
}, latency);
});
const loadTime = Date.now() - startTime;
console.log(` โ
${cdn.emoji} ${cdn.name}: Loaded in ${loadTime}ms`);
return {
asset,
cdn,
loadTime,
url,
success: true
};
} catch (error) {
const loadTime = Date.now() - startTime;
console.log(` โ ${cdn.emoji} ${cdn.name}: Failed after ${loadTime}ms - ${error.message}`);
throw new Error(`${cdn.name} failed: ${error.message}`);
}
}
// ๐ Load asset with Promise.any for first success
async loadAsset(asset: AssetInfo): Promise<LoadResult> {
console.log(`๐ Loading ${asset.type}: ${asset.path}`);
console.log(`๐ก Trying ${this.cdns.length} CDNs simultaneously...`);
// ๐ Race all CDNs for first success
const loadPromises = this.cdns.map(cdn => this.loadFromCDN(asset, cdn));
try {
const result = await Promise.any(loadPromises);
console.log(`๐ Successfully loaded from ${result.cdn.emoji} ${result.cdn.name}!`);
return result;
} catch (aggregateError) {
console.log("๐ฅ All CDNs failed!");
// ๐ Log all failure reasons
(aggregateError as AggregateError).errors.forEach((error, index) => {
console.log(` ${index + 1}. ${this.cdns[index].emoji} ${this.cdns[index].name}: ${error.message}`);
});
throw new Error(`Failed to load ${asset.path} from any CDN`);
}
}
// ๐ฆ Load multiple assets with individual fallbacks
async loadAssets(assets: AssetInfo[]): Promise<LoadResult[]> {
console.log(`๐ Loading ${assets.length} assets with CDN fallbacks...\n`);
const loadPromises = assets.map(async (asset, index) => {
try {
console.log(`\n๐ฆ Asset ${index + 1}/${assets.length}:`);
const result = await this.loadAsset(asset);
return result;
} catch (error) {
console.log(`๐ฅ Asset ${index + 1} completely failed: ${error.message}`);
throw error;
}
});
// ๐ญ Use allSettled to get all results (some may fail)
const results = await Promise.allSettled(loadPromises);
const successful = results
.filter((result): result is PromiseFulfilledResult<LoadResult> =>
result.status === 'fulfilled'
)
.map(result => result.value);
const failed = results.filter(result => result.status === 'rejected').length;
console.log(`\n๐ Loading Summary:`);
console.log(` โ
Successfully loaded: ${successful.length}/${assets.length}`);
console.log(` โ Failed to load: ${failed}/${assets.length}`);
if (successful.length > 0) {
console.log(`\n๐ CDN Performance:`);
const cdnStats = successful.reduce((stats, result) => {
const cdnName = result.cdn.name;
stats[cdnName] = (stats[cdnName] || 0) + 1;
return stats;
}, {} as Record<string, number>);
Object.entries(cdnStats).forEach(([cdn, count]) => {
const cdnInfo = this.cdns.find(c => c.name === cdn);
console.log(` ${cdnInfo?.emoji} ${cdn}: ${count} assets`);
});
}
return successful;
}
// ๐ฏ Smart asset loading with performance tracking
async loadWithPerformanceTracking(assets: AssetInfo[]): Promise<{
results: LoadResult[];
performance: {
totalTime: number;
averageLoadTime: number;
fastestCDN: string;
slowestCDN: string;
successRate: number;
};
}> {
const startTime = Date.now();
const results = await this.loadAssets(assets);
const totalTime = Date.now() - startTime;
const averageLoadTime = results.reduce((sum, r) => sum + r.loadTime, 0) / results.length;
const cdnTimes = results.reduce((times, result) => {
const cdn = result.cdn.name;
if (!times[cdn]) times[cdn] = [];
times[cdn].push(result.loadTime);
return times;
}, {} as Record<string, number[]>);
const avgCdnTimes = Object.entries(cdnTimes).map(([cdn, times]) => ({
cdn,
avgTime: times.reduce((sum, time) => sum + time, 0) / times.length
}));
const fastestCDN = avgCdnTimes.sort((a, b) => a.avgTime - b.avgTime)[0]?.cdn || "None";
const slowestCDN = avgCdnTimes.sort((a, b) => b.avgTime - a.avgTime)[0]?.cdn || "None";
return {
results,
performance: {
totalTime,
averageLoadTime,
fastestCDN,
slowestCDN,
successRate: (results.length / assets.length) * 100
}
};
}
}
// ๐ฎ Demo the multi-CDN loader
async function demonstrateMultiCDNLoader() {
const loader = new MultiCDNLoader();
const assets: AssetInfo[] = [
{ path: "js/app.bundle.js", type: "script", size: 245760, cacheable: true },
{ path: "css/styles.min.css", type: "stylesheet", size: 51200, cacheable: true },
{ path: "images/hero-banner.webp", type: "image", size: 102400, cacheable: true },
{ path: "fonts/inter-regular.woff2", type: "font", size: 25600, cacheable: true },
{ path: "js/vendor.chunk.js", type: "script", size: 512000, cacheable: true }
];
try {
const { results, performance } = await loader.loadWithPerformanceTracking(assets);
console.log(`\n๐ Performance Report:`);
console.log(` โฑ๏ธ Total time: ${performance.totalTime}ms`);
console.log(` ๐ Average load time: ${performance.averageLoadTime.toFixed(0)}ms`);
console.log(` ๐ Fastest CDN: ${performance.fastestCDN}`);
console.log(` ๐ Slowest CDN: ${performance.slowestCDN}`);
console.log(` ๐ Success rate: ${performance.successRate.toFixed(1)}%`);
} catch (error) {
console.error("๐ฅ Multi-CDN loading demo failed:", error);
}
}
๐ Example 2: Database Connection Pool with Fallbacks
Letโs create a robust database connection system:
// ๐๏ธ Database connection interfaces
interface DatabaseConfig {
id: string;
host: string;
port: number;
database: string;
type: 'primary' | 'replica' | 'backup';
region: string;
emoji: string;
}
interface ConnectionResult {
config: DatabaseConfig;
connectionTime: number;
isHealthy: boolean;
lastQuery?: Date;
}
interface QueryResult<T = any> {
data: T;
executionTime: number;
connection: ConnectionResult;
query: string;
}
class DatabaseConnectionPool {
private databases: DatabaseConfig[] = [
{ id: "primary-us", host: "db-primary.us-east.com", port: 5432, database: "app_prod", type: "primary", region: "us-east", emoji: "๐ข" },
{ id: "primary-eu", host: "db-primary.eu-west.com", port: 5432, database: "app_prod", type: "primary", region: "eu-west", emoji: "๐ข" },
{ id: "replica-us-1", host: "db-replica1.us-east.com", port: 5432, database: "app_prod", type: "replica", region: "us-east", emoji: "๐ต" },
{ id: "replica-us-2", host: "db-replica2.us-east.com", port: 5432, database: "app_prod", type: "replica", region: "us-east", emoji: "๐ต" },
{ id: "backup-local", host: "db-backup.local.com", port: 5432, database: "app_prod", type: "backup", region: "local", emoji: "๐ก" }
];
// ๐ Connect to single database
private async connectToDatabase(config: DatabaseConfig): Promise<ConnectionResult> {
const startTime = Date.now();
try {
// ๐ Simulate database connection with realistic scenarios
await new Promise((resolve, reject) => {
const connectionTime = {
'primary': 80 + Math.random() * 120, // 80-200ms
'replica': 100 + Math.random() * 200, // 100-300ms
'backup': 200 + Math.random() * 400 // 200-600ms
}[config.type];
const failureRate = {
'primary': 0.05, // 5% failure rate
'replica': 0.08, // 8% failure rate
'backup': 0.03 // 3% failure rate (more reliable but slower)
}[config.type];
setTimeout(() => {
if (Math.random() < failureRate) {
const errors = [
"Connection timeout ๐ก",
"Authentication failed ๐",
"Database unavailable ๐ซ",
"Connection limit exceeded ๐ฆ",
"Network unreachable ๐"
];
reject(new Error(errors[Math.floor(Math.random() * errors.length)]));
} else {
resolve(undefined);
}
}, connectionTime);
});
const connectionTime = Date.now() - startTime;
console.log(` โ
${config.emoji} ${config.id}: Connected in ${connectionTime}ms`);
return {
config,
connectionTime,
isHealthy: true,
lastQuery: new Date()
};
} catch (error) {
const connectionTime = Date.now() - startTime;
console.log(` โ ${config.emoji} ${config.id}: Failed after ${connectionTime}ms - ${error.message}`);
throw new Error(`${config.id} connection failed: ${error.message}`);
}
}
// ๐ Get first available connection using Promise.any
async getConnection(preferredType?: 'primary' | 'replica' | 'backup'): Promise<ConnectionResult> {
console.log(`๐ Seeking database connection...`);
// ๐ฏ Order databases by preference
let orderedDatabases = [...this.databases];
if (preferredType) {
orderedDatabases = [
...this.databases.filter(db => db.type === preferredType),
...this.databases.filter(db => db.type !== preferredType)
];
console.log(`๐ Preferring ${preferredType} databases`);
}
console.log(`๐ก Trying ${orderedDatabases.length} databases simultaneously...`);
const connectionPromises = orderedDatabases.map(db => this.connectToDatabase(db));
try {
const connection = await Promise.any(connectionPromises);
console.log(`๐ Connected to ${connection.config.emoji} ${connection.config.id} (${connection.config.type})!`);
return connection;
} catch (aggregateError) {
console.log("๐ฅ All database connections failed!");
(aggregateError as AggregateError).errors.forEach((error, index) => {
console.log(` ${index + 1}. ${orderedDatabases[index].emoji} ${orderedDatabases[index].id}: ${error.message}`);
});
throw new Error("No database connections available");
}
}
// ๐ Execute query with automatic failover
async executeQuery<T = any>(query: string, preferredType?: 'primary' | 'replica'): Promise<QueryResult<T>> {
console.log(`๐ Executing query: ${query.substring(0, 50)}${query.length > 50 ? '...' : ''}`);
const connection = await this.getConnection(preferredType);
const startTime = Date.now();
try {
// ๐ Simulate query execution
await new Promise(resolve => setTimeout(resolve, 50 + Math.random() * 150));
// ๐ฒ Simulate query results
const mockData = {
users: [
{ id: 1, name: "Alice ๐ฉ", email: "[email protected]" },
{ id: 2, name: "Bob ๐จ", email: "[email protected]" }
]
} as T;
const executionTime = Date.now() - startTime;
console.log(`โ
Query executed in ${executionTime}ms on ${connection.config.emoji} ${connection.config.id}`);
return {
data: mockData,
executionTime,
connection,
query
};
} catch (error) {
const executionTime = Date.now() - startTime;
console.log(`โ Query failed after ${executionTime}ms: ${error.message}`);
throw error;
}
}
// ๐ Smart query execution with read/write routing
async smartQuery<T = any>(
query: string,
options: {
type: 'read' | 'write';
timeout?: number;
retries?: number;
}
): Promise<QueryResult<T>> {
const { type, timeout = 5000, retries = 2 } = options;
// ๐ฏ Determine preferred database type
const preferredType = type === 'write' ? 'primary' : 'replica';
console.log(`\n๐ฏ Smart ${type.toUpperCase()} query with ${retries} retries:`);
for (let attempt = 1; attempt <= retries + 1; attempt++) {
try {
console.log(`\n๐ Attempt ${attempt}:`);
// โฐ Add timeout to the query
const queryPromise = this.executeQuery<T>(query, preferredType);
const timeoutPromise = new Promise<never>((_, reject) => {
setTimeout(() => reject(new Error(`Query timeout after ${timeout}ms`)), timeout);
});
const result = await Promise.race([queryPromise, timeoutPromise]);
console.log(`๐ Smart query succeeded on attempt ${attempt}!`);
return result;
} catch (error) {
console.log(`โ Attempt ${attempt} failed: ${error.message}`);
if (attempt === retries + 1) {
throw new Error(`Smart query failed after ${retries + 1} attempts: ${error.message}`);
}
// โฐ Wait before retry
const delay = Math.pow(2, attempt - 1) * 1000;
console.log(`โฐ Waiting ${delay}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error("This should never happen");
}
// ๐ Database health check
async checkDatabaseHealth(): Promise<{
healthy: DatabaseConfig[];
unhealthy: DatabaseConfig[];
summary: string;
}> {
console.log("๐ฅ Performing database health check...");
const healthPromises = this.databases.map(async (db) => {
try {
await this.connectToDatabase(db);
return { db, healthy: true };
} catch (error) {
return { db, healthy: false, error: error.message };
}
});
const results = await Promise.allSettled(healthPromises);
const healthy: DatabaseConfig[] = [];
const unhealthy: DatabaseConfig[] = [];
results.forEach(result => {
if (result.status === 'fulfilled') {
if (result.value.healthy) {
healthy.push(result.value.db);
} else {
unhealthy.push(result.value.db);
}
} else {
// This shouldn't happen with our implementation
console.error("Health check itself failed:", result.reason);
}
});
const summary = `${healthy.length} healthy, ${unhealthy.length} unhealthy databases`;
console.log(`\n๐ Health Check Results: ${summary}`);
console.log("โ
Healthy databases:");
healthy.forEach(db => console.log(` ${db.emoji} ${db.id} (${db.type})`));
if (unhealthy.length > 0) {
console.log("โ Unhealthy databases:");
unhealthy.forEach(db => console.log(` ${db.emoji} ${db.id} (${db.type})`));
}
return { healthy, unhealthy, summary };
}
}
// ๐ฎ Demo the database connection pool
async function demonstrateDatabasePool() {
const pool = new DatabaseConnectionPool();
try {
// ๐ฅ Check database health first
await pool.checkDatabaseHealth();
// ๐ Execute different types of queries
console.log("\n" + "=".repeat(60));
// ๐ Read query (prefers replicas)
const readResult = await pool.smartQuery(
"SELECT * FROM users WHERE active = true",
{ type: 'read', timeout: 3000, retries: 2 }
);
console.log(`๐ Read query returned ${readResult.data.users?.length || 0} users`);
// โ๏ธ Write query (requires primary)
const writeResult = await pool.smartQuery(
"UPDATE users SET last_login = NOW() WHERE id = 1",
{ type: 'write', timeout: 2000, retries: 1 }
);
console.log(`โ๏ธ Write query completed successfully`);
} catch (error) {
console.error("๐ฅ Database pool demo failed:", error.message);
}
}
๐ Advanced Concepts
๐งโโ๏ธ Competitive Service Resolution
Handle multiple service implementations competing for the best result:
// ๐ Advanced competitive service resolution
class ServiceCompetition<T> {
// ๐ Race multiple service implementations
async compete<T>(
services: Array<{
name: string;
provider: () => Promise<T>;
priority: number;
timeout: number;
emoji: string;
}>
): Promise<{
result: T;
winner: string;
competitionTime: number;
attempts: number;
}> {
console.log(`๐ Starting service competition with ${services.length} contestants...`);
const startTime = Date.now();
// ๐ฏ Create time-limited promises
const competitorPromises = services.map(service => {
return new Promise<{ result: T; service: string }>((resolve, reject) => {
const timeoutId = setTimeout(() => {
reject(new Error(`${service.name} timed out after ${service.timeout}ms`));
}, service.timeout);
service.provider()
.then(result => {
clearTimeout(timeoutId);
console.log(` ๐ ${service.emoji} ${service.name} finished successfully!`);
resolve({ result, service: service.name });
})
.catch(error => {
clearTimeout(timeoutId);
console.log(` โ ${service.emoji} ${service.name} failed: ${error.message}`);
reject(new Error(`${service.name}: ${error.message}`));
});
});
});
try {
const { result, service: winner } = await Promise.any(competitorPromises);
const competitionTime = Date.now() - startTime;
console.log(`๐ Winner: ${winner} in ${competitionTime}ms!`);
return {
result,
winner,
competitionTime,
attempts: services.length
};
} catch (aggregateError) {
const competitionTime = Date.now() - startTime;
console.log(`๐ฅ All services failed after ${competitionTime}ms`);
(aggregateError as AggregateError).errors.forEach((error, index) => {
console.log(` ${services[index].emoji} ${services[index].name}: ${error.message}`);
});
throw new Error("All services failed in competition");
}
}
// ๐ฏ Quality-based competition with scoring
async competitiveQuality<T>(
services: Array<{
name: string;
provider: () => Promise<T>;
quality: (result: T) => number; // Score 0-100
emoji: string;
}>,
minimumQuality: number = 70
): Promise<{
result: T;
winner: string;
quality: number;
allResults: Array<{ service: string; result: T; quality: number }>;
}> {
console.log(`๐ Quality competition (minimum score: ${minimumQuality})...`);
// ๐ Run all services in parallel and wait for all
const servicePromises = services.map(async (service) => {
try {
const result = await service.provider();
const quality = service.quality(result);
console.log(` ${service.emoji} ${service.name}: Quality score ${quality}/100`);
return {
service: service.name,
result,
quality,
success: true
};
} catch (error) {
console.log(` โ ${service.emoji} ${service.name}: Failed - ${error.message}`);
return {
service: service.name,
result: null,
quality: 0,
success: false,
error: error.message
};
}
});
const settledResults = await Promise.allSettled(servicePromises);
// ๐ Process results and find qualifying services
const validResults = settledResults
.filter((result): result is PromiseFulfilledResult<any> =>
result.status === 'fulfilled' && result.value.success
)
.map(result => result.value)
.filter(result => result.quality >= minimumQuality)
.sort((a, b) => b.quality - a.quality); // Highest quality first
if (validResults.length === 0) {
throw new Error(`No services met minimum quality threshold of ${minimumQuality}`);
}
const winner = validResults[0];
console.log(`๐ฅ Quality winner: ${winner.service} with score ${winner.quality}/100`);
return {
result: winner.result,
winner: winner.service,
quality: winner.quality,
allResults: validResults.map(r => ({
service: r.service,
result: r.result,
quality: r.quality
}))
};
}
}
// ๐ฎ Demo competitive services
async function demonstrateServiceCompetition() {
const competition = new ServiceCompetition();
// ๐ Translation service competition
const translationServices = [
{
name: "Google Translate",
provider: async () => {
await new Promise(resolve => setTimeout(resolve, 200 + Math.random() * 300));
if (Math.random() < 0.1) throw new Error("API quota exceeded");
return "Bonjour le monde! ๐ซ๐ท";
},
priority: 1,
timeout: 1000,
emoji: "๐ฅ"
},
{
name: "DeepL",
provider: async () => {
await new Promise(resolve => setTimeout(resolve, 300 + Math.random() * 400));
if (Math.random() < 0.15) throw new Error("Service unavailable");
return "Bonjour tout le monde! ๐ซ๐ท";
},
priority: 2,
timeout: 1200,
emoji: "๐ฆ"
},
{
name: "Azure Translator",
provider: async () => {
await new Promise(resolve => setTimeout(resolve, 250 + Math.random() * 350));
if (Math.random() < 0.08) throw new Error("Authentication failed");
return "Salut le monde! ๐ซ๐ท";
},
priority: 3,
timeout: 1500,
emoji: "๐จ"
}
];
try {
console.log("๐ Translation Service Competition:");
const translationResult = await competition.compete(translationServices);
console.log(`\n๐ฏ Translation Result:`);
console.log(` Winner: ${translationResult.winner}`);
console.log(` Result: "${translationResult.result}"`);
console.log(` Time: ${translationResult.competitionTime}ms`);
} catch (error) {
console.error("๐ฅ Translation competition failed:", error.message);
}
try {
// ๐จ Image processing quality competition
console.log("\n๐จ Image Processing Quality Competition:");
const imageServices = [
{
name: "AI Upscaler Pro",
provider: async () => {
await new Promise(resolve => setTimeout(resolve, 1000));
return { url: "processed_pro.jpg", resolution: "4K", artifacts: 2 };
},
quality: (result: any) => 95 - result.artifacts * 5,
emoji: "๐"
},
{
name: "Fast Processor",
provider: async () => {
await new Promise(resolve => setTimeout(resolve, 300));
return { url: "processed_fast.jpg", resolution: "2K", artifacts: 8 };
},
quality: (result: any) => 80 - result.artifacts * 3,
emoji: "โก"
},
{
name: "Budget Service",
provider: async () => {
await new Promise(resolve => setTimeout(resolve, 500));
return { url: "processed_budget.jpg", resolution: "HD", artifacts: 12 };
},
quality: (result: any) => 60 - result.artifacts * 2,
emoji: "๐ฐ"
}
];
const qualityResult = await competition.competitiveQuality(imageServices, 75);
console.log(`\n๐ Quality Competition Result:`);
console.log(` Winner: ${qualityResult.winner} (Quality: ${qualityResult.quality}/100)`);
console.log(` All qualifying results: ${qualityResult.allResults.length}`);
} catch (error) {
console.error("๐ฅ Quality competition failed:", error.message);
}
}
โ ๏ธ Common Pitfalls and Solutions
๐ฑ Pitfall 1: Misunderstanding AggregateError
// โ Wrong - treating AggregateError like regular Error
async function badErrorHandling() {
try {
const result = await Promise.any([
Promise.reject("Error 1"),
Promise.reject("Error 2"),
Promise.reject("Error 3")
]);
} catch (error) {
console.log("Error:", error.message); // ๐ฅ Won't show individual errors!
}
}
// โ
Correct - properly handling AggregateError
async function goodErrorHandling() {
try {
const result = await Promise.any([
Promise.reject(new Error("Service A failed")),
Promise.reject(new Error("Service B failed")),
Promise.reject(new Error("Service C failed"))
]);
} catch (error) {
if (error instanceof AggregateError) {
console.log(`๐ฅ All ${error.errors.length} attempts failed:`);
error.errors.forEach((err, index) => {
console.log(` ${index + 1}. ${err.message}`);
});
} else {
console.log("Unexpected error:", error.message);
}
}
}
๐คฏ Pitfall 2: Not Considering Timing and Resources
// โ Dangerous - all attempts run simultaneously consuming resources
async function wastefulAny() {
const promises = [
expensiveAPICall("service-1"), // Costs $0.01 per call
expensiveAPICall("service-2"), // Costs $0.01 per call
expensiveAPICall("service-3") // Costs $0.01 per call
];
// ๐ธ This will call ALL services even though we only need one!
return Promise.any(promises);
}
// โ
Smart - staggered attempts with cancellation
async function economicalAny<T>(
serviceFactories: (() => Promise<T>)[],
staggerDelay: number = 100
): Promise<T> {
const controllers: AbortController[] = [];
const promises: Promise<T>[] = [];
try {
// ๐ Start services with staggered delays
serviceFactories.forEach((factory, index) => {
const controller = new AbortController();
controllers.push(controller);
const delayedPromise = new Promise<T>((resolve, reject) => {
setTimeout(async () => {
if (controller.signal.aborted) {
reject(new Error("Aborted"));
return;
}
try {
const result = await factory();
resolve(result);
} catch (error) {
reject(error);
}
}, index * staggerDelay);
});
promises.push(delayedPromise);
});
const result = await Promise.any(promises);
// ๐งน Cancel remaining operations
controllers.forEach(controller => controller.abort());
return result;
} catch (error) {
// ๐งน Clean up on failure too
controllers.forEach(controller => controller.abort());
throw error;
}
}
async function expensiveAPICall(service: string): Promise<string> {
console.log(`๐ธ Calling expensive ${service}...`);
await new Promise(resolve => setTimeout(resolve, 1000));
return `Result from ${service}`;
}
๐ฏ Pitfall 3: Promise.any vs Promise.race Confusion
// โ Wrong - using Promise.race when you want first success
async function confusedRace() {
const attempts = [
Promise.reject("Fast failure"), // โ This will win the race!
Promise.resolve("Slow success") // Never gets a chance
];
try {
const result = await Promise.race(attempts); // ๐ฅ Will throw immediately
console.log("Success:", result); // Never reached
} catch (error) {
console.log("Failed:", error); // This runs
}
}
// โ
Correct - using Promise.any for first success
async function smartAny() {
const attempts = [
Promise.reject("Fast failure"), // ๐ Ignored, keep trying
Promise.resolve("Slow success") // โ
This is what we get!
];
try {
const result = await Promise.any(attempts); // โ
Waits for success
console.log("Success:", result); // "Slow success"
} catch (error) {
console.log("All failed:", error); // Only if ALL fail
}
}
// ๐ฏ When to use each:
// Promise.race: "I need the fastest response, good or bad"
// Promise.any: "I need any successful response, ignore failures"
// Promise.all: "I need ALL to succeed"
// Promise.allSettled: "I want to know about ALL results"
๐ ๏ธ Best Practices
- ๐ Embrace Optimism: Use Promise.any when you have multiple ways to succeed
- ๐จ Handle AggregateError: Always check for and properly handle AggregateError
- ๐ฐ Consider Resources: Stagger expensive operations to avoid waste
- โฐ Add Timeouts: Combine with timeout patterns for better reliability
- ๐งน Clean Up: Cancel remaining operations when one succeeds
- ๐ Monitor Performance: Track which services succeed most often
- ๐ Plan Graceful Degradation: Have backup strategies when all fail
๐งช Hands-On Exercise
๐ฏ Challenge: Build a Smart Content Delivery System
Create an intelligent content delivery system that optimizes for speed, quality, and cost:
๐ Requirements:
- ๐ Multiple content sources (CDNs, origin servers, caches)
- ๐ฏ Different optimization strategies (speed, quality, cost)
- ๐ Performance monitoring and automatic routing
- ๐ Fallback chains with intelligent retry
- ๐ฐ Cost-aware decision making
- ๐ Real-time performance analytics
๐ Bonus Points:
- Geographic routing based on user location
- A/B testing different delivery strategies
- Machine learning for predicting best sources
- Adaptive timeout based on historical performance
- Circuit breaker pattern for failing sources
๐ก Solution
๐ Click to see solution
// ๐ Smart content delivery system with Promise.any
interface ContentSource {
id: string;
type: 'cdn' | 'origin' | 'cache' | 'p2p';
url: string;
region: string;
cost: number; // Cost per GB
reliability: number; // 0-1 score
avgLatency: number; // ms
emoji: string;
}
interface DeliveryStrategy {
name: string;
priority: 'speed' | 'quality' | 'cost' | 'balanced';
sourceRanking: (sources: ContentSource[]) => ContentSource[];
emoji: string;
}
interface DeliveryResult {
content: any;
source: ContentSource;
deliveryTime: number;
cost: number;
strategy: string;
quality: number;
}
interface PerformanceMetrics {
totalRequests: number;
avgDeliveryTime: number;
totalCost: number;
successRate: number;
sourceUsage: Record<string, number>;
strategyEffectiveness: Record<string, number>;
}
class SmartContentDelivery {
private sources: ContentSource[] = [
{ id: "cloudflare-global", type: "cdn", url: "https://cdn.cloudflare.com", region: "global", cost: 0.085, reliability: 0.99, avgLatency: 85, emoji: "โ๏ธ" },
{ id: "aws-us-east", type: "cdn", url: "https://d123.cloudfront.net", region: "us-east", cost: 0.10, reliability: 0.98, avgLatency: 95, emoji: "๐ " },
{ id: "google-global", type: "cdn", url: "https://cdn.googleapis.com", region: "global", cost: 0.08, reliability: 0.97, avgLatency: 90, emoji: "๐ก" },
{ id: "origin-primary", type: "origin", url: "https://origin.example.com", region: "us-central", cost: 0.15, reliability: 0.95, avgLatency: 150, emoji: "๐ " },
{ id: "edge-cache", type: "cache", url: "https://edge.example.com", region: "local", cost: 0.02, reliability: 0.90, avgLatency: 45, emoji: "โก" },
{ id: "p2p-network", type: "p2p", url: "https://p2p.example.com", region: "distributed", cost: 0.01, reliability: 0.85, avgLatency: 120, emoji: "๐" }
];
private strategies: DeliveryStrategy[] = [
{
name: "Speed First",
priority: "speed",
sourceRanking: (sources) => [...sources].sort((a, b) => a.avgLatency - b.avgLatency),
emoji: "๐"
},
{
name: "Cost Optimized",
priority: "cost",
sourceRanking: (sources) => [...sources].sort((a, b) => a.cost - b.cost),
emoji: "๐ฐ"
},
{
name: "Reliability Focus",
priority: "quality",
sourceRanking: (sources) => [...sources].sort((a, b) => b.reliability - a.reliability),
emoji: "๐ก๏ธ"
},
{
name: "Balanced Approach",
priority: "balanced",
sourceRanking: (sources) => [...sources].sort((a, b) => {
const scoreA = (a.reliability * 0.4) + ((200 - a.avgLatency) / 200 * 0.3) + ((0.2 - a.cost) / 0.2 * 0.3);
const scoreB = (b.reliability * 0.4) + ((200 - b.avgLatency) / 200 * 0.3) + ((0.2 - b.cost) / 0.2 * 0.3);
return scoreB - scoreA;
}),
emoji: "โ๏ธ"
}
];
private metrics: PerformanceMetrics = {
totalRequests: 0,
avgDeliveryTime: 0,
totalCost: 0,
successRate: 0,
sourceUsage: {},
strategyEffectiveness: {}
};
// ๐ฆ Deliver content from single source
private async deliverFromSource(
contentPath: string,
source: ContentSource,
sizeKB: number = 100
): Promise<DeliveryResult> {
const startTime = Date.now();
try {
// ๐ Simulate content delivery with realistic scenarios
await new Promise((resolve, reject) => {
// ๐ Calculate delivery time based on source characteristics
const baseTime = source.avgLatency + (sizeKB / 1000 * 20); // 20ms per MB
const jitter = Math.random() * 50; // Network jitter
const deliveryTime = baseTime + jitter;
// ๐ Failure probability based on reliability
const failureRate = 1 - source.reliability;
setTimeout(() => {
if (Math.random() < failureRate) {
const errors = [
"Connection timeout ๐ก",
"Server overloaded ๐ฅ",
"Content not found ๐",
"Rate limit exceeded ๐ฆ",
"Network congestion ๐"
];
reject(new Error(errors[Math.floor(Math.random() * errors.length)]));
} else {
resolve(undefined);
}
}, deliveryTime);
});
const deliveryTime = Date.now() - startTime;
const cost = (sizeKB / 1024) * source.cost; // Cost per MB
const quality = Math.min(100, 95 + (source.reliability - 0.85) * 20); // Quality score
console.log(` โ
${source.emoji} ${source.id}: Delivered in ${deliveryTime}ms (${quality}/100 quality, $${cost.toFixed(4)})`);
return {
content: `Content from ${source.id}`,
source,
deliveryTime,
cost,
strategy: "single-source",
quality
};
} catch (error) {
const deliveryTime = Date.now() - startTime;
console.log(` โ ${source.emoji} ${source.id}: Failed after ${deliveryTime}ms - ${error.message}`);
throw new Error(`${source.id} delivery failed: ${error.message}`);
}
}
// ๐ Smart delivery using Promise.any with strategy
async deliverContent(
contentPath: string,
strategy: DeliveryStrategy,
sizeKB: number = 100,
maxSources: number = 3
): Promise<DeliveryResult> {
console.log(`๐ฏ Delivering ${contentPath} using ${strategy.emoji} ${strategy.name} strategy`);
// ๐ Rank sources according to strategy
const rankedSources = strategy.sourceRanking(this.sources).slice(0, maxSources);
console.log(`๐ก Racing top ${rankedSources.length} sources...`);
rankedSources.forEach((source, index) => {
console.log(` ${index + 1}. ${source.emoji} ${source.id} (${source.type})`);
});
// ๐ Race sources for first successful delivery
const deliveryPromises = rankedSources.map(source =>
this.deliverFromSource(contentPath, source, sizeKB)
);
try {
const result = await Promise.any(deliveryPromises);
// ๐ Update metrics
this.updateMetrics(result, strategy, true);
console.log(`๐ Successfully delivered via ${result.source.emoji} ${result.source.id}!`);
console.log(`๐ Stats: ${result.deliveryTime}ms, Quality ${result.quality}/100, Cost $${result.cost.toFixed(4)}`);
return {
...result,
strategy: strategy.name
};
} catch (aggregateError) {
console.log("๐ฅ All sources failed!");
(aggregateError as AggregateError).errors.forEach((error, index) => {
console.log(` ${rankedSources[index].emoji} ${rankedSources[index].id}: ${error.message}`);
});
// ๐ Update metrics for failure
this.updateMetrics(null, strategy, false);
throw new Error(`Failed to deliver ${contentPath} using ${strategy.name} strategy`);
}
}
// ๐ง Adaptive delivery with strategy competition
async adaptiveDelivery(contentPath: string, sizeKB: number = 100): Promise<{
result: DeliveryResult;
winningStrategy: string;
competitionTime: number;
}> {
console.log(`๐ง Adaptive delivery: Racing all strategies for ${contentPath}`);
const startTime = Date.now();
// ๐ Race all strategies simultaneously
const strategyPromises = this.strategies.map(async (strategy) => {
try {
const result = await this.deliverContent(contentPath, strategy, sizeKB, 2);
return { result, strategy: strategy.name };
} catch (error) {
throw new Error(`${strategy.name}: ${error.message}`);
}
});
try {
const { result, strategy: winningStrategy } = await Promise.any(strategyPromises);
const competitionTime = Date.now() - startTime;
console.log(`๐ Winning strategy: ${winningStrategy} in ${competitionTime}ms`);
return {
result,
winningStrategy,
competitionTime
};
} catch (aggregateError) {
const competitionTime = Date.now() - startTime;
console.log(`๐ฅ All strategies failed after ${competitionTime}ms`);
(aggregateError as AggregateError).errors.forEach((error, index) => {
console.log(` ${this.strategies[index].emoji} ${this.strategies[index].name}: ${error.message}`);
});
throw new Error("All delivery strategies failed");
}
}
// ๐ Batch content delivery with mixed strategies
async deliverBatch(requests: Array<{
path: string;
sizeKB: number;
priority: 'speed' | 'cost' | 'quality' | 'balanced';
}>): Promise<{
successful: DeliveryResult[];
failed: Array<{ path: string; error: string }>;
summary: string;
totalCost: number;
avgDeliveryTime: number;
}> {
console.log(`๐ Batch delivery: ${requests.length} items with mixed strategies`);
const batchPromises = requests.map(async (request) => {
try {
const strategy = this.strategies.find(s => s.priority === request.priority);
if (!strategy) {
throw new Error(`Unknown priority: ${request.priority}`);
}
const result = await this.deliverContent(request.path, strategy, request.sizeKB);
return { success: true, result, path: request.path };
} catch (error) {
return { success: false, error: error.message, path: request.path };
}
});
const batchResults = await Promise.allSettled(batchPromises);
const successful: DeliveryResult[] = [];
const failed: Array<{ path: string; error: string }> = [];
batchResults.forEach(result => {
if (result.status === 'fulfilled') {
if (result.value.success) {
successful.push(result.value.result);
} else {
failed.push({ path: result.value.path, error: result.value.error });
}
} else {
failed.push({ path: "unknown", error: result.reason.message });
}
});
const totalCost = successful.reduce((sum, result) => sum + result.cost, 0);
const avgDeliveryTime = successful.reduce((sum, result) => sum + result.deliveryTime, 0) / successful.length;
const summary = `${successful.length} delivered, ${failed.length} failed`;
console.log(`\n๐ Batch Summary: ${summary}`);
console.log(`๐ฐ Total cost: $${totalCost.toFixed(4)}`);
console.log(`โฑ๏ธ Average delivery: ${avgDeliveryTime.toFixed(0)}ms`);
return {
successful,
failed,
summary,
totalCost,
avgDeliveryTime
};
}
// ๐ Update performance metrics
private updateMetrics(result: DeliveryResult | null, strategy: DeliveryStrategy, success: boolean): void {
this.metrics.totalRequests++;
if (success && result) {
this.metrics.avgDeliveryTime = (this.metrics.avgDeliveryTime + result.deliveryTime) / 2;
this.metrics.totalCost += result.cost;
// Track source usage
this.metrics.sourceUsage[result.source.id] = (this.metrics.sourceUsage[result.source.id] || 0) + 1;
// Track strategy effectiveness
this.metrics.strategyEffectiveness[strategy.name] = (this.metrics.strategyEffectiveness[strategy.name] || 0) + 1;
}
this.metrics.successRate = (Object.values(this.metrics.strategyEffectiveness).reduce((a, b) => a + b, 0) / this.metrics.totalRequests) * 100;
}
// ๐ Get performance analytics
getAnalytics(): PerformanceMetrics & {
recommendations: string[];
topSources: Array<{ id: string; usage: number; emoji: string }>;
topStrategies: Array<{ name: string; effectiveness: number; emoji: string }>;
} {
const topSources = Object.entries(this.metrics.sourceUsage)
.map(([id, usage]) => {
const source = this.sources.find(s => s.id === id);
return { id, usage, emoji: source?.emoji || "โ" };
})
.sort((a, b) => b.usage - a.usage)
.slice(0, 3);
const topStrategies = Object.entries(this.metrics.strategyEffectiveness)
.map(([name, effectiveness]) => {
const strategy = this.strategies.find(s => s.name === name);
return { name, effectiveness, emoji: strategy?.emoji || "โ" };
})
.sort((a, b) => b.effectiveness - a.effectiveness);
const recommendations: string[] = [];
if (this.metrics.successRate < 90) {
recommendations.push("๐จ Success rate is low - consider adding more reliable sources");
}
if (this.metrics.avgDeliveryTime > 200) {
recommendations.push("โก Delivery times are high - prioritize faster sources or add edge caching");
}
if (this.metrics.totalCost > 10) {
recommendations.push("๐ฐ Costs are accumulating - consider cost-optimized strategies");
}
if (topSources[0]?.usage > this.metrics.totalRequests * 0.8) {
recommendations.push("โ๏ธ Over-reliance on single source - diversify for better resilience");
}
return {
...this.metrics,
recommendations,
topSources,
topStrategies
};
}
}
// ๐ฎ Demo the smart content delivery system
async function demonstrateSmartDelivery() {
const delivery = new SmartContentDelivery();
try {
// ๐ฏ Test individual strategies
console.log("๐ฏ Testing Individual Strategies:\n");
const strategies = delivery.strategies;
for (const strategy of strategies.slice(0, 2)) { // Test first 2 strategies
console.log(`\n${strategy.emoji} Testing ${strategy.name}:`);
try {
await delivery.deliverContent("assets/hero-image.jpg", strategy, 500);
} catch (error) {
console.log(`โ Strategy failed: ${error.message}`);
}
}
// ๐ง Test adaptive delivery
console.log("\n" + "=".repeat(60));
console.log("๐ง Testing Adaptive Delivery:");
const adaptiveResult = await delivery.adaptiveDelivery("assets/app-bundle.js", 1024);
console.log(`๐ Adaptive delivery completed with ${adaptiveResult.winningStrategy}`);
// ๐ฆ Test batch delivery
console.log("\n" + "=".repeat(60));
console.log("๐ฆ Testing Batch Delivery:");
const batchRequests = [
{ path: "images/logo.png", sizeKB: 50, priority: "speed" as const },
{ path: "docs/manual.pdf", sizeKB: 2048, priority: "cost" as const },
{ path: "videos/demo.mp4", sizeKB: 10240, priority: "quality" as const },
{ path: "assets/icons.svg", sizeKB: 25, priority: "balanced" as const }
];
const batchResult = await delivery.deliverBatch(batchRequests);
// ๐ Show analytics
console.log("\n" + "=".repeat(60));
console.log("๐ Performance Analytics:");
const analytics = delivery.getAnalytics();
console.log(`\n๐ Overall Metrics:`);
console.log(` ๐ฆ Total requests: ${analytics.totalRequests}`);
console.log(` โ
Success rate: ${analytics.successRate.toFixed(1)}%`);
console.log(` โฑ๏ธ Average delivery: ${analytics.avgDeliveryTime.toFixed(0)}ms`);
console.log(` ๐ฐ Total cost: $${analytics.totalCost.toFixed(4)}`);
console.log(`\n๐ Top Sources:`);
analytics.topSources.forEach((source, index) => {
console.log(` ${index + 1}. ${source.emoji} ${source.id}: ${source.usage} deliveries`);
});
console.log(`\n๐ฏ Strategy Effectiveness:`);
analytics.topStrategies.forEach((strategy, index) => {
console.log(` ${index + 1}. ${strategy.emoji} ${strategy.name}: ${strategy.effectiveness} successes`);
});
if (analytics.recommendations.length > 0) {
console.log(`\n๐ก Recommendations:`);
analytics.recommendations.forEach(rec => console.log(` ${rec}`));
}
} catch (error) {
console.error("๐ฅ Smart delivery demo failed:", error.message);
}
}
// ๐ Run the demo
demonstrateSmartDelivery();
๐ Key Takeaways
Youโve mastered Promise.any! Hereโs what you can now do:
- โ Find the first success among multiple attempts with optimistic thinking ๐ช
- โ Handle AggregateError properly when all attempts fail ๐ก๏ธ
- โ Build resilient fallback systems that keep trying until they succeed ๐ฏ
- โ Create competitive service architectures that race for the best result ๐
- โ Optimize resource usage with intelligent staggering and cancellation ๐
Remember: Promise.any is your optimistic friend - it believes that at least one of your attempts will succeed! ๐
๐ค Next Steps
Congratulations! ๐ Youโve mastered Promise.any in TypeScript!
Hereโs what to explore next:
- ๐ป Practice with the smart content delivery exercise above
- ๐๏ธ Build a multi-provider authentication system with fallbacks
- ๐ Move on to our next tutorial: โAsync Functions: Return Types and Behaviorโ
- ๐ Explore advanced patterns like circuit breakers and adaptive timeouts
Remember: Sometimes the best strategy is to try multiple approaches and celebrate the first one that works! ๐
Happy coding! ๐๐โจ