File size: 4,693 Bytes
60aea95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31ab930
60aea95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
async function loadFragments() {
    // Find all elements with ids starting with 'fragment-'
    const fragmentElements = Array.from(document.querySelectorAll('[id^="fragment-"]'));
    
    class FetchQueue {
        constructor(maxConcurrent = 3) {
            this.queue = [];
            this.maxConcurrent = maxConcurrent;
            this.activeFetches = 0;
            this.maxRetries = 3; // Maximum number of retry attempts
            this.baseDelay = 1000; // Base delay in milliseconds (1 second)
        }

        async sleep(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        }

        async fetchWithRetry(fragmentPath, retryCount = 0) {
            try {
                const response = await fetch(fragmentPath);
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                return await response.text();
            } catch (error) {
                if (retryCount < this.maxRetries) {
                    // Exponential backoff: 1s, 2s, 4s
                    const delay = this.baseDelay * Math.pow(2, retryCount);
                    console.warn(`Retry ${retryCount + 1}/${this.maxRetries} for ${fragmentPath} after ${delay}ms`);
                    await this.sleep(delay);
                    return this.fetchWithRetry(fragmentPath, retryCount + 1);
                }
                throw error;
            }
        }

        async addFetch(element) {
            const fragmentName = element.id.replace('fragment-', '');
            const fragmentPath = `fragments/${fragmentName}.html`;
            
            return new Promise(async (resolve, reject) => {
                try {
                    const fetchPromise = (async () => {
                        try {
                            const html = await this.fetchWithRetry(fragmentPath);
                            
                            // Process the fragment
                            const temp = document.createElement('div');
                            temp.innerHTML = html;
                            element.innerHTML = temp.innerHTML;
                            
                            // Handle scripts
                            const scripts = temp.getElementsByTagName('script');
                            Array.from(scripts).forEach(oldScript => {
                                const newScript = document.createElement('script');
                                Array.from(oldScript.attributes).forEach(attr => {
                                    newScript.setAttribute(attr.name, attr.value);
                                });
                                newScript.textContent = oldScript.textContent;
                                oldScript.parentNode.removeChild(oldScript);
                                document.body.appendChild(newScript);
                            });
                            
                            this.activeFetches--;
                            resolve();
                        } catch (error) {
                            console.error(`Failed to load fragment ${fragmentPath} after ${this.maxRetries} retries:`, error);
                            this.activeFetches--;
                            reject(error);
                        }
                    })();

                    this.queue.push(fetchPromise);
                    this.activeFetches++;
                } catch (error) {
                    reject(error);
                }
            });
        }

        async processNext(element) {
            if (this.activeFetches < this.maxConcurrent && element) {
                await this.addFetch(element);
            }
        }
    }

    // Initialize queue
    const fetchQueue = new FetchQueue(3);
    let currentIndex = 0;
    const elements = fragmentElements; // Assuming this is defined elsewhere

    // Initial loading of first 3 elements
    while (currentIndex < elements.length && currentIndex < 3) {
        await fetchQueue.processNext(elements[currentIndex]);
        currentIndex++;
    }

    // Process remaining elements as fetches complete
    while (currentIndex < elements.length) {
        // Wait for any fetch to complete
        await Promise.race(fetchQueue.queue);
        // Remove completed fetch from queue
        fetchQueue.queue = fetchQueue.queue.filter(p => p.status === 'pending');
        // Add next element to queue
        await fetchQueue.processNext(elements[currentIndex]);
        currentIndex++;
    }

    // Wait for remaining fetches to complete
    await Promise.all(fetchQueue.queue);
}

export { loadFragments }