简体   繁体   English

JavaScript Array.filter 唯一性而不是阻止 UI

[英]JavaScript Array.filter uniqes and not block the UI

I have a specific use case where some validation logic has to happen in the UI (for various business reasons[...]).我有一个特定的用例,其中一些验证逻辑必须在 UI 中发生(出于各种业务原因[...])。 The array may contain up to several tens or up to a few hundred thousand items (1-400K).该数组可能包含多达几十个或多达几十万个项目 (1-400K)。 The frontend is Angular based.前端是基于 Angular 的。

The first step is to check for duplicates (and store them in another array[...]).第一步是检查重复项(并将它们存储在另一个数组中[...])。 This is accomplished with below:这是通过以下方式完成的:

validateTargets(targets: string[]): ValidationResultObject[] {

    let result: ValidationResultObject[];
    let dups: string[] = [];

    var uniques = targets.filter( (item,index) => {
        if (targets.indexOf(item) === index) {
        return targets.indexOf(item) === index
        }
        else {
            dups.push(targets[index])
        }
    }

    //other validation logic goes here

    return result;
}

Problem is an obvious UI freeze when this runs against anything above 50K.问题是当它针对 50K 以上的任何内容运行时,明显的 UI 冻结。 For the time being I've put above as callback in another function in a setTimeout to at least allow the UI to run a spinner while the page hangs :)目前,我已经在setTimeout中的另一个函数中作为回调放在上面,以至少允许 UI 在页面挂起时运行微调器 :)

I've seen several ways people advise how to design code to allow UI to be responsive (or at least re-draw);我已经看到人们建议如何设计代码以允许 UI 具有响应性(或至少重新绘制)的几种方式; however, my case is a bit tricky since I deal with duplicates.但是,我的情况有点棘手,因为我要处理重复项。

I was thinking to break down the array to chunks and run above Array.filter part in a loop within a setTimeout (for UI) BUT I later need to compare the chunks against themselves anyways so it just prolongs the logic!我正在考虑将数组分解为块并在setTimeout (用于 UI)内的循环中在Array.filter部分上方运行,但我后来无论如何都需要将这些块与它们自己进行比较,因此它只会延长逻辑! I do not feel comfortable enough to experiment with workers as there are browsers in the organization that do not support those.我觉得对员工进行试验不太舒服,因为组织中的浏览器不支持这些浏览器。

Does anyone have an idea how to work this out?有谁知道如何解决这个问题? No, it is not possible to move this to backend :(不,不可能将其移动到后端:(

Regards问候

You can filter out duplicates much, much more efficiently:您可以更有效地过滤掉重复项:

let filtered = targets.reduce((result, item) => {
  result[item] = 1;
  return result;
}, {});
let noDuplicates = Object.keys(filtered);

That makes one pass over the array, and leverages the internal efficiency of property name lookup over the sequential search of .indexOf() .这使得一次遍历数组,并利用属性名称查找的内部效率超过.indexOf()的顺序搜索。 For an initial array with the extremely large number of elements you have, this should run in a comparably tiny amount of time.对于具有大量元素的初始数组,这应该在相对较短的时间内运行。

我从未遇到过这种情况,但我想问一下您是否在 javascript 中使用了Set类型,因为它在内部删除了重复项,并且比过滤JS Set vs Array更高效,如果您的浏览器不支持 Set,您仍然可以使用 polyfill。

You could use an asynchronous function to process this amount of data.您可以使用异步函数来处理此数量的数据。 When it's finished call a callback with the result as an argument to continue the normal flow after it is finished.当它完成时,以结果为参数调用回调以在完成后继续正常流程。

async validateTargets(targets: string[], callback: function): {
 //...Logic
 callback(result)
}

Also, to remove duplicates you could use此外,要删除重复项,您可以使用

[...new Set(items)]

Note: This will only work if the Items array contains only primitive values注意:这仅在 Items 数组仅包含原始值时才有效

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM