简体   繁体   English

Javascript 性能:While 与 For 循环

[英]Javascript Performance: While vs For Loops

The other day during a tech interview, one of the question asked was "how can you optimize Javascript code"?前几天在一次技术面试中,被问到的一个问题是“如何优化 Javascript 代码”?

To my own surprise, he told me that while loops were usually faster than for loops.令我惊讶的是,他告诉我 while 循环通常比 for 循环快。

Is that even true?这是真的吗? And if yes, why is that?如果是,那是为什么?

You should have countered that a negative while loop would be even faster!您应该反驳说,负while循环会更快! See: JavaScript loop performance - Why is to decrement the iterator toward 0 faster than incrementing .请参阅: JavaScript 循环性能 - 为什么将迭代器递减到 0 比递增更快

In while versus for , these two sources document the speed phenomenon pretty well by running various loops in different browsers and comparing the results in milliseconds: https://blogs.oracle.com/greimer/entry/best_way_to_code_a and: http://www.stoimen.com/blog/2012/01/24/javascript-performance-for-vs-while/ .whilefor ,这两个来源通过在不同浏览器中运行各种循环并以毫秒为单位比较结果,很好地记录了速度现象: https : //blogs.oracle.com/greimer/entry/best_way_to_code_a和: http://www .stoimen.com/blog/2012/01/24/javascript-performance-for-vs-while/

Conceptually, a for loop is basically a packaged while loop that is specifically geared towards incrementing or decrementing (progressing over the logic according to some order or some length).从概念上讲, for循环基本上是一个打包的while循环,专门针对递增或递减(根据某种顺序或某种长度在逻辑上进行)。 For example,例如,

for (let k = 0; ++k; k < 20) {…}

can be sped up by making it a negative while loop:可以通过使其成为负 while 循环来加速:

var k = 20;
while (--k) {…}

and as you can see from the measurements in the links above, the time saved really does add up for very large numbers.从上面链接中的测量结果可以看出,对于非常大的数字,节省的时间确实加起来。

While this is a great answer in minute detection of speed and efficiency I'd have to digress to @Pointy original statement.虽然这是对速度和效率的微小检测的一个很好的答案,但我不得不离题到@Pointy 的原始声明。

The right answer would have been that it's generally pointless to worry about such minutia, since any effort you put into such optimizations could be rendered a complete waste by the next checkin to V8 or SpiderMonkey正确的答案是,担心这种细节通常是没有意义的,因为您在此类优化中所做的任何努力都可能在下次签入 V8 或 SpiderMonkey 时完全浪费掉

Since Javascript is client side determined and was originally having to be coded per browser for full cross-browser compatibility (back before ECMA was even involved it was worse) the speed difference may not even be a logical answer at this point due to the significant optimization and adoption of Javascript on browsers and their compiler engines.由于 Javascript 是客户端确定的,并且最初必须为每个浏览器进行编码以实现完整的跨浏览器兼容性(在 ECMA 甚至涉及之前它更糟),由于显着优化,此时速度差异甚至可能不是合乎逻辑的答案以及在浏览器及其编译器引擎上采用 Javascript。

We're not even talking about about non-strict script only writing such as applications in GAS, so while the answers and questions are fun they would most likely be more trivial than useful in real world application.我们甚至不是在谈论非严格的脚本,比如在 GAS 中编写应用程序,所以虽然答案和问题很有趣,但它们很可能比在现实世界的应用程序中有用更琐碎。

To expound on this topic you first need to understand where this topic is originally coming from and compiling vs interpreting.要阐述这个主题,您首先需要了解这个主题的最初来源以及编译与解释。 Let's take a brief history of the evolution of languages and then jump back to compiling vs interpreting.让我们简要回顾一下语言的演变历史,然后再回到编译与解释之间。 While not required reading you can just read Compiling vs Interpeting for the quick answer but for in-depth understanding I'd recommend reading through both Compiling vs Interpreting and the Evolution of Programming (showing how they are applied today).虽然不是必需阅读,但您可以阅读 Compiling vs Interpeting 以获得快速答案,但为了深入理解,我建议阅读 Compiling vs Interpreting 和 Evolution of Programming(展示它们在今天的应用)。

