Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

preface

I remember being asked by an interviewer how to test the speed of a certain operation (execution time).

var start = (new Date()).getTime(); Var end = (new Date()).getTime(); console.log( "Duration:", (end - start) );Copy the code

But this is the wrong solution

Why is that?

This particular run of the operation took about this long. And whether it always runs at that speed, you basically have no idea. You don’t know if the engine or the system is affected at this point, or if the calculation will run faster at other times. Such a low reliability test would hardly support any of your decisions. This performance test is basically useless.

repeat

Many people might wrap it in a loop so that the entire test takes longer to run. If you repeat an operation 100 times and the entire loop reports 137ms, you can divide it by 100 to get an average time of 1.37ms per operation, but that’s not true.

Simple mathematical averages are by no means sufficient to make judgments about the performance you want to extrapolate across the application. By iterating 100 times, even a few (too high or too low) outliers can affect the average, and then by applying the result repeatedly, you spread out the error, creating even more deception.

Benchmark.js

I’m not going to go through their entire documentation to explain how benchmark.js works. Their API is great, you should read it. There are also some great articles that cover more details and methods, Like here perfplanet.com/2010/bulletproof-javascript-benchmarks (http://calendar.) and here (monsur. Hosa. / 2012/12/11 / in Benchmarksjs. HTML).

Function foo() {var bench = new Benchmark("foo test", var bench = new Benchmark("foo test", var bench = new Benchmark("foo test", var bench = new Benchmark("foo test", var bench = new bench) {//... // Optional additional options (see documentation)}); bench.hz; // the number of operations per second; // Error bound bench. Stats. Variance; // Sample variance //Copy the code

The environment is king

The test conditions are as close to what you expect to be true as possible. Only in this way can the result come close to the truth.

jsPerf.com

JsPerf’s benchmark.js library runs statistically accurate and reliable tests and places the results on a publicly available URL that you can forward to others.

Write a test

To write tests well, you need to carefully analyze and think about what the differences are between the two test cases and whether those differences are intentional or not.

Don’t try to narrow down to a tiny piece of real code and measure only that small piece of performance out of context, because functional and performance testing is better when you include a larger (still meaningful) context. These tests may also run slower, meaning that any differences found in the environment are more meaningful.

Micro performance

A lot of times, some of the performance optimizations we make through code may not make a big difference in the engine’s eyes, such as ++ I drinking I ++.

Not all engines are alike

The engine is free to decide whether an operation needs to be optimized, possibly by trade-offs, to replace the secondary performance of the operation. It’s hard to find a way for an algorithm to run fast in all browsers.

The big picture

How do you know what the big picture is? The first step is to know if your code is running on the critical path. If you are not on the critical path, your optimizations will probably not benefit much.

Tail-call optimization

A tail call is a function call that appears at the “end” of another function. After this call, there is nothing left to do.

A non-recursive tail call:

function foo(x) { return x; } function bar(y) { return foo(y + 1); } function baz() {return 1 + bar(40); } baz(); / / 42Copy the code

Foo (y + 1) is the bar (..) In, because in foo(..) When done, bar(..) That’s done, too, and you just need to return foo(..) The result of the call. However, bar(40) is not a tail call, because after it is done, its result needs to be incremented by one before it can be returned by baz().

summary

  • Effective performance testing of a piece of code, especially against an alternative to the same code to see which is faster, requires careful attention to detail;
  • Tail-call optimization is an optimization required by ES6 that makes some of the recursive patterns in JavaScript that would otherwise be impossible practical.