The iterator version speeds up 10x in safari here if I slightly modify it to
let i = 0; return { next: () => ({ done: (i > N), value: ++i }) };
and then re-run the table a few times until the JIT decides to compile it more aggressively.
While we microbenchmarking this, a basic loop is way less overhead than any of these
for (let i = 0; i < b.iterations; i++) {
let sum = 0;
for (let j = 0; j < N; j++) sum += j;
}
That's true. The browser matters a lot here. The code you suggested is unfortunately not always possible when you may want an iterator (also it needs to be i++). I am trying to benchmark the pattern here and not the specific implementation.
To be honest I don't know if microbenchmark with a trivial inside is super helpful for making decisions. In nearly all real code, the contents are going to be much more expensive than the overhead. In the very hottest tiny inner loops where the overhead ends up dominating (or where the use of generators or other features prevents the JIT from compiling the code to a high-performance version for whatever reason), people should profile their code and try to switch to a basic for loop if at all possible.
Absolutely! I was writing some code to iterate over vectors from a database and did this experiment after we noticed that switching to generators slowed down our throughput but a lot. I then wrote this benchmark to see whether generators were the issue (which it seems like they are) and whether iterators may be okay. We implemented iterators eventually. The performance was the same as the callback in our use case (at least in node).
Yes, indeed very interesting. I was very surprised to see the differences in performance among the cases and also among the browsers.
Generator vs Iterator vs Callback | Dominik Moritz | Observable