From 5c7574fd3f8c9dab78dfada955c78184eda2065f Mon Sep 17 00:00:00 2001
From: Mimi <1119186082@qq.com>
Date: Tue, 4 Aug 2026 14:55:10 +0800
Subject: [PATCH] Improve Algolia search concurrency
---
.../js/third-party/search/algolia-search.js | 127 ++++++++++--------
1 file changed, 68 insertions(+), 59 deletions(-)
diff --git a/source/js/third-party/search/algolia-search.js b/source/js/third-party/search/algolia-search.js
index e77dcf2..1b22ab2 100644
--- a/source/js/third-party/search/algolia-search.js
+++ b/source/js/third-party/search/algolia-search.js
@@ -19,83 +19,92 @@ document.addEventListener('DOMContentLoaded', () => {
return result;
};
- let isSearching = false;
- let pendingQuery = null;
+ let latestSearchId = 0;
- const searchAlgolia = async (searchText, page = 0) => {
- if (isSearching) {
- pendingQuery = { searchText, page };
- return;
- }
- isSearching = true;
+ const searchAlgolia = async (searchText, page, searchId) => {
+ if (searchId !== latestSearchId) return;
+ container.setAttribute('aria-busy', 'true');
const startTime = Date.now();
- const result = await client.search({
- requests: [{
- indexName,
- page,
- query : searchText,
- hitsPerPage : hits.per_page || 10,
- attributesToRetrieve : ['permalink'],
- attributesToHighlight: ['title', 'excerpt', 'excerptStrip', 'contentStripTruncate'],
- highlightPreTag : '',
- highlightPostTag : ''
- }]
- });
- const data = result.results[0];
- if (data.nbHits === 0) {
- container.innerHTML = '
';
- } else {
- const stats = CONFIG.i18n.hits_time
- .replace('${hits}', data.nbHits)
- .replace('${time}', Date.now() - startTime);
- let pagination = '';
- if (data.nbPages > 1) {
- pagination += '';
- }
+ try {
+ const result = await client.search({
+ requests: [{
+ indexName,
+ page,
+ query : searchText,
+ hitsPerPage : hits.per_page || 10,
+ attributesToRetrieve : ['permalink'],
+ attributesToHighlight: ['title', 'excerpt', 'excerptStrip', 'contentStripTruncate'],
+ highlightPreTag : '',
+ highlightPostTag : ''
+ }]
+ });
+ if (searchId !== latestSearchId) return;
- container.innerHTML = `
+ const data = result.results[0];
+ if (data.nbHits === 0) {
+ container.innerHTML = '
';
+ } else {
+ const stats = CONFIG.i18n.hits_time
+ .replace('${hits}', data.nbHits)
+ .replace('${time}', Date.now() - startTime);
+ let pagination = '';
+ if (data.nbPages > 1) {
+ pagination += '';
+ }
+
+ container.innerHTML = `
${stats}
${data.hits.map(formatHits).join('')}
${pagination}`;
- if (typeof pjax === 'object') pjax.refresh(container);
- container.querySelectorAll('.page-number').forEach(element => {
- element.addEventListener('click', async event => {
- event.preventDefault();
- await searchAlgolia(searchText, Number(element.dataset.index));
+ if (typeof pjax === 'object') pjax.refresh(container);
+ container.querySelectorAll('.page-number').forEach(element => {
+ element.addEventListener('click', async event => {
+ event.preventDefault();
+ if (input.value.trim() !== searchText) return;
+ const searchId = ++latestSearchId;
+ await searchAlgolia(searchText, Number(element.dataset.index), searchId);
+ });
});
- });
- }
- isSearching = false;
- if (pendingQuery !== null && (pendingQuery.searchText !== searchText || pendingQuery.page !== page)) {
- const { searchText, page } = pendingQuery;
- pendingQuery = null;
- searchAlgolia(searchText, page);
+ }
+ } catch (error) {
+ if (searchId !== latestSearchId) return;
+ console.warn('Algolia search failed:', error);
+ container.innerHTML = '
';
+ } finally {
+ if (searchId === latestSearchId) container.removeAttribute('aria-busy');
}
};
- const inputEventFunction = async () => {
+ const inputEventFunction = async searchId => {
+ if (searchId !== latestSearchId) return;
const searchText = input.value.trim();
- if (searchText === '') {
- container.innerHTML = '
';
- return;
- }
+ if (searchText === '') return;
// Algolia client will automatically cache the data for same queries
- await searchAlgolia(searchText, 0);
+ await searchAlgolia(searchText, 0, searchId);
};
const debouncedSearch = NexT.utils.debounce(inputEventFunction, 500);
- input.addEventListener('input', debouncedSearch);
+ input.addEventListener('input', () => {
+ const searchId = ++latestSearchId;
+ if (input.value.trim() === '') {
+ container.removeAttribute('aria-busy');
+ container.innerHTML = '
';
+ } else {
+ container.setAttribute('aria-busy', 'true');
+ }
+ debouncedSearch(searchId);
+ });
// Handle and trigger popup window
document.querySelectorAll('.popup-trigger').forEach(element => {