COMPILING VS INTERPRETING编译与解释

Compiled language coding is a method of programming in which you write your code in a compilable manner that a compiler understands, some of the more recognized languages today are Java, C++ and C#.编译语言编码是一种编程方法,您可以在其中以编译器理解的可编译方式编写代码,当今一些更受认可的语言是 Java、C++ 和 C#。 These languages are written with the intent that a compiler program then translates the code into the machine code or bytecode used by your target machine.这些语言的编写意图是编译器程序然后将代码转换为目标机器使用的机器代码或字节码。

Interpreted code解释代码
is code that is processed J ust I n T ime (JIT) at the time of the execution without compiling first, it skips this step and allows for quicker writing, debugging, additions/changes, etc. It also will never store the script's interpretation for future use, it will re-interpret the script each time a method is called.是,被加工Ĵ乌斯在执行时N t个IME(JIT)无第一编译代码,它将跳过该步骤,并且允许更快的写入,调试,添加/变更等,也绝不会存储该脚本的解释为了将来使用,每次调用方法时它都会重新解释脚本。 The interpreted code is ran within a defined and intended program runtime environment (for javascript is usually a browser) to which once interpreted by the environment is then output to the desired result.解释的代码在定义的和预期的程序运行时环境(对于 javascript 通常是浏览器)中运行,一旦被环境解释,然后输出到所需的结果。 Interpreted scripts are never meant to be stand-alone software and are always looking to plug into a valid runtime environment to be interpreted.解释过的脚本从来都不是独立的软件,并且总是希望插入有效的运行时环境以进行解释。 This is why a script is not executable.这就是脚本不可执行的原因。 They'll never communicate directly a operating system.他们永远不会直接与操作系统通信。 If you look at the system processes occurring you'll never see your script being processed, instead you see the program being processed which is processing your script in its runtime environment.如果您查看正在发生的系统进程,您将永远不会看到正在处理的脚本,而是会看到正在处理的程序,该程序正在其运行时环境中处理您的脚本。

So writing a hello script in Javascript means that the browser interprets the code, defines what hello is and while this occurs the browser is translating this code back down to machine level code saying I have this script and my environment wants to display the word hello so the machine then processes that into a visual representation of your script.所以用 Javascript 编写一个 hello 脚本意味着浏览器解释代码,定义 hello 是什么,当发生这种情况时,浏览器正在将此代码转换回机器级代码,说我有这个脚本,我的环境想要显示单词 hello 所以然后机器将其处理为脚本的可视化表示。 It's a constant process, which why you have processors in computers and a constant action of processing occurring on the system.这是一个持续的过程,这就是为什么您在计算机中有处理器以及在系统上发生的持续处理动作的原因。 Nothing is ever static, processes are constantly being performed no matter the situation.没有什么是静止的,无论情况如何,流程都在不断地执行。

Compilers编译器
usually compile the code into a defined bytecode system, or machine code language, that is now a static version of your code.通常将代码编译成已定义的字节码系统或机器代码语言,即现在是代码的静态版本。 It will not be re-interpreted by the machine unless the source code is recompiled.除非重新编译源代码,否则机器不会重新解释它。 This is why you will see a runtime error post compilation which a programmer then has to debug in the source and recompile.这就是为什么您会在编译后看到运行时错误,然后程序员必须在源代码中调试并重新编译。 Interpreter intended scripts (like Javascript or PHP) are simply instructions not compiled before being ran so the source code is easily edited and fixed without the need for additional compiling steps as the compilation is done in real-time.解释器预期的脚本(如 Javascript 或 PHP)只是在运行之前未编译的指令,因此源代码很容易编辑和修复,无需额外的编译步骤,因为编译是实时完成的。

