JavaScript 性能长时间运行的任务

2024-01-24

前几天我注意到这里有一个问题(减少 Javascript CPU 使用率 https://stackoverflow.com/questions/6846681/reducing-javascript-cpu-usage)我很感兴趣。

本质上,这个人想要逐个字符地加密一些文件。显然,一次性完成所有这些操作将会锁定浏览器。

他的第一个想法是一次以大约 1kb 的字符串块的形式进行处理,然后暂停 X 毫秒,这样用户就可以在处理之间保持与页面的交互。他还考虑过使用 webWorkers (最好的想法),但它显然不是跨浏览器的。

现在我真的不想解释为什么这在 javascript 中可能不是一个好主意。但我想看看是否能想出一个解决方案。

我记得看过 Douglas Crockford 的视频在 jsconf http://blip.tv/jsconfeu/douglas-crockford-loopage-4384069。该视频与 Node.js 和事件循环相关。但我记得他谈到将长时间运行的函数分解为单独的块,因此新调用的函数会到达事件循环的末尾。而不是用长时间运行的任务阻塞事件循环,从而防止其他事情发生。

我知道这是一个值得我研究的解决方案。作为一名前端开发人员,我从未真正经历过 JS 中运行时间极长的任务,并且热衷于了解如何分解它们以及它们如何执行。

我决定尝试一个递归函数,它从 0 毫秒的 setTimeout 内部调用自身。我认为这将为事件循环中想要在运行时发生的任何其他事情提供中断。但我也认为,当没有其他事情发生时,你将获得最大的计算量。

这是我想出的。

(我要为代码道歉。我正在控制台中进行实验,所以这又快又脏。)

function test(i, ar, callback, start){
    if ( ar === undefined ){
        var ar = [],
        start = new Date;
    };
    if ( ar.length < i ){
        ar.push( i - ( i - ar.length )  );
        setTimeout(function(){
            test( i, ar, callback, start);
        },0);
    }
    else {
        callback(ar, start);
    };
}

(您可以将此代码粘贴到控制台中,它将起作用)

本质上,该函数的作用是获取一个数字,创建一个数组并在调用自身时调用自身array.length < number将到目前为止的计数推入数组。它将第一次调用中创建的数组传递给所有后续调用。

我对其进行了测试,它似乎完全按照预期工作。只是它的性能相当差。我用它测试了一下..

(这又不是性感的代码)

test(5000, undefined, function(ar, start ){ 
    var finish = new Date; 
    console.log(
        ar.length,
        'timeTaken: ', finish - start 
    ); 
});

现在我显然想知道需要多长时间才能完成,上面的代码大约花了20秒。现在在我看来,JS 计数到 5000 不应该需要 20 秒。再加上它正在做一些计算和处理,以将项目推送到数组中。但 20 多岁还是有点陡。

因此,我决定同时生成几个,看看这对浏览器性能和计算速度有何影响。

(代码并没有变得更性感)

function foo(){ 
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 1'  ) });
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 2'  ) });
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 3'  ) });
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 4'  ) });
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 5'  ) });
};

所以总共有五个,同时运行并且不会导致浏览器挂起。

进程结束后,所有结果几乎同时返回。全部完成大约需要 21.5 秒。这仅比单独运行慢 1.5 秒。但我将鼠标在窗口中移动到具有以下内容的元素上::hover效果只是为了确保浏览器仍然响应,因此这可能会导致 1.5 秒的开销。

因此,由于这些函数显然是并行运行的,因此浏览器中留下了更多的计算资源。

有谁能够解释一下这里发生的性能问题,并详细说明如何改进这样的功能?

只是为了发疯我这样做了..

function foo(){
    var count = 100000000000000000000000000000000000000;  
    test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 1'  ) });
    test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 2'  ) });
    test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 3'  ) });
    test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 4'  ) });
    test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 5'  ) });
};

在我写这篇文章的整个过程中,它一直在运行,并且仍在继续。浏览器没有抱怨或挂起。结束后我会添加完成时间。


setTimeout 没有最小延迟0ms。最小延迟在 5ms-20ms 范围内,具体取决于浏览器。

我自己的个人测试表明setTimeout不会立即将您放回到事件堆栈上

实例 http://jsfiddle.net/km5tY/63/

在再次调用之前它有一个任意的最小时间延迟

var s = new Date(),
    count = 10000,
    cb = after(count, function() {
        console.log(new Date() - s);    
    });

doo(count, function() {
    test(10, undefined, cb);
});
  • 并行运行 10000 个这样的程序,数到 10 需要 500 毫秒。
  • 运行 100 计数到 10 需要 60 毫秒。
  • 从 1 计数到 10 需要 40 毫秒。
  • 运行 1 计数到 100 需要 400 毫秒。

显然,每个人似乎setTimeout必须等待至少 4ms 才能再次调用。但这就是瓶颈。个别延迟setTimeout.

如果您并行安排其中 100 个或更多,那么它就会起作用。

我们如何优化这个?

var s = new Date(),
    count = 100,
    cb = after(count, function() {
        console.log(new Date() - s);    
    }),
    array = [];

doo(count, function() {
    test(10, array, cb);
});

在同一阵列上设置 100 个并行运行。这将避免主要瓶颈,即 setTimeout 延迟。

以上在2ms内完成。

var s = new Date(),
    count = 1000,
    cb = after(count, function() {
        console.log(new Date() - s);    
    }),
    array = [];

doo(count, function() {
    test(1000, array, cb);
});

7 毫秒内完成

var s = new Date(),
    count = 1000,
    cb = after(1, function() {
        console.log(new Date() - s);    
    }),
    array = [];

doo(count, function() {
    test(1000000, array, cb);
});

并行运行 1000 个作业大致是最佳的。但你会开始遇到瓶颈。数到 100 万仍然需要 4500 毫秒。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript 性能长时间运行的任务 的相关文章

  • 如何获取数组中对象的属性名称?

    这是我的数组 var testeArray name Jovem1 esteira Macaco name Jovem esteira Doido horse Chimbinha 从上面 我想得到一个像这样的数组 var propertyN
  • Angular JS - 如何验证数字输入中的位数

    我们想要做的是 有一个仅接受 0 24 的输入 对于时间输入应用程序 这些是用户应该能够输入到输入中的值 0 1 2 3 4 5 6 7 8 9 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
  • 使用 Jasmine 监视 Backbone.js 路由调用

    在主干路由器上监视方法调用时遇到问题 以确保它在给定路由上调用正确的方法 测试摘录 describe Router gt beforeEach gt router new App Router Backbone history start
  • React 测试库:当输入表单上的 fireEvent 更改时,给定元素没有值设置器

    我想改变的值材质用户界面 https material ui com components text fields TextField在反应测试库中 我已经设置了 data testid 然后使用getByTestId我拿起了输入元素 th
  • 仅返回 JavaScript 字符串中最后一个下划线之前的文本

    如果我有一个像这样的字符串 var str Arthropoda Arachnida Zodariidae Habronestes hunti 如何获取最后一个下划线之前的字符串的第一部分 在这种情况下我只想 Arthropoda Arac
  • 如何获取 CSS 旋转元素的实际(非原始)高度

    我需要获取几个不同元素的实际高度 为了精确的自定义工具提示定位 并且其中一些元素 不是全部 被旋转 elem outerHeight 返回原始高度 而不是实际显示的高度 这是一个非常简单的例子 http jsfiddle net NPC42
  • 重置输入控件的边框颜色 (HTML/Javascript)

    有谁知道使用 javascript 修改输入控件后如何重置它的边框颜色 通过突出显示其中包含不正确或无效数据的字段等来进行验证非常有用 例如 改变边框 document getElementById myinput style border
  • 自定义过滤器在 Angular Hybrid 应用程序中不起作用

    我正在尝试将 AngularJS 1 6 应用程序与 Angular 5 一起转换为混合应用程序 我定义了以下简单过滤器 function use strict var filterId colorPicker angular module
  • JavaScript/Angular 1 - Promise.all 到 async-await

    我在两个变量中分配了对 Web 服务的两次调用referencesPromise and contactTypesPromise onInit 如果需要 我可以为此创建一个新方法 onInit const referencesPromise
  • 与玻璃钢战斗

    我读过有关 FRP 的内容 非常兴奋 它看起来很棒 因此您可以编写更多高级代码 并且一切都更加可组合 等等 然后我尝试用数百个 sloc 从纯 js 到 Bacon 重写我自己的小游戏 我发现 我实际上不是编写高级纯逻辑代码 而是击败了 B
  • 更改导航栏悬停时 div 的背景图像

    我正在开发一个项目 我对 Javascript 很陌生 所以我想知道是否有 Jquery 代码或只是一个关于如何使背景图像在导航菜单悬停时更改的过程 例如将鼠标悬停在链接一上会将 div 的背景图像更改为图像 1 将鼠标悬停在链接二上会将
  • 如何使 Loopback 模型事件起作用?

    我尝试过一个例子http apidocs strongloop com loopback model http apidocs strongloop com loopback model MyModel on changed functio
  • 如何提高 Guice 启动时的性能

    好吧 我知道我的计算不客观等等 但无论如何 我讨厌在执行单元测试时等待这么多时间 我的 guice swing 应用程序需要大约 7 秒来初始化 这是一个简单的 IRC 客户端 在那一刻 没有打开连接 我什至还没有调用任何 java io
  • Web 扩展中共享 vuex 状态(死对象问题)

    我正在尝试在网络扩展中使用共享的 vue js 状态 状态存储在后台脚本的 DOM 中并呈现在弹出页面中 第一次尝试 我的第一次尝试是使用一个没有 vuex 的简单商店 背景 js var store count 0 popup js br
  • 如何在 C# 中通过 JavaScript 回调运行 QUnit 测试并获取测试结果?

    在我的几个项目中 我使用 MVC 模式将代码 关注点 分为 3 层 模型层和控制层都在 C 上运行 因此我使用 MSTest 或 NUnit 等测试框架来验证这些层的功能需求 对于视图层 我使用 QUnit 来测试 JavaScript 文
  • 是否可以阻止在每个 HTTP 请求中发送 cookie?

    我最近发现 这里 每个网络请求都会发送浏览器cookie吗 https stackoverflow com questions 1336126 does every web request send the browser cookies
  • 为什么 foreach 这么慢?

    PHPBench com http www phpbench com 在每个页面加载上运行快速基准测试脚本 在 foreach 测试中 当我加载它时 foreach 的运行时间是第三个示例的 4 到 10 倍 为什么本机语言构造明显比执行逻
  • 谷歌地图通过骨干javascript返回div标签但不显示

    我已经开始使用地理定位 我可以获得坐标等 我想在地图中显示它 但是当我将地图返回到 div 时 什么也没有显示 现在我查看了 div 地图正在返回 但只是不可见 这是有问题的 div 请注意 这似乎只是一个小地图的链接 a style di
  • CasperJS:如何单击所有选定的按钮?

    我正在尝试使用 CasperJS 作为网络抓取工具 并且有一个带有按钮的页面 单击该按钮将加载数据 因此 我想先单击所有这些按钮 然后等待 然后再实际进行查询以获取所有必要的数据 问题是对于 Casper casper thenClick
  • 用于将字符串与通配符模式进行匹配的递归函数

    所以我一整天都在试图解决这个作业 只是无法完成 以下函数接受 2 个字符串 第二个 不是第一个 可能包含 的 星号 An 是字符串的替换 空 1个字符或更多 它可以出现 仅在s2中 一次 两次 更多或根本不出现 它不能与另一个相邻 ab c

随机推荐

  • jQuery 中触发退格键

    如何在 jQuery 中触发退格键事件 以下示例不起作用 var e jQuery Event backspace keyCode 8 myarea trigger e 你实际上无法触发它 例如 您可以从某个输入中删除最后一个字符 但无法触
  • 返回范围的 SQL Select 查询[重复]

    这个问题在这里已经有答案了 可能的重复 MS SQL Server 中的行偏移 https stackoverflow com questions 187998 row offset in ms sql server 我想选择从 x1 到
  • 如何优雅地处理请求中的连接错误?

    我有一个简单的 python 电报机器人 代码如下 import requests import json from time import sleep import os filename bot last update target o
  • 具有自动生成源的 Cmake 可执行文件

    我想从 test runner cpp 中创建一个可执行文件 add executable myexe CMAKE CURRENT BINARY DIR test runner cpp 但这个特定的 cpp 文件本身是在预构建命令中自动生成
  • 如何防止我的 macOS 应用程序同时运行多个实例?

    我有一个应用程序 我允许用户使用启动器应用程序通过首选项启用 登录时打开 请参阅https en atjason com Cocoa SwiftCocoa Auto 20Launch 20at 20Login html https en a
  • 在 Jenkins 中对参数组进行分组和装饰

    我正在编写一个带有相当多参数的 Jenkins 管道作业 并且我正在寻找一种方法visually将它们组合在一起 以便更容易理解 而不是将它们全部扔在那里 我会满足于至少暗示这些参数彼此相关这一事实的任何内容 可能是标题 也可能是盒子 有没
  • 配置更改时 Intent extras 为空

    我创建了一个显示在SurfaceView我可以得到setDataSource通过使用Bundle extras getIntent getExtras 一切正常 直到我尝试设置景观布局land layout xml 我的日志猫是 Cause
  • 没有验证错误时工具提示不显示 WPF

    我搜索并没有看到解决方案 如果我没有在组合框工具提示属性中设置工具提示 我只能获得显示工具提示的验证 我希望看到验证错误工具提示 当存在时 否则显示组合框属 性中的工具提示 当我从工具提示属性 即从组合框的属性面板 中删除文本时 验证工具提
  • 如何将升序和降序结合起来?

    我有一个非常大的文件 很多千兆字节 看起来像 输入 txt a textA 2 c textB 4 b textC 5 e textD 1 d textE 4 b textF 5 第一步 我想按第三列按降序对行进行数字排序 如果行与第三列具
  • MySQL Workbench:未选择对象

    我已经在我的机器上安装了 MySQL Workbench 但现在我无法选择左侧的表格 这是我目前所拥有的 如何访问数据库中的表 向下拉滚动条 我遇到了同样的问题 但我所需要做的就是扩展导航菜单
  • 生成列表 - 几何级数

    我想使用具有 4 个参数的谓词生成一个几何级数列表 将生成级数的列表 此列表的长度 起始元素和级数的乘数 到目前为止 我所做的只是使用一个 3 参数谓词来不间断地生成几何级数 gengeom X X gengeom H Tail H Q X
  • 如何对位标志枚举实现按位运算?

    我有一个如下所示的枚举 repr u8 pub enum PublicFlags PublicFlagVersion 0x01 PublicFlagReset 0x02 NoncePresent 0x04 IdPresent 0x08 Pk
  • 我可以在我的 iOS 应用程序中使用实验性 WebKit 功能吗?

    我正在使用react native 开发一个iOS 应用程序 我想使用仍处于 实验 阶段的 MediaRecorder 我在 Safari 高级设置中打开了它 但是当我尝试在我的应用程序中使用它时 var mediaRecorder new
  • Symfony 5 ParamConverter 更新后损坏

    最后的作曲家更新完全破坏了我基于 Symfony5 的项目 php CRITICAL Uncaught Error Argument 1 passed to Sensio Bundle FrameworkExtraBundle Reques
  • C++ 到 CLR 的字节码编译器?

    我希望能够编译 C C 库 以便它在 CLR 中的托管运行时中运行 有几个工具 http en wikipedia org wiki Java Virtual Machine C to bytecode compilers使用 JVM 执行
  • xpath 表达式上的 Postgresql 索引没有加速

    我们正在尝试在 Postgresql 中创建 OEBS 模拟功能 假设我们有一个表单构造函数 需要将表单结果存储在数据库中 例如电子邮件正文 在 Oracle 中 您可以使用具有 150 列的表 以及存储在其他位置的一些映射 将每个字段存储
  • 如何在 PHP 中更新 MySQL 行?

    我正在使用一个 MySQL 数据库 但是当我尝试更新其中的一行时 它不起作用 这是我正在使用的更新代码 mysql query UPDATE offtopic SET next insert WHERE id id 首先 你应该让它更安全一
  • 无法连接到“ssl://gateway.sandbox.push.apple.com:2195”

    我在我的MacBook Air中成功运行了APNS代码 但事实证明我无法在我的另一台计算机上运行它 我检查了一下这些是相同的 1 pem 文件 具体 2 程序 无法工作的计算机有 Windows 7 XAMPP 支持 OpenSSL 无防火
  • 在 PHP 中设置浮点数的精度

    我从数据库中获取一个号码 这个号码可能是float or int 我需要将数字的小数精度设置为3 这使得数字不长于 关于小数 5 020 or 1518845 756 使用PHP round number precision 我看到一个问题
  • JavaScript 性能长时间运行的任务

    前几天我注意到这里有一个问题 减少 Javascript CPU 使用率 https stackoverflow com questions 6846681 reducing javascript cpu usage 我很感兴趣 本质上 这