4 ms·
const foo = [...bar]; is about 20x slower than const foo = bar.slice(); Yes, 20x. It only gets worse the more you do it -- it's both slower and wastes more mem
by Jasper_ 4y ago
const foo = [...bar]; is about 20x slower than const foo = bar.slice();
Yes, 20x. It only gets worse the more you do it -- it's both slower and wastes more memory, because it relies on the Iterator protocol, which actually compiles to something like this:
const foo = [];
const iter = bar[Symbol.iterator]();
while (true) {
const it = iter.next();
foo.push(it.value);
if (it.done)
break;
}
Minus some extra error handling with try/catch. Note, that all those calls to .next() every loop have to be dispatched; they can be optimized away, but V8 and JSC are very picky about when they can inline something like this. Also note that every call to .next() returns a brand new object, which means a lot of GC pressure. If you're copying an array of 20,000 items, you just created 20,000 tiny objects of garbage which all need to be GC'd.
Last I asked around, everyone said escape analysis would solve this. But in the 7 years I've been writing JS, I've never seen a single engine correctly elide this object creation. Every so often I boot up d8 with its assembly dumper and confirm, that yes, it is still creating a heap object, even in simple cases, yes, even with all optimizations enabled.
I try and ban all uses of the iterator protocol (for...of, spread, some kinds of destructuring assignment) in all the high-performance code I write. It's helpful, but it's a huge battery drain. And it's because they just spec'd the feature wrong.
- melony 4y agoWhy does React use it so much?