Not All Compiled Code is Created Equal并非所有编译后的代码都是平等的
An easy way to illustrate this is video game systems.说明这一点的一个简单方法是视频游戏系统。 The Playstation vs Xbox. Playstation 与 Xbox。 Xbox system are built to support the .net framework to optimize coding and development. Xbox系统内置支持.net框架,优化编码开发。 C# utilizes this framework in conjunction with a Common Language Runtime in order to compile the code into bytecode. C# 将此框架与公共语言运行时结合使用,以便将代码编译为字节码。 Bytecode is not a strict definition of compiled code, it's a intermediate step placed in the process that allows the writing of code quicker and on a grander scale for programs, that is then interpreted when the code is executed at runtime using, you guessed it, J ust I n T ime (JIT).字节码不是编译代码的严格定义,它是放置在过程中的一个中间步骤,它允许更快地为程序编写更大规模的代码,然后在运行时执行代码时对其进行解释,你猜对了, Ĵ乌斯N t个IME(JIT)。 The difference is this code is only interpreted once, once compiled the program will not re-interpret that code again unless restarted.不同之处在于这段代码只解释一次,一旦编译,除非重新启动,否则程序不会再次重新解释该代码。

Interpreted script languages will never compile the code, so a function in an interpreted script is constantly being re-processed while a compiled bytecode's function is interpreted once and the instructions are stored until the program's runtime is stopped.解释性脚本语言永远不会编译代码,因此解释性脚本中的函数不断地被重新处理,而编译后的字节码的函数被解释一次,并且指令被存储直到程序的运行时停止。 The benefit is that the bytecode can be ported to another machine's architecture provided you have the necessary resources in place.好处是字节码可以移植到另一台机器的架构,前提是你有必要的资源。 This is why you have to install .net and possibly updates and frameworks to your system in order for a program to work correctly.这就是为什么您必须在系统中安装 .net 以及可能的更新和框架才能使程序正常工作。

The Playstation does not use a .net framework for its machine. Playstation 不为其机器使用 .net 框架。 You will need to code in C++, C++ is meant to be compiled and assembled for a particular system architecture.您将需要使用 C++ 进行编码,C++ 旨在针对特定的系统架构进行编译和组装。 The code will never be interpreted and will need to be exactly correct in order to run.代码永远不会被解释,并且需要完全正确才能运行。 You can never easily move this type language like you could an intermediate language .您永远无法像移动中间语言那样轻松地移动这种类型的语言 It's made specifically for that machine's architecture and will never be interpreted otherwise.它专为该机器的架构而设计,绝不会以其他方式解释。

