Aktuelle Antworten brauchen 2 Sekunden, um angezeigt zu werden

Gibt es eine Möglichkeit, die neuesten Antworten sofort anzuzeigen? Derzeit verwende ich diesen Code:

  api.onPageChange(() =
    if (window.location.pathname === "/") {
      const container = document.querySelector(".latest-topic-list");
      if (!container || container.dataset.modified === "true") return;

      fetch("/posts.json?order=created")
        .then(res = res.json())
        .then(data = {
          const replies = data.latest_posts
            .filter(p = p.post_number  1  p.topic_slug.includes("private-message"))
            .slice(0, 15);

          const topicFetches = replies.map(post =
            fetch(`/t/${post.topic_id}.json`)
              .then(res = res.json())
              .then(topic = {
                return {
                  post,
                  category: topic.category_id ? topic.category_name : null,
                  tags: topic.tags || []
                };
              })
          );

          Promise.all(topicFetches).then(results = {
            const rows = results.map(({ post, category, tags }) = {
              const url = `/t/${post.topic_slug}/${post.topic_id}/${post.post_number}`;
              const avatarUrl = post.avatar_template.replace("{size}", "45");
              const excerpt = post.excerpt?.replace(/<\/?[^\/>]+(>|$)/g, "")?.slice(0, 120) + (post.excerpt?.length  120 ? '...' : '') || '';

              const categoryHtml = category
                ? `span style="font-size: 0.85em; color: #666;"Categoria: strong${category}/strong/spanbr`
                : '';

              const tagsHtml = tags.length
                ? `span style="font-size: 0.85em; color: #666;"Tags: ${tags.map(tag = `span style="background:#eee; padding:2px 6px; border-radius:3px; margin-right:4px;"${tag}/span`).join("")}/span`
                : '';

              return `
                tr class="topic-list-item"
                  td class="main-link clearfix"
                    div style="display: flex; align-items: center; gap: 16px; padding: 8px 0;"
                      div style="flex-shrink: 0;"
                        a class="avatar-link" href="/u/${post.username}"
                          img loading="lazy" width="45" height="45" src="${avatarUrl}" class="avatar" alt="${post.username}"
                        /a
                      /div
                      div style="display: flex; flex-direction: column; justify-content: center; padding-top: 8px; padding-bottom: 8px;"
                        span class="link-top-line" style="margin-bottom: 6px;"
                          a href="${url}" class="title raw-link"${excerpt}/a
                        /span
                        div class="link-bottom-line"
                          ${categoryHtml}
                          ${tagsHtml}
                        /div
                      /div
                    /div
                  /td
                /tr
              `;
            }).join("");

            // Cria o contêiner da seção de últimos comentários
            const latestRepliesContainer = document.createElement("div");
            latestRepliesContainer.className = "latest-replies-container";
            latestRepliesContainer.style.marginTop = "2em";

            latestRepliesContainer.innerHTML = `
              table class="topic-list latest-topic-list"
                thead
                  tr
                    th class="default"Últimos Comentários/th
                  /tr
                /thead
                tbody
                  ${rows}
                /tbody
              /table
            `;

            container.parentNode.insertBefore(latestRepliesContainer, container.nextSibling);
            container.dataset.modified = "true";
          });
        })
        .catch(error = {
          console.error("Erro ao buscar últimos comentários:", error);
        });
    }
  });
/scriptaber es dauert im Durchschnitt 2 Sekunden, bis der Inhalt erscheint. Dasselbe passiert bei den Blocks in der rechten Seitenleiste mit "kürzlichen Antworten". Ist das normal?

[Zitat=“David_Ghost, Beitrag:1, Thema:365041”]
Derzeit verwende ich diesen Code
[/Zitat]

Warum fügst du irgendetwas an Code hinzu?

Das funktioniert direkt ohne irgendetwas Besonderes; ist es für dich kaputt?

Das ist sein Problem.

Ich würde sagen, das ist zu erwarten, da der Code mehrere API-Anfragen stellt.
Er ruft die neuesten Beiträge ab und stellt dann eine Anfrage pro Themen-ID (hier 15), um den Kategorienamen abzurufen.

Im Moment weiß ich nicht, ob es eine andere Möglichkeit gibt, außer ein Plugin zu verwenden und zum Beispiel eine benutzerdefinierte SQL-Abfrage zu machen.

Das ist genau richtig.
Aber die Rechte Seitenleistenblöcke machen auch Anfragen? Sie liefert mir die gleichen Ergebnisse für aktuelle Antworten. Es dauert 2 Sekunden, bis sie erscheinen.

