roger pence

Potentially, each day is crucial in the total development

Search
Advanced Search
Folder to search:
Limit search to one of these properties:

    FlexSearch: Perform a search

    With the index populated and ready to go, we're reading to fullfill a search request. The code presented in this section is steps 5, 6 and 8 from the worker sequence diagram (click "Worker sequence diagram" below for another look at the sequence diagram).

    Worker sequence diagram
    sequenceDiagram autonumber actor User participant client as client<br>(search.js) participant worker as worker<br>(search-worker.js) note over client, worker: index created <br>when page loads client ->> worker: FlexSearch.CREATE_INDEX activate worker create participant index worker ->> index: create index worker->> client: FlexSearch.INDEX_READY note over client, worker: 5K docs indexed in 2/3 of second! deactivate worker User ->> client: send search request client ->> worker: FlexSearch.SEARCH_INDEX activate worker worker ->> index: search index index ->> worker: search results worker ->> client: FlexSearch.SEARCH_RESULTS deactivate worker client ->> User: render search results
    FlexSearch Web worker sequence diagram

    The steps to perform a search are:

    1. The user enters search value.
    2. search.js captures the search value and issues a FlexSearch.SEARCH_INDEX message (which includes the search arguments FlexSearch needs).
    3. Upon receiving the FlexSearch.SEARCH_INDEX, the worker uses the search data in the message to perform the search and issues a FlexSearch.SEARCH_RESULTS message (which includes the search results).
    4. Upon receiving the FlexSearch.SEARCH_RESULTS message, using the search results sent with the message, search.js renders the search results for the user to see.
    let indexReady = false;
    let searchDebounceTimeoutId = null;
    
    /*
     * Watch for worker messages.
     */
    worker.addEventListener("message", (event) => {
        const { type, data } = event.data;
    
        switch (type) {
            case FlexSearch.INDEX_READY:
                indexReady = true;
    
            case FlexSearch.SEARCH_RESULTS:
                renderSearchResults(data);
        }
    });
    
    /*
     * Value to search for changed.
     */
    input.addEventListener("input", () => {
        const query = input.value.trim();
    
        if (!query || !indexReady) return;
    
        clearTimeout(searchDebounceTimeoutId);
        searchDebounceTimeoutId = setTimeout(() => {
            submitSearchRequest();
        }, 300); // 300ms debounce
    });
    
    function submitSearchRequest() {
        const query = input.value.trim();
    
        const searchArgs = {
            query,
            enrich: true,
        };
    
        worker.postMessage({ type: FlexSearch.SEARCH_INDEX, data: { searchArgs } });
    }
    
    // Render search results.
    function renderSearchResults(docs) {
        for (const doc of docs) {
            const excludeTags = ["posts", "links"];
    
            const divStart = '<div class="tags-wrapper">';
            const divEnd = "</div>";
    
            const tags = doc.tags.split(",");
            let tagsString = [];
    
            tags.forEach((tag) => {
                if (!excludeTags.includes(tag)) {
                    tagsString.push(`<span class="tags-list">${tag}</span>`);
                }
            });
    
            const html = `<li class="search-result-row">${divStart}<a href="${doc.url}">${doc.id} - ${doc.title}</a>${tagsString.join("")}${divEnd}</li>`;
    
            results.insertAdjacentHTML("beforeend", html);
        }
    }