So you see even compiled languages are not inherently finalized versions of a compiled language.所以你会看到,即使是编译语言也不是编译语言的固有最终版本。 Compiled languages are meant, in their strict definition, to be compiled fully for use.编译型语言在其严格定义中意味着完全编译以供使用。 Interpreted languages are meant to be interpreted by a program but are also the most portable languages in programming due to only needing a program installed that understand the script but they also use the most resources due to constantly being interpreted.解释型语言旨在由程序解释,但也是编程中最便携的语言,因为只需要安装一个理解脚本的程序,但由于不断被解释,它们也使用最多的资源。 Intermediate languages (such as Java and C#) are hybrids of these 2, compiling in part but also requiring outside resources in order to still be functional.中间语言(如 Java 和 C#)是这两种语言的混合体,部分编译但也需要外部资源才能仍然正常工作。 Once ran they then compile again, which is a one time interpretation while in runtime.一旦运行,它们就会再次编译,这是在运行时的一次性解释。

Evolution of Programming编程的演变

Machine Code机器码
The lowest form of coding, this code is strictly binary in its representation (I won't get into ternary computation as it's based on theory and practical application for this discussion).编码的最低形式,该代码在其表示上是严格的二进制(我不会进入三元计算,因为它基于理论和本次讨论的实际应用)。 Computers understand the natural values, on/off true/false.计算机理解自然值,开/关真/假。 This is machine level numerical code, which is different from the next level, assembly code.这是机器级别的数字代码,不同于下一级,汇编代码。

Assembly Code汇编代码
The direct next level of code is assembly language.直接的下一级代码是汇编语言。 This is the first point in which a language is interpreted to be used by a machine.这是语言被解释为机器使用的第一点。 This code is meant to interpret mnemonics, symbols and operands that are then sent to the machine in machine level code.该代码旨在解释助记符、符号和操作数,然后以机器级代码发送到机器。 This is important to understand because when you first start programming most people make the assumption it's either this or that meaning either I compile or interpret.理解这一点很重要,因为当您第一次开始编程时,大多数人都会假设它是这个那个,意思是我编译或解释。 No coding language beyond low level machine code is either compile only instructions or interpret only instructions!!!除了低级机器代码之外的任何编码语言都不是仅编译指令或仅解释指令!!!

We went over this in "Not All Compiled Code is Created Equal".我们在“并非所有编译后的代码都生而平等”中对此进行了讨论。 Assembly language is the first instance of this.汇编语言是这方面的第一个实例。 Machine code is what the machine reads but assembly language is what a human can read.机器代码是机器读取的,而汇编语言是人类可以读取的。 As computers process faster, through better technological advancements, our lower level languages begin to become more condensed in nature and not needed to be manually implemented.随着计算机处理速度更快,通过更好的技术进步,我们的低级语言在本质上开始变得更加简洁,不需要手动实现。 Assembly language used to be the high level coding language as it was the quicker method to coding a machine.汇编语言曾经是高级编码语言,因为它是对机器进行编码的更快方法。 It was essentially a syntax language that once assembled (the lowest form of compiling) directly converted to machine language.它本质上是一种语法语言,一旦组装(编译的最低形式)直接转换为机器语言。 An assembler is a compiler but not all compilers are assemblers.汇编器是编译器,但并非所有编译器都是汇编器。

High Level Coding高级编码
High level coding languages are languages that are one step above assembly but may even contain an even higher level (this would be Bytecode/Intermediate languages).高级编码语言是比汇编语言高一级但甚至可能包含更高级别的语言(这将是字节码/中间语言)。 These languages are compiled from there defined syntax structure into either the machine code needed, the bytecode to be interpreted or a hybrid of either of the previous method combined with a special compiler that allows for assembly to be written inline.这些语言从那里定义的语法结构编译成所需的机器代码、要解释的字节码,或者是前一种方法与允许内联编写汇编的特殊编译器相结合的混合体。 High level coding like it's predecessor, Assembly, is meant to reduce the workload of the developer and remove any chance for critical errors in redundant tasks, like the building of executable programs.像它的前身Assembly 一样的高级编码旨在减少开发人员的工作量并消除冗余任务中出现关键错误的任何机会,例如构建可执行程序。 In today's world rarely will you see a developer work in assembly for the sake of crunching data in for the benefit of size alone.在当今世界,您很少会看到开发人员在汇编中工作,只是为了大小而处理数据。 More often than a developer may have a situation, like in video game console development, where they need a speed increase in the process.开发人员通常会遇到这样的情况,例如在视频游戏机开发中,他们需要加快流程的速度。 Because high level coding compilers are tools that seek to ease the development process they may not 100% of the compile the code in the most efficient manner for that system architecture.由于高级编码编译器是寻求简化开发过程的工具,因此它们可能无法 100% 以最有效的方式为该系统架构编译代码。 In that case Assembly code would be written to maximize the system's resources.在这种情况下,将编写汇编代码以最大化系统资源。 But you'll never see a person writing in machine code, unless you just meet a weirdo.但是你永远不会看到一个人用机器代码编写,除非你遇到一个怪人。

THE SUMMARY摘要

If you made it this far, congratulations!如果你做到了这一步,恭喜你! You just listened more in one sitting than my wife can, about this stuff, for a lifetime.你只是一次坐下来比我妻子听得更多,关于这些东西,一生。 The OP's question was about performance of while vs for loops. OP 的问题是关于 while 与 for 循环的性能。 The reason this is a moot point in today's standards is two-fold.在今天的标准中这是一个有争议的问题的原因有两个。

Reason One原因一
The days of interpreting Javascript are gone.解释 Javascript 的日子已经一去不复返了。 All major browsers (Yes, even Opera and Netscape) utilize a Javascript Engine that is made to compile the script before implementing it.所有主要浏览器(是的,甚至 Opera 和 Netscape)都使用 Javascript 引擎,该引擎用于在实现脚本之前对其进行编译。 The performance tweaks discussed by JS developers in terms of non-call out methods are obsolete methods of study when looking at native functions within the language. JS 开发人员在非调用方法方面讨论的性能调整在查看语言中的本机函数时是过时的研究方法。 The code is already compiled and optimized for that before ever being a part of the DOM.在成为 DOM 的一部分之前,代码已经为此进行了编译和优化。 It's not interpreted again while that page is up because that page is the runtime environment.在该页面启动时不会再次解释它,因为该页面是运行时环境。 Javascript has really become an intermediate language more so than interpreted script. Javascript 已经真正成为一种中间语言,而不是解释性脚本。 The reason it will never be called an intermediate scripting language is because Javascript is never compiled.它永远不会被称为中间脚本语言的原因是因为 Javascript 永远不会被编译。 That's the only reason.这是唯一的原因。 Besides that it's function in a browser environment a minified version of what happens with Bytecode.除此之外,它在浏览器环境中的功能是字节码发生的缩小版本。

Reason Two The chances of you writing a script, or library of scripts, that would ever require as much processing power as an desktop application on a website is almost nill.原因二您编写脚本或脚本库需要与网站上的桌面应用程序一样多的处理能力的可能性几乎为零。 Why?为什么? Because Javascript was never created with the intent to be an all encompassing language.因为 Javascript 的创建意图是成为一种无所不包的语言。 It's creation was simply to provide a medium level language programming method that would allow processes to be done that weren't provided by HTML and CSS, while the alleviating development struggles of requiring dedicated high level coding languages, specifically Java.它的创建只是为了提供一种中级语言编程方法,允许完成 HTML 和 CSS 未提供的过程,同时减轻需要专用高级编码语言(特别是 Java)的开发困难。

CSS and JS was not supported for most of the early ages of web development.大多数早期的 Web 开发都不支持 CSS 和 JS。 Till around 1997 CSS was not a safe integration and JS fought even longer.直到 1997 年左右,CSS 还不是一个安全的集成,而 JS 的战斗时间更长。 Everything besides HTML is a supplemental language in the web world.除了 HTML 之外的一切都是网络世界中的一种补充语言。

HTML is specific for being the building blocks for a site. HTML 专用于作为站点的构建块。 You'd never write javascript to fully frame a website.您永远不会编写 javascript 来完全构建网站。 At most you'd do DOM manipulation but building a site.您最多只能进行 DOM 操作,但要构建一个站点。

You'd never style your site in JS as it's just not practical.你永远不会在 JS 中设计你的网站,因为它不实用。 CSS handles that process. CSS 处理这个过程。

You'd never store, besides temporarily, using Javascript.除了临时,您永远不会使用 Javascript 进行存储。 You'd use a database.你会使用一个数据库。

So what are we left with then?那么我们还剩下什么呢? Increasingly just functions and processes.越来越只是功能和流程。 CSS3 and its future iterations are going to take all methods of styling from Javascript. CSS3 及其未来的迭代将采用 Javascript 的所有样式方法。 You see that already with animations and psuedo states(hover, active, etc.).您已经通过动画和伪状态(悬停、活动等)看到了这一点。

The only valid argument of optimization of code in Javascript at this point is for badly written functions, methods and operations that could be helped by optimization of the user's formula/code pattern.在这一点上,Javascript 中代码优化的唯一有效论据是写得不好的函数、方法和操作,它们可以通过优化用户的公式/代码模式来帮助。 As long as you learn proper and efficient coding patterns Javascript, in today's age, has no loss of performance from its native functions.只要你学习正确和高效的编码模式 Javascript,在当今时代,它的原生功能并没有损失性能。

for(var k=0; ++k; k< 20){ ... }

can be sped up by making it a negative while loop:可以通过使其成为负 while 循环来加速:

 var k = 20; while(--k){ ... };

A more accurate test would be to use for to the same extent as while .更准确的测试是使用for的程度与while相同。 The only difference will be that using for loops offers more description.唯一的区别是使用 for 循环提供了更多的描述。 If we wanted to be super crazy we could just forgo the entire block;如果我们想变得超级疯狂,我们可以放弃整个街区;

var k = 0;
for(;;){doStuff till break}
//or we could do everything
for (var i=1, d=i*2, f=Math.pow(d, i); f < 1E9; i++, d=i*2, f=Math.pow(d,i)){console.log(f)}

Either way...in NodeJS v0.10.38 I'm handling a JavaScript loop of 10 9 in a quarter second with for being on average about 13% faster.无论哪种方式......在v0.10.38的NodeJS我处理9在四分之一秒的用JavaScript的环路是平均约13%的速度。 But that really has no affect on my future decisions with which loop to use or the amount I choose to describe in a loop.但这对我未来决定使用哪个循环或我选择在循环中描述的数量没有影响。

> t=Date.now();i=1E9;
> while(i){--i;b=i+1}console.log(Date.now()-t);
292
> t=Date.now();i=1E9;
> while(--i){b=i+1}console.log(Date.now()-t);
285
> t=Date.now();i=1E9;
> for(;i>0;--i){b=i+1}console.log(Date.now()-t);
265
> t=Date.now();i=1E9;
> for(;i>0;){--i;b=i+1}console.log(Date.now()-t);
246 

2016 Answer 2016 答案

In JavaScript the reverse for loop is the fastest.在 JavaScript 中,反向 for 循环是最快的。 For loops are trivially faster than while loops.对于循环是平凡比while循环更快。 Be more focused on readability .更加注重可读性

Here is some bench marking.这是一些基准标记。

The following loops where tested:测试了以下循环:

var i,
  len = 100000,
  lenRev = len - 1;

i = 0;
while (i < len) {
    1 + 1;
    i += 1;
}

i = lenRev;
while (-1 < i) {
    1 + 1;
    i -= 1;
}

for (i = 0; i < len; i += 1) {
    1 + 1;
}

for (i = lenRev; - 1 < i; i -= 1) {
    1 + 1;
}

2017 Answer 2017 答案

jsperf for vs foreach on Chrome 59 jsperf for vs foreach 在 Chrome 59 上

Here you can see Array.forEach has become fastest on the latest version of Chrome (59) as of the date written (7/31/17).在这里你可以看到Array.forEach在最新版本的 Chrome (59) 上成为最快的,截至撰写日期 (7/31/17)。 You can find average times for other browser versions here: https://jsperf.com/for-vs-foreach/66 .您可以在此处找到其他浏览器版本的平均时间: https : //jsperf.com/for-vs-foreach/66

This shows to prove that ES engine optimization changes what is more efficient at any time.这证明了 ES 引擎优化随时改变更有效的东西。

My recommendation is that you use whichever is more expressive for your use case.我的建议是您使用对您的用例更具表现力的任何一种。

Performance differences within the same magnitude will mostly be irrelevant in the future as computers become faster exponentially by Moore's Law.随着计算机按照摩尔定律呈指数级增长,相同量级内的性能差异在未来几乎无关紧要。

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

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