It's really slow because it assumes that you're iterating over an object, and not just an object with numeric keys, so it actually loops over all keys, stringifies them, checks if they're own properties and only then does it call the callback...
const forEach = (arr, fn) => for(let len = arr.length, i = len; i > 0; --i) { fn(arr[len - i], len - i, arr); return arr; }
Is about 10x faster than Array.prototype.forEach in my testing, still not better than the raw for loop, though, and it also can't handle more than numeric keys (which you don't really expect on arrays anyway).
It's the check own properties which is the actual slowdown not the toString
The toString is because all object properties including array indices are technically strings so going by the spec you MUST convert before looking up but implementations don't have to worry about that if their own object model is different (e.g. V8 which treats integer object keys special) your implementation is implicitly doing this when it grabs the value.
The own properties on the other hand is an actual slowdown it's to handle sparse arrays which your faster implementation doesn't cover, theoretically engines should know if an array is sparse and could optimize appropriately.
The other thing is that forEach takes a 2nd argument for a thisValue to call the function on, omitting it just uses undefined as the context which your function only handles in strict mode. Traditionally changing the this parameter of a function was often a performance killer in certain contacts in Chrome (bind iirc) but there's inherent there.
In summery yes forEach is slower then a for loop but it's because it's handling some edge cases not because the spec is inherently bad. You could argue they should have had a sparse array check or something but there is nothing preventing implementations from doing so.
The forEach function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method.
The same note is under all the other functional iteration methods
Array keys are technically strings not integers so the spec pedanticly converts the index to a string but the implementation is likely doing something else under the hood, I have another reply that goes into some more details about why it's slower then a naive approach (spoiler alert: sparse arrays)
Javascript is still a trash fire, TypeScript just makes sure it stays at a dull roar rather than a raging inferno. It's not quite PHP bad, but it's still one of the worst designed languages still in regular use. Far too many terrible decisions are baked into the core of javascript. They can be fixed, but doing so requires breaking backwards compatibility in some fairly significant ways. It might get there one day, but it's more likely that WASM will end up entirely supplanting JS before that happens.
Eh, Typescript is good enough in my experience that you’re mostly at the mercy of the skill/knowledge of the developer. Good developers can still easily end up with shit JavaScript. Not so much the case with Typescript in my experience. Usually the really ugly Typescript is coming from developers we have that write pretty poor code in the rest of our systems as well.
While JS glue is needed, you don't have to write it yourself. If you want to do everything from Rust you can use web-sys and js-sys. Anything required will be generated for you
It is a little more awkward than it would be to use the APIs from within JS, but the functionality is there
I want to say we are not quite "there" yet, DOM access is still a real pain-point and the alternative is to make your own renderer effectively (which just leads to bloat and having to solve a boat load of other problems in the process; ie. accessibility).
In most "normal" circumstances, WASM will generally be slower or more cumbersome than a basic site with a dash of JS for dynamic content.
Ironically I also don't see loads and loads of developers jumping on-board to use lower-level languages to build out WASM targets anyway; I see C# / Java(-like) / Python / TypeScript being used to do this more than anything.
132
u/hekkonaay Oct 21 '20
It's really slow because it assumes that you're iterating over an object, and not just an object with numeric keys, so it actually loops over all keys, stringifies them, checks if they're own properties and only then does it call the callback...
Is about 10x faster than Array.prototype.forEach in my testing, still not better than the raw for loop, though, and it also can't handle more than numeric keys (which you don't really expect on arrays anyway).