Ich werde sehen, wie ich ein Plugin erstellen kann. Danke.

Ja, es tut dasselbe beim Abrufen der neuesten Beiträge, aber das ist alles. Es versucht nicht, den Kategorienamen zu erhalten, das ist der Unterschied.

Ich verstehe. Vielen Dank für die Hilfe.

Ich werde versuchen, eine andere Lösung zu finden

Schließlich verwende ich das vorerst:

<script type="text/discourse-plugin" version="0.11.3">
  api.onPageChange(() => {
    if (window.location.pathname === "/") {
      const container = document.querySelector(".latest-topic-list");
      if (!container) return;
      
      // Vermeidet mehrfache Initialisierungen
      if (window.latestRepliesInitialized) return;
      window.latestRepliesInitialized = true;
      
      // Konfigurationen
      const POLLING_INTERVAL = 2000; // 2 Sekunden
      const COMMENTS_TO_SHOW = 15;
      const CACHE_DURATION = 30 * 60 * 1000; // 30 Minuten
      
      // Cache-Schlüssel
      const CACHE_KEY = "discourse_latest_replies_data";
      const CACHE_TIMESTAMP_KEY = "discourse_latest_replies_timestamp";
      const CACHE_LAST_ID_KEY = "discourse_latest_replies_last_id";
      
      // Speichert die letzte gesehene Post-ID zum Vergleich
      let lastSeenPostId = parseInt(localStorage.getItem(CACHE_LAST_ID_KEY) || "0");
      let pollingIntervalId = null;
      
      console.log(`Initialisiere Plugin für letzte Kommentare (letzte ID im Cache: ${lastSeenPostId})`);
      
      // Funktion zum Laden der Kommentare
      function loadLatestReplies(silent = false, forceRefresh = false) {
        // Überprüft zuerst den Cache, wenn keine erzwungene Aktualisierung vorliegt
        if (!forceRefresh) {
          const cachedData = localStorage.getItem(CACHE_KEY);
          const cacheTimestamp = localStorage.getItem(CACHE_TIMESTAMP_KEY);
          const now = Date.now();
          
          // Wenn gültige Daten im Cache vorhanden sind
          if (cachedData && cacheTimestamp && now - parseInt(cacheTimestamp) < CACHE_DURATION) {
            try {
              const results = JSON.parse(cachedData);
              console.log(`Verwende Daten aus dem Cache (${results.length} Kommentare, Cache von ${Math.round((now - parseInt(cacheTimestamp)) / 1000 / 60)} Minuten alt)`);
              renderLatestReplies(results, false);
              
              // Wenn nicht still, müssen wir nichts weiter tun
              if (!silent) {
                return;
              }
              
              // Wenn still, fahren wir fort, um Aktualisierungen zu prüfen
            } catch (e) {
              console.error("Fehler bei der Verarbeitung des Caches:", e);
              // Bei einem Fehler im Cache fahren wir fort, um frische Daten abzurufen
            }
          } else if (cachedData) {
            console.log("Cache abgelaufen, hole frische Daten");
          } else {
            console.log("Kein Cache gefunden, hole frische Daten");
          }
        } else {
          console.log("Erzwinge Aktualisierung, ignoriere Cache");
        }
        
        // Wenn nicht still, zeige den Lade-Indikator
        if (!silent) {
          // Wenn bereits ein Container für Kommentare existiert, zeige keinen Indikator
          const existingContainer = document.querySelector(".latest-replies-container");
          if (!existingContainer) {
            let loadingIndicator = document.getElementById("latest-replies-loading");
            if (!loadingIndicator) {
              loadingIndicator = document.createElement("div");
              loadingIndicator.id = "latest-replies-loading";
              loadingIndicator.innerHTML = `
                <div style="text-align: center; padding: 20px;">
                  <span class="spinner small"></span>
                  <span style="margin-left: 10px;">Lade letzte Kommentare...</span>
                </div>
              `;
              container.parentNode.insertBefore(loadingIndicator, container.nextSibling);
            }
          }
        }
        
        // Hole die neuesten Daten
        fetch("/posts.json?order=created")
          .then(res => res.json())
          .then(data => {
            // Log für Diagnose
            if (!silent) {
              console.log("Daten von der API erhalten:", data.latest_posts.length);
            }
            
            const replies = data.latest_posts
              .filter(p => p.post_number > 1 && !p.topic_slug.includes("private-message"))
              .slice(0, COMMENTS_TO_SHOW);
            
            // Prüfe, ob es neue Posts gibt
            const maxId = replies.length > 0 ? Math.max(...replies.map(post => post.id)) : 0;
            const hasNewPosts = maxId > lastSeenPostId;
            
            // Log für Diagnose
            if (hasNewPosts && !silent) {
              console.log(`Neue Posts erkannt. Letzte ID: ${lastSeenPostId}, Neue maximale ID: ${maxId}`);
            }
            
            // Aktualisiere die letzte gesehene ID
            if (maxId > lastSeenPostId) {
              lastSeenPostId = maxId;
              localStorage.setItem(CACHE_LAST_ID_KEY, lastSeenPostId.toString());
            }
            
            // Wenn keine neuen Posts und es eine stille Prüfung ist, nichts tun
            if (!hasNewPosts && silent && !forceRefresh) {
              return;
            }
            
            // Hole die Details der Themen
            const topicPromises = replies.map(post => {
              // Prüfe, ob wir das Thema im Cache haben
              const topicCacheKey = `discourse_topic_${post.topic_id}`;
              const cachedTopic = localStorage.getItem(topicCacheKey);
              
              if (cachedTopic && !forceRefresh) {
                try {
                  return Promise.resolve(JSON.parse(cachedTopic));
                } catch (e) {
                  console.error(`Fehler bei der Verarbeitung des Themas im Cache ${post.topic_id}:`, e);
                  // Bei einem Fehler im Cache holen wir es vom Server
                }
              }
              
              return fetch(`/t/${post.topic_id}.json`)
                .then(res => res.json())
                .then(topic => {
                  // Speichere das Thema im Cache
                  localStorage.setItem(topicCacheKey, JSON.stringify(topic));
                  return topic;
                })
                .catch(error => {
                  console.error(`Fehler beim Abrufen des Themas ${post.topic_id}:`, error);
                  return { category_id: null, category_name: null, tags: [] };
                });
            });
            
            Promise.all(topicPromises)
              .then(topics => {
                const results = replies.map((post, index) => {
                  const topic = topics[index];
                  return {
                    post,
                    category: topic.category_id ? topic.category_name : null,
                    tags: topic.tags || []
                  };
                });
                
                // Speichere die Ergebnisse im Cache
                localStorage.setItem(CACHE_KEY, JSON.stringify(results));
                localStorage.setItem(CACHE_TIMESTAMP_KEY, Date.now().toString());
                
                // Rendere die Ergebnisse
                renderLatestReplies(results, hasNewPosts || forceRefresh);
              })
              .catch(error => {
                console.error("Fehler bei der Verarbeitung der Themen:", error);
              });
          })
          .catch(error => {
            console.error("Fehler beim Abrufen der letzten Kommentare:", error);
            // Entferne den Lade-Indikator im Fehlerfall
            if (!silent) {
              const loadingElement = document.getElementById("latest-replies-loading");
              if (loadingElement) loadingElement.remove();
            }
          });
      }
      
      // Funktion zum Rendern der Ergebnisse
      function renderLatestReplies(results, animate = false) {
        // Entferne den Lade-Indikator
        const loadingElement = document.getElementById("latest-replies-loading");
        if (loadingElement) loadingElement.remove();
        
        // Wenn keine Ergebnisse, nichts tun
        if (!results || results.length === 0) {
          console.log("Keine Kommentare gefunden zum Anzeigen");
          return;
        }
        
        const rows = results.map(({ post, category, tags }) => {
          const url = `/t/${post.topic_slug}/${post.topic_id}/${post.post_number}`;
          const avatarUrl = post.avatar_template.replace("{size}", "45");
          const excerpt = post.excerpt?.replace(/</?[^>]+(>|$)/g, "")?.slice(0, 120) + (post.excerpt?.length > 120 ? '...' : '') || '';

          const categoryHtml = category
            ? `<span style="font-size: 0.85em; color: #666;">Kategorie: <strong>${category}</strong></span><br>`
            : '';

          const tagsHtml = tags.length
            ? `<span style="font-size: 0.85em; color: #666;">Tags: ${tags.map(tag => `<span style="background:#eee; padding:2px 6px; border-radius:3px; margin-right:4px;">${tag}</span>`).join("")}</span>`
            : '';

          const animationClass = animate ? 'new-comment' : '';

          return `
            <tr class="topic-list-item ${animationClass}" data-post-id="${post.id}">
              <td class="main-link clearfix">
                <div style="display: flex; align-items: center; gap: 16px; padding: 8px 0;">
                  <div style="flex-shrink: 0;">
                    <a class="avatar-link" href="/u/${post.username}">
                      <img loading="lazy" width="45" height="45" src="${avatarUrl}" class="avatar" alt="${post.username}">
                    </a>
                  </div>
                  <div style="display: flex; flex-direction: column; justify-content: center; padding-top: 8px; padding-bottom: 8px;">
                    <span class="link-top-line" style="margin-bottom: 6px;">
                      <a href="${url}" class="title raw-link">${excerpt}</a>
                    </span>
                    <div class="link-bottom-line">
                      ${categoryHtml}
                      ${tagsHtml}
                    </div>
                  </div>
                </div>
              </td>
            </tr>
          `;
        }).join("");

        // Füge den Animationsstil hinzu, falls noch nicht vorhanden
        if (!document.getElementById('latest-replies-style')) {
          const style = document.createElement('style');
          style.id = 'latest-replies-style';
          style.textContent = `
            @keyframes highlightNew {
              0% { background-color: rgba(255, 255, 0, 0.3); }
              100% { background-color: transparent; }
            }
            .new-comment {
              animation: highlightNew 2s ease-out;
            }
          `;
          document.head.appendChild(style);
        }

        // Entferne den bestehenden Container, falls vorhanden
        const existingContainer = document.querySelector(".latest-replies-container");
        if (existingContainer) {
          existingContainer.remove();
        }

        // Erstelle den Container für den Abschnitt der letzten Kommentare
        const latestRepliesContainer = document.createElement("div");
        latestRepliesContainer.className = "latest-replies-container";
        latestRepliesContainer.style.marginTop = "2em";

        // Füge Button für manuelle Aktualisierung und Status-Indikator hinzu
        const cacheTime = new Date(parseInt(localStorage.getItem(CACHE_TIMESTAMP_KEY) || Date.now()));
        const formattedTime = cacheTime.toLocaleTimeString();
        
        latestRepliesContainer.innerHTML = `
          <table class="topic-list latest-topic-list">
            <thead>
              <tr>
                <th class="default">
                  Letzte Kommentare
                  <span id="comments-status" style="font-size: 0.8em; font-weight: normal; margin-left: 10px;">
                  </span>
                  <button id="refresh-comments" class="btn btn-flat no-text btn-icon" style="float: right;" title="Kommentare aktualisieren">
                    <svg class="fa d-icon d-icon-sync svg-icon svg-string" width="16" height="16" aria-hidden="true"><use xlink:href="#sync"></use></svg>
                  </button>
                </th>
              </tr>
            </thead>
            <tbody id="latest-replies-tbody">
              ${rows}
            </tbody>
          </table>
        `;

        container.parentNode.insertBefore(latestRepliesContainer, container.nextSibling);
        container.dataset.modified = "true";
        
        // Füge Click-Event zum Aktualisierungs-Button hinzu
        document.getElementById("refresh-comments").addEventListener("click", function() {
          // Aktualisiere den Status-Text
          const statusElement = document.getElementById("comments-status");
          if (statusElement) {
            statusElement.textContent = "(aktualisiere...)";
          }
          
          // Erzwingt die Aktualisierung
          loadLatestReplies(false, true);
        });
        
        console.log(`Gerendert ${results.length} Kommentare`);
      }
      
      // Starte das initiale Laden (unter Verwendung des Caches)
      loadLatestReplies(false, false);
      
      // Konfiguriere das Polling mit hoher Frequenz
      pollingIntervalId = setInterval(() => {
        // Aktualisiere nur, wenn der Benutzer auf der Startseite ist
        if (window.location.pathname === "/") {
          loadLatestReplies(true, false); // Still, verwende Cache falls verfügbar
        }
      }, POLLING_INTERVAL);
      
      console.log(`Polling alle ${POLLING_INTERVAL}ms konfiguriert`);
      
      // Bereinige den Intervall, wenn der Benutzer die Seite verlässt
      api.onPageChange((url) => {
        if (url !== "/") {
          console.log("Verlasse Startseite, bereinige Ressourcen");
          
          if (pollingIntervalId) {
            clearInterval(pollingIntervalId);
            pollingIntervalId = null;
          }
          
          window.latestRepliesInitialized = false;
        }
      });
    }
  });
</script>

es funktioniert wie erwartet. Es fügt automatisch neue Kommentare hinzu und speichert sie im Cache. Ich weiß, dass das nicht ideal ist. Ich werde bald einen Plugin versuchen.

Das Ziel hier ist: Anstatt einer Kategorie mit dem Stil der Seite „Neueste Themen“, würde ich gerne eine Kategorie mit den „Neuesten Antworten“ haben.