js 在数组中搜索 50k 结果太慢了

js search in array with 50k result is so slow

我有网络应用POS 在客户端而不是在服务器中的浏览器中的数组过滤器搜索 首先,我将所有产品下载为数组并对其进行处理 并且它在 20k 以下的产品数量上工作得很好 一段时间以来,产品数组的数量达到了 50k

我的结果数组是这样的..

   [
      {
        "id": 1,
        "name": "Product 1",
        "number": "1",
        "available_on_pos": 1,
        "pos_quick_lunch": 1,
        "product_category_id": 1,
        "discount_value": 10,
        "smallest_unit_id": 1,
        "smallest_unit_barcode": null,
        "smallest_unit_selling_price": 10,
        "smallest_unit_selling_price_above": null,
        "smallest_unit_selling_price_above_price": null,
        "tax_value": 16,
        "get_smallest_unit_id": {
          "id": 1,
          "name": "Unit"
        },
        "get_price_list_lines": []
      },
      {
        "id": 13,
        "name": "Product 2",
        "number": "13",
        "available_on_pos": 1,
        "pos_quick_lunch": null,
        "product_category_id": 1,
        "discount_value": null,
        "smallest_unit_id": 1,
        "smallest_unit_barcode": "9501025172815",
        "smallest_unit_selling_price": 0.509,
        "smallest_unit_selling_price_above": null,
        "smallest_unit_selling_price_above_price": null,
        "tax_value": 16,
        "get_smallest_unit_id": {
          "id": 1,
          "name": "Unit"
        },
        "get_price_list_lines": []
      }
    ]

这是搜索方法

var results = this.products.filter(obj => obj.smallest_unit_barcode != null && obj.smallest_unit_barcode.includes(value));
this.pos_quick_lunch = results;

正如我所说,产品数组是 50k,当我在同一产品搜索中按条形码枪多次时,搜索就像有延迟,这是等待的很长时间.. 有什么方法可以使搜索更轻松、更快捷

不清楚你是在谈论客户端 js 还是 node.js 服务器。

如果您在浏览器上谈论 js 运行,我认为更好的方法是让后端进行过滤。 我认为客户不应该获得如此大量的数据。

如果您使用 node.js 服务器,您应该考虑改进您的数据库查询并让它进行过滤而不是查询整个数据。

is there any way thats i can make the search much easer and faster

var results = this.products.filter(obj => obj.smallest_unit_barcode != null && obj.smallest_unit_barcode.includes(value));

只要我们把注意力集中在这部分代码上,而不是开始讨论一般的设计思想,我看到了这些选项...

缓存未定义的案例

您可以创建一个包含 smalles_unit_barcode != null 或 undefined 的产品列表并保留它。这应该会给你带来一点改进。

// do this only when products collection changes
const this.cachedProductsWithBarcode = this.products.filter(p => !!p.smallest_unit_barcode);

// do this on every request / input
const results = this.cachedProductsWithBarcode(p => p.smallest_unit_barcode.includes(value));

您需要部分匹配吗?

如果您获得了完整的货品编号/gtin,则无需进行部分搜索,您可以改用字典查找。

// only when products collection changes
const dict = this.products.reduce((prev, cur) => (prev[cur.smalles_unit_barcode] = cur, prev), {});

// for each request
return dict[value];

(如果大多数时候你得到的是完整的条形码,但有时只是其中的一部分,你可以考虑先进行查找,如果没有匹配则继续搜索。)

延迟用户输入/缓存

如果您搜索针来自用户输入,用户可以在其中键入条形码,并且您在每次击键时都执行此搜索,此搜索将阻止 UI 使应用程序无法使用。延迟用户输入(= 只有在我们不再有击键的情况下才进行搜索,例如 500 毫秒)可以改善用户体验。

此外,您还可以缓存结果

// User input "123"
// const firstResult = products.find(...)

// User input "1234"
// ... must be in firstResult, so let' search there
return firstResult.find(...)

(这只有在 'search while typing' 时才有意义,并且如果 needle 允许的结果多于缓存的结果列表,则需要使缓存无效。)

杂项...

  • 如果可能,请使用 startsWith() 而不是 includes()(预计大约 10% 的改进)- 如果您不能使用 ==
  • 限制结果数量。在许多情况下,您只需要一个结果,因此请改用 find()。您永远不需要超过 10 个结果,因此在达到此数量时停止过滤。
  • 在 UI 中将搜索和查找分开。根据我的经验,有些人确实可以快速输入文章代码 + ENTER -(= 完整代码 = 字典查找 = 快速)但有时他们不知道完整代码并想要搜索(= 部分代码 = 慢)。分离这两个用例可以像使用带有两个按钮(“ok”、“search”和 ENTER =“ok”)的输入字段一样简单。或者您使用类似输入 => ENTER => 在字典中查找完整代码 => 未找到的流程? => 显示“未找到,这里有一些结果...”

产品目录搜索通常是从后端服务器端完成的(特别是因为您的产品数据集非常大,而不是少数)。您需要实现一个搜索字段和调用 API 的按钮。此外,结果应该分页,这意味着您不想将所有 50k 产品加载到浏览器的内存中,否则您很容易 运行 陷入应用缓存问题(尤其是在移动设备中)。