如何在十萬條數(shù)據(jù)中,實現(xiàn)毫秒級前端模糊搜索?
一個常見的場景是:在下拉選擇框、數(shù)據(jù)表格或搜索欄中,用戶輸入關(guān)鍵詞,系統(tǒng)需要從成千上萬條數(shù)據(jù)中實時篩選出匹配項。
當(dāng)數(shù)據(jù)量達到10萬級別時,傳統(tǒng)的前端搜索方案往往會引發(fā)災(zāi)難性的UI卡頓,甚至導(dǎo)致瀏覽器崩潰。

為何 Array.filter 會干掉我們的應(yīng)用
讓我們先看看最直觀的實現(xiàn)方式:
// 假設(shè)我們有10萬條用戶數(shù)據(jù)
const allUsers = [
{ id: 1, name: "story", email: "story@fedjavascript.com" },
// ... 99999 more users
];
const query = 'userNameOrEmail';
// 在10萬條數(shù)據(jù)下,這個時間會非常長
const results = allUsers.filter(user =>
user.name.toLowerCase().includes(query) ||
user.email.toLowerCase().includes(query)
);這種方法的致命缺陷在于:O(n) 復(fù)雜度:每次輸入,都會完整遍歷10萬條數(shù)據(jù),且會阻塞 UI 主線程。
從“運行時計算”到“預(yù)計算與索引”
解決性能問題的核心思想是空間換時間和預(yù)計算。在數(shù)據(jù)加載之初,就為其建立一個快速查找索引。
自己從零實現(xiàn)一個高效的索引和模糊匹配算法(如Trie樹、Levenshtein距離算法)是復(fù)雜且耗時的,幸運的是,社區(qū)已經(jīng)有了非常成熟強大的開源庫。
以 FlexSearch.js 為例來重構(gòu)上面的例子:

index.add 過程就是建立索引的預(yù)計算環(huán)節(jié),它可能需要幾百毫秒甚至幾秒(取決于數(shù)據(jù)復(fù)雜度和設(shè)備性能),但這是一次性的投入。
現(xiàn)在,將 filter 替換為 index.search。
const query = 'userNameOrEmail';
// 通常在 1ms 以內(nèi)!
const results = index.search(query, { limit: 100 });
// search() 返回包含文檔ID的匹配結(jié)果集,可據(jù)此從 allUsers find 數(shù)據(jù)index.search 的速度是驚人的,因為它利用了預(yù)先構(gòu)建的索引,查詢耗時通常在1毫秒以內(nèi),即使是10萬條數(shù)據(jù)。
最佳實踐是將所有與FlexSearch相關(guān)的操作都放入Web Worker中,F(xiàn)lexSearch內(nèi)置了對Worker的支持,創(chuàng)建索引時設(shè)置 worker 為 true 即可。
對于用戶的連續(xù)輸入,建議使用防抖確保只在用戶停止輸入一小段時間后(如200ms)才執(zhí)行搜索,減少不必要的搜索。































