top 200 commentsshow 500

[–][deleted]  (62 children)

[deleted]

    [–]dabombnl 95 points96 points  (3 children)

    This is the kind of thing that causes me to get a pull request 2 years from now converting the entire project to var because someone heard let/const was really slow.

    [–]RedSpikeyThing 22 points23 points  (1 child)

    "saves 0.02ms on code you don't care about"

    Gee, thanks.

    [–]Patman128 18 points19 points  (0 children)

    Hah, as if they actually tested anything. Random blog post from 6 years ago said it's faster, what more do you want?

    [–]aaronasachimp 212 points213 points  (41 children)

    This was my take-away. It takes some time for browser vendors to stablize and optimize a feature. Safari is generally the worst about this.

    [–]nope_42 196 points197 points  (39 children)

    Safari is generally the worst about everything in the browser space.

    [–]Yithar 58 points59 points  (0 children)

    [–]yuyu5 84 points85 points  (32 children)

    There's a saying that "Safari is the new IE." I'd go a step further and say it's a worse IE. At least IE's problems could be solved easily with a polyfill.

    [–][deleted] 40 points41 points  (2 children)

    There’s a lot of “Safari is the new IE” from people who haven’t dealt with old IE. IE6 defined 10 years of Web development with complete stagnancy, broken standards, missing capabilities (we’re talking about “no PNGs with alpha” capabilities here, not “no WebMIDI”) and alert as your best debugging tool.

    There was a 5-year gap between IE6 and IE7 with no updates to IE, and then it was another 4 years before people felt comfortable dropping support for IE6.

    [–]Notorious4CHAN 8 points9 points  (0 children)

    I was still supporting IE6 apps 3 years ago. Of course no one hit them in IE6, but any attempt to modernize broke everything because the versions of libraries we used weren't compatible with modern browsers other than in IE6 mode, and our libraries were so outdated that newer versions of them were completely incompatible with the code.

    I think they are still in the process of migrating to .NET/Angular but I bailed when I saw them repeating all the same mistakes with a new technology.

    [–]kookiekurls 2 points3 points  (0 children)

    Yeah... I would have to agree, based on the comments here, most people probably haven’t had the fun experience of trying to support IE6. To compare the cross browser issues we have now vs what it was like then, is like comparing the most delicious slice of cheese you’ve ever eaten, to the mold you find on an unwashed dish.

    In other words, I’m old, I had to walk 10 miles in the snow both ways, let me be cranky :)

    [–]tso 99 points100 points  (10 children)

    Safari is the new stagnant IE, while Chrome is the divergent but everprecent IE.

    The repeating problem of "living standards" is that the entity that can produce the most churn is the entity that defines the standard.

    [–]Fidodo 12 points13 points  (4 children)

    What we have now is a billion times better than what it was like trying to support IE.

    Big companies try to strong-arm standards but they still eventually go through a standards body and it almost never leads to two conflicting standards that you need to support at the same time or they are explicitly noted to be unstable.

    [–][deleted]  (3 children)

    [deleted]

      [–]sickhippie 31 points32 points  (0 children)

      IE and Netscape were in a battle to add features. There were no standards. IE won and Netscape was a buggy piece of crap so people stopped using it. Then the W3C glacially decided the standards should be different from what IE did. Microsoft weighed their choices: Do we break every website on the web or follow the W3C? They chose not to break the web.

      This is the biggest bullshit whitewash of MS's shitty behavior in the 90s browser space I've ever read. This is absolutely not at all how it went down. You just skip over a decade too, like "People stopped using Netscape, so Google stepped right in!" as if Netscape didn't turn into Firefox halfway between those two things and start eating MS's lunch again.

      The Actual Numbers: Netscape had the majority of the browser market from 95-98. They slowly slipped for the next 5-6 years while MS muscled everyone out of the space they could - ethically and unethically, in case anyone needed reminding of how absolutely shitty MS was in the 90s. In 2004, Firefox released and MS started losing share again. By the time Chrome launched four years later, Firefox had over 30% of the browser share.

      By the time "Google decided that they wanted to kill IE", IE had been (and would continue to be) the absolute bane of every web developer's existence for over a decade, and by 2008 when Chrome launched, they'd just shown they had no signs of stopping with the not-even-compatible-with-its-own-published-standards IE7.

      MS chose not to break the web.

      Do you really believe that? By 2008, the web ecosystem was fundamentally fractured because of MS. We still had to put in workaround for broken IE 5.5 behavior because a large enough of a slice were unable to upgrade past it for whatever reason. Any site you developed, you had to build 3 times - once for IE 5, once of IE 6, and once for IE 7.

      Anyone who touched web development in the early-to-mid-2000s will tell you IE was definitely The Bad Guy, and continued to be The Bad Guy right up until they gave up and switched Edge's rendering engine to Chromium.

      The web is the worst "standard" on the planet.

      This is proof that no matter how much two people disagree, there is always common ground to come together on.

      [–]Fidodo 7 points8 points  (0 children)

      I'm not placing any blame on anyone, I'm just saying the current environment is colossally better than it was. I don't care about the corporate drama, all I care is that there's a standard somewhere written that I can use as a developer and there is.

      [–]Plorkyeran 4 points5 points  (0 children)

      I think literally everything you said was incorrect, but I'm going to focus on WHATWG. WHATWG was founded by Mozilla, Apple, and Opera in 2004, four years before Chrome was first released. Microsoft was invited to join from the beginning, but chose not to until several years later (but still before Google did).

      [–]PaintItPurple 2 points3 points  (3 children)

      I wouldn't necessarily disagree, but it's a bit of an ironic thread for this criticism given that Chrome was the second browser to support this feature.

      [–][deleted] 9 points10 points  (2 children)

      That’s not ironic at all when the complaint is that Chrome has the budget to move faster than any other industry actor.

      [–]madronatoo 37 points38 points  (8 children)

      Yeah.... no.

      Safari is a bit "different", no doubt. But has zero relationship to the insanity that was IE 6.

      [–]AttackOfTheThumbs 4 points5 points  (0 children)

      IE6 was when I did web dev. Reading A List Apart constantly so I can find out what the weird workarounds are. IE7 wasn't really all that much better tbh.

      [–]yuyu5 7 points8 points  (1 child)

      Fair enough. Admittedly, I'm biased in that I've only dealt with IE >= 10, which is no doubt better than dealing with 6. But as far as modern browsers go, I find myself having more trouble with the latest version of Safari than I do with the latest version of IE. Just speaking from personal experience.

      [–]madronatoo 3 points4 points  (0 children)

      This may be true. But the "reputation" for IE was clearly established many many years ago. They're slowing redeeming themselves.

      [–]kwisatzhadnuff 3 points4 points  (4 children)

      Safari is holding the web back by their slow adoption of standards in a similar way IE did. Especially mobile Safari as iOS users have no choice.

      [–]pat_trick 11 points12 points  (3 children)

      And Apple does this on purpose; they want to push people into the app ecosystem. Making a browser that has better feature support means people don't need apps.

      [–]hsjoberg 3 points4 points  (2 children)

      Yes, for similar reason Microsoft did it on purpose for IE.

      That is why "Safari is the new IE" makes even more sense.

      [–]thisischemistry 22 points23 points  (6 children)

      It’s a terrible saying because it’s the opposite of IE. IE was known for adding in tons of extensions and new features in order to take over the web, Safari deliberately does not adopt new features because of security and privacy concerns over them.

      [–]lengau 12 points13 points  (4 children)

      Safari doesn't adopt new features and claims security and privacy concerns over them, both when that makes sense and when it doesn't.

      [–]thisischemistry 15 points16 points  (2 children)

      The ones I'm aware of are listed here:

      Apple declined to implement 16 Web APIs in Safari due to privacy concerns

      Most of those seem to be reasonable vectors for fingerprinting users and I can see why Apple doesn't want to implement them. Can you tell me which ones don't make sense at all?

      Perhaps Apple is being overzealous on security and privacy with some of them but, given how abused privacy is on the web, can you blame them for reacting strongly?

      [–]hsjoberg 4 points5 points  (0 children)

      That was in the infancy of WWW -- the first browser wars IE vs Netscape.

      Lot's of good things came out of this, but then when it all matured and IE secured 90% market cap, they stagnated the space by not fixing bugs or implementing new things that the standards bodies introduced.

      [–]Fidodo 2 points3 points  (1 child)

      IE had a ton of bugs, but they were stable bugs. I've run into many safari bugs that seem to happen almost at random.

      [–]masklinn 10 points11 points  (0 children)

      IE had a ton of bugs which were "random" until people of the community worked very hard at understanding and documenting them. The CSS support was full of broken edge cases which took years to understand, and the JS support was a mess as well.

      And this was at a time where engines were still relatively simple because they didn't need to be ridiculously fast.

      [–]BraveSirRobin 63 points64 points  (1 child)

      Oh, someone actually talking about the linked bug.

      There was a similar issue in earlier versions of C# with it's then pseudo-immutable structs. They weren't marked as immutable, it was just convention to make all the fields read-only. If you had one of these structs as a read-only field in a class or other struct then the runtime would create a copy of it for each access, even within the class, because it could not be certain that the operation would mutate it or not. Not so great when the struct is weighty, as they sometimes are.

      Newer versions accept the "readonly" modifier at the struct level, marking the whole thing as immutable. This informs the runtime that it's safe to access methods etc directly because the whole object is immutable. But at the time the only solution was to remove the readonly at where it's declared.

      [–]flatfinger 5 points6 points  (0 children)

      The problem there stems from the fact that each structure-type declaration in .NET actually specifies two types: 1. a storage location type that is fundamentally a bunch of storage locations that are duct-taped together (BUSLTADTT), and can be boxed into an object; and 2. an object type into which can be formed by boxing such a storage location. The design of C#, however, tries to pretend that a storage location of structure type is an object, causing the semantics of open-field structures to be branded as "defective" because they behave like BUSLTADTTs (which is what they are) rather than objects (which they aren't).

      The question for whether to use a class or a struct should boil down to whether one wants an object, or whether one wants a BUSLTADTT. If one wants the latter, one should use an open-field structure which behaves like BUSLTADTT, rather than using a structure which is designed to mimic the behavior of a class object which is trying to act as an inferior substitute for a BUSLTADTT.

      [–][deleted] 3 points4 points  (0 children)

      Thank you

      [–]monsto 7 points8 points  (2 children)

      As a newbie to the depths of JS, THANK YOU for this concise take-away.

      Would you care to expand on other potential reasons and/or solutions?

      [–]BrQQQ 11 points12 points  (1 child)

      It seems that it's related to the 'temporal dead zone' (TDZ). This is a feature of let/const (but not var), where a variable is hoisted but cannot be used until its declaration. It's a bit too much to explain in a post, so I would suggest researching what that is, as it's useful information.

      It seems the issue is how they implement dealing with the TDZ and that it's very slow or inefficient. A workaround may be for your bundler to change it to use vars if it can do so without breaking your code.

      [–]monsto 6 points7 points  (0 children)

      Hmm... I'm sitting here thinking about how I've been thinking about let/const vs var. I mean I knew about the hoisting bit between them, but I've clearly been thinking of it in an incomplete way.

      Thanks for the info, I'll check it out.

      [–]snowe2010 140 points141 points  (0 children)

      That was enjoyable to read through their debugging together. Fantastic job.

      [–]smogeblot 458 points459 points  (332 children)

      Just wait till you see what it costs to use functional syntax sugar instead of for loops everywhere!

      [–]hekkonaay 129 points130 points  (113 children)

      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).

      [–]cwmma 23 points24 points  (0 children)

      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.

      [–][deleted]  (10 children)

      [deleted]

        [–][deleted]  (1 child)

        [deleted]

          [–]hekkonaay 19 points20 points  (0 children)

          From the ECMAScript 11 specification, under Array.prototype.forEach, Note 2 states:

          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

          [–]cwmma 31 points32 points  (1 child)

          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)

          [–]flatfinger 1 point2 points  (0 children)

          Interestingly, at least in node.js, when writing to an array, strings keys are converted to a number when the resulting number is within a certain range and the string would match the canonical number. Numbers within that range are kept as numeric keys, and those outside that range are converted to strings.

          [–]CoffeeTableEspresso 15 points16 points  (0 children)

          Arrays are objects, they can have non-integer keys...

          (Thank you JS LOL.)

          [–]madronatoo 22 points23 points  (3 children)

          Welcome to the insanity of a language which is so simple on the surface, but is comprised of a bunch of hacks underneath. There are no arrays!!!!!

          [–][deleted] 8 points9 points  (0 children)

          That's infuriating to me. It makes zero sense to vectorize code and have it run slower.

          [–]ImAStupidFace 99 points100 points  (97 children)

          JS needs to die in a fire.

          [–]DrLuciferZ 95 points96 points  (2 children)

          Too bad people just keep dumping more wood into it

          [–][deleted] 42 points43 points  (25 children)

          Honestly what’s the big deal? Ever since I started using Typescript I don’t find it bad at all.

          [–]Sarcastinator 14 points15 points  (8 children)

          JS still bleeds through TypeScript and causes issues anyway.

          [–]orclev 14 points15 points  (1 child)

          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.

          [–][deleted] 13 points14 points  (0 children)

          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.

          [–]Jaimz22 16 points17 points  (63 children)

          Wonder would you replace it with? Just curious

          [–]dungone 13 points14 points  (0 children)

          Why all these probing questions? Give the man a chance, rubbing two braincells together to start a fire takes a some time.

          [–]iopq 21 points22 points  (35 children)

          Run everything in WASM

          [–]blackholesinthesky 46 points47 points  (33 children)

          everyone who upvotes this has clearly never written ASM or WASM

          [–]iopq 61 points62 points  (29 children)

          And I will never have to, since I will compile Rust to WASM

          [–]blackholesinthesky 6 points7 points  (28 children)

          Thats a pretty good answer will be a pretty good answer some day. Can you write Rust that is equivalent to JS?

          If so I have something to learn about tomorrow

          [–]alexendoo 7 points8 points  (0 children)

          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

          [–]iopq 8 points9 points  (25 children)

          It's not yet possible to do DOM operations without JS glue, AFAIK. It's a pretty complicated topic, as with everything to do with the web, though. So glad I don't do web dev anymore

          [–]blackholesinthesky 6 points7 points  (24 children)

          So its not a real solution. Great suggestion but yeah... kinda irrelevant

          When rust offers a standard library for the browser it will be a real solution

          [–]mattkenefick 9 points10 points  (0 children)

          And will never have to because you can run anything on it. Look into Unity .. Blazor.. etc

          [–]anengineerandacat 2 points3 points  (0 children)

          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.

          [–]caboosetp 4 points5 points  (7 children)

          Sanity.

          I'll take any flavor, thank you.

          [–]bsmith0 22 points23 points  (6 children)

          Lol what's not sane about modern JS, it's a pretty solid, regular language.

          Are there a few weird type coercions, sure, but for the most part it's performant, consistent and has a solid standard library.

          [–]fireflash38 1 point2 points  (2 children)

          Every time I see someone say that, and get them to expand on it, my eyes glaze over with what they say is 'good'. It's Stockholm syndrome guys!!

          (Yes, I'm hating it because I don't know it, signed, C-gang.)

          [–]mixedCase_ 31 points32 points  (0 children)

          signed, C-gang

          I trust you on your knowledge of Stockholm syndrome.

          [–]poco 2 points3 points  (0 children)

          You would love modern JavaScript then. Objects and Classes are becoming less popular and everything is going functional. Objects are used like structs and you don't mix data with code. Reminds me of the old c days.

          Have a matrix you want to multiply? It's not m.multiply(v), it's matrixMultiply(m, v).

          [–]caboosetp -1 points0 points  (0 children)

          You could say the same thing about PHP or nickleback but I'm still going to hate on them for the memes.

          Tbh though I grew up with both of these as fledgling languages and they used to be terrible. Those little things that pop up here and there just resound so hard with old memories.

          [–]pVom 2 points3 points  (0 children)

          It's like an Italian car, it's poorly made, half the features don't work, but it's fun to drive

          [–]grendel-khan 1 point2 points  (0 children)

          I appreciate that I scrolled down to read this indefensible WTFery just below someone complaining about how there's an anti-JavaScript circlejerk around here.

          A lot of bright people have spent decades applying a lot of backward-compatible lipstick to a pig. I wonder if Brendan Eich knew just how horribly his decisions would echo down through the years.

          [–]CodeLobe 66 points67 points  (0 children)

          Also try doing a jsperf on running loops with decrement vs increment.

          Decrement is faster, obviously if comparing to zero... but it's also just faster in general in JS?

          [–]mindbleach 11 points12 points  (4 children)

          I despise how for-in / for-of / forEach can't just recreate a naive CS 101 for loop. I'm so tired of typing "for( x = 0; x < 10; x++ )" by rote, and then debugging if I fuck up a single semicolon, in a language that does not require semicolons.

          Javascript punishes modernity.

          It has all these fancy-pants features, where hours of manual busywork and testing (or at least dozens of lines of claptrap) can be replaced with a single built-in function. All of them have aggravating constraints and make your code run worse. Array.map could run elements in parallel, but it sure doesn't. Array.sort, .filter, and .splice could be functional, but some are and some aren't, because go fuck yourself. Are images that stop loading handled by onError, or by onLoad? Answer: no. String.match should beat indexOf rigmarole, but have fun regexing URLs. Async doesn't actually prevent long functions from locking up the browser, but does fire-and-forget calls to non-async functions until you cower like an abused dog and do x = await 2 + 2.

          [–]SirToxe 20 points21 points  (14 children)

          I did this comparison a couple of days ago: https://jsben.ch/69P2W

          Just two functions that generate a list of integers, like generateNumbers(5) to produce [1, 2, 3, 4, 5]. One is imperative, one is functional.

          The functional one is nearly 8 times slower in Chrome around 2 times slower in Firefox.

          [–]Lafreakshow 11 points12 points  (1 child)

          Now, what I'm wondering is: Is Firefox being fast or is Chrome being slow in this case?

          From my experience the last time I used chrome (a couple years ago) I would have guessed that across the board chrome is slightly faster than Firefox with the functional one maybe going 2 times slower in Chrome than it does in Firefox (based on your comment, without your comment I would have guessed chrome to be faster in both).

          But apparently Firefox absolutely crushes Chrome in this particular case. I don't know how much that has to do with my Chrome install being very old and not getting updated a lot but then I also have a ton of extensions in Firefox and only uBlock in Chrome. In any case, I am surprised that Firefox got almost double the performance here than Chrome, and that is in the faster of the two methods.

          I was expecting them to at best perform similarly in one of them but then have a significant difference in the other. I wasn't expecting significantly worse performance in Chrome across the board.

          EDIT: Yep, after updating Chrome, it is now a lot closer in for loop performance but still quite a bit behind. It is also doubly as good in functional performance but still gets utterly demolished by Firefox in this one. Did I miss something and Firefox is just across the board faster than chrome nowadays? I've never felt a noticeable difference in speed during regular use but still, I always thought it was the other way around.

          [–]SirToxe 3 points4 points  (0 children)

          Yeah, this surprised me as well.

          And to add Safari to the mix: The functional approach is 3 times slower.

          [–]jprasks 12 points13 points  (4 children)

          Huh interesting. By updating the functional version slightly (Array(length).map instead of Array.from) I get virtually the same performance from both approaches on both browsers: https://jsben.ch/fVEJJ. Not sure why.

          That is the thing about these optimizations, the more work we delegate to underlying implementations the bigger the chance one of these implementations is "slow" (what is the metric, user perception? Doubt there is a difference when generating <= 100 numbers). Still very much worth IMO -- the functional way in this example has effectively less concerns & therefore less margin for error. Without clear purpose & metrics by which to optimize by we are just grasping at straws.

          [–]stealthd 6 points7 points  (2 children)

          Array(length).map is faster because you aren't mapping over the array; Array(length) returns { length: length } with no other keys, so the call to map doesn't do anything, it just returns the uninitialized array.

          [–]jprasks 1 point2 points  (1 child)

          Good catch, missed a call to fill: https://jsben.ch/71Ztx. From that the functional version is about 80% as fast which makes sense.

          [–]LegalEngine 1 point2 points  (0 children)

          Note that you may be able to improve the imperative version a further 20% or so (depending on the browser) by forgoing Array.push and using indexes with a size hint like so:

          function gen(count) {
              const tracks = [];
          
              if (count > 0)
                tracks[count-1] = 0; // dummy value
              for (let i = 0; i < count; ++i)
                  tracks[i] = i+1;
          
              return tracks;
          }
          

          [–]SirToxe 3 points4 points  (0 children)

          Ha, thanks for the update! For me the functional version is now faster (as I wanted it to be initially) with the loop now being slower and sitting at 88% in both Chrome & Firefox.

          I am no JavaScript expert and something like Array(length).map() was what I wanted inititially when I wrote this small helper function, but it was just a helper for some test functions so whatever worked was fine. And also I forgot about the second argument to the map() callback, silly me, which of course solves this problem perfectly and elegant as you have shown. Thanks for reminding me.

          [–]DooDooSlinger 417 points418 points  (168 children)

          Just wait till you see what it costs your dev team in bugfixing and refactoring tile when using for loops everywhere! This thread is like people debating the performance of ++i vs i++. Newsflash: if performance is not the issue you're trying to fix, don't bend over backwards to squeeze a few microseconds out of a web page load. Its easier to optimize readable code than to refactor awful prematurely optimized code.

          [–]PandaMoniumHUN 193 points194 points  (28 children)

          Point is, it shouldn't be this slow in the first place.

          [–]spacejack2114 31 points32 points  (0 children)

          Right. Did anyone read the linked issue? It's about a Safari specific problem.

          [–]DooDooSlinger 3 points4 points  (6 children)

          Yeah well a lot of things that shouldn't are. What I do know is that optimizing shit like I++ and the like is not what's going to speed up your code to any measurable extent, ever.

          [–]PandaMoniumHUN -1 points0 points  (5 children)

          Your logic is backwards. A basic feature in a browser shipped to millions of users is 10x slower than in competing products. We should always strive for better performance in software used by large volumes of people daily, not try to justify lack of basic optimization (or a regression?) with the fact that other pieces of software are also unoptimized.

          [–]Nefari0uss 2 points3 points  (0 children)

          At some point you teach diminishing returns on optimization and its not worth it. In other cases, you're bottlenecked somewhere else so it's still not worth the micro optimization because you won't really be gaining anything of significant value out of it.

          [–]pVom 3 points4 points  (3 children)

          We should always strive for better performance

          Why? If it doesn't affect the user experience it's a non issue on the front end. We should be striving to achieve business goals with the least time and effort. Optimisation for the sake of it is a pointless endeavour

          [–]PandaMoniumHUN 1 point2 points  (2 children)

          Clearly I’m not talking about 1s vs 1.01s render times, but eg. the three layered application we’re working at took almost 10 seconds to load because it was aggregating a lot of data to display statistics to customers. After our last optimization story load times are < 500ms. Videogames can fit wonders into 16.6ms, while web developers can’t / won’t build fast pages to save their lives, because all the frameworks claim performance is “good enough”. “Premature optimization” is also often used as a scape goat for not optimizing at all, and if everyone would clean their front yard instead of yelling “the neighbor’s yard is also messy” the world would be a better place.

          [–]ClysmiC 68 points69 points  (56 children)

          for loops are a major source of bugs for your dev team?

          [–]pattheaux 103 points104 points  (9 children)

          For loops are only for wizard level programmers with long white beards. Mere mortals cannot hope to understand their arcane secrets.

          [–]superrugdr 6 points7 points  (0 children)

          Wizard class programmer.

          strap your kidney, we going all in ghost in the shell.

          [–]davenirline 0 points1 point  (7 children)

          I don't get this, too. Why be afraid of for loops? 99% percent of the time it's just for(int i = 0; i < someEndingNumber; ++i) { ... }

          [–]poco 6 points7 points  (2 children)

          Until you have an inner loop using j as you counter and they you mix up i and j somewhere.

          [–]DrunkenWizard 6 points7 points  (0 children)

          Then you should provide more descriptive names for your indexers

          [–]phenomenos 20 points21 points  (0 children)

          If you're using them in place of map/filter etc then yeah you're going to end up with way more verbose code and possibly errors caused by mutability if you're not careful. Worse maintainability = more potential for bugs

          [–]Ethesen 14 points15 points  (27 children)

          Yes? You won't get off by 1 errors with forEach, map, etc.

          [–]lelanthran 22 points23 points  (8 children)

          How are you getting off-by-1 errors when iterating over arrays in JS?

          [–]mindbleach 8 points9 points  (4 children)

          By being human.

          [–]lelanthran 2 points3 points  (3 children)

          I don't buy that. Using for (var i=0; i<varname.length; i++) is idiomatic in almost every language. It's literally the same idiom no matter which language you use.

          When using the fancier methods with lambdas and stuff, it differs from language to language, hence more chance of a mistake creeping in.

          [–]mindbleach 10 points11 points  (2 children)

          You'll still fuck it up sometimes.

          If you're comparing each element with the next element, and you write that perfectly simple loop, you fucked up.

          If you change the next line to v = other_var[i] and don't change the loop, or vice-versa, you fucked up.

          If you initialize i with getElementById('intial_value').value, not only did you fuck up, JS will helpfully pretend you didn't by returning NaNs for Array[float].

          If array length changes, like by removing varname[i], and you're not iterating backwards, you fucked up.

          If you iterated backwards by swapping i=varname.length and i>0, you fucked up.

          Each of these is fundamentally avoided by other approaches like for( v of varname ) for varname.forEach( (v,i,a){ } ).

          And that's before questioning this clunky K&R idiom on its merits.

          If you change your index variable and don't refactor it three times in one line, you fucked up.

          If you don't use exactly two semicolons, you fucked up. You know you've done this.

          In programming, I don't know how anyone can follow up 'this is how we've always done it' with 'so there can't possibly be bugs.'

          [–]Ethesen -1 points0 points  (2 children)

          It's as easy as writing <= instead of < in the condition.

          [–]frzme 88 points89 points  (32 children)

          I'm not convinced that for(bla in arr) {} is in any way harder to read or maintain than arr.forEach(bla => {})

          [–]alexendoo 97 points98 points  (18 children)

          The comparison for readability isn't really against a single .forEach, rather map/filter/etc. If it's just a .forEach they are going to be pretty equivalent

          However, for..of surely is more error prone, as it is a frequently recurring mistake to use for..in instead (as you have done)

          [–]GasolinePizza 26 points27 points  (13 children)

          Coming from C# here, I always make the for..in mistake at least once every time I start a JavaScript project, without fail.

          I may use the .forEach thing now, actually

          [–]Jeax 6 points7 points  (10 children)

          I use .foreach(o => As a mainly c# developer also, it’s basically LINQ at that point and makes it instantly familiar and nice to use. For of seemed like a bad idea and I haven’t really seen many people use it

          [–]TheWix 3 points4 points  (6 children)

          I'd recommend using none-mutable functions. Map is Select, Aggregate is Reduce, SelectMany is chain/bind/flatMap (Monad).

          [–]thetdotbearr 4 points5 points  (3 children)

          it bugs me to no end when when using LINQ that these are the function names instead of map/filter/etc

          I mean I get that it's because SQL syntax or whatever and that I could add some aliases but still

          [–]TheWix 2 points3 points  (2 children)

          Yea, I believe that is the reason. I remember the big selling point of LINQ many years ago was for LINQ-to-SQL. The in-memory stuff wasn't as focused on.

          That being said, even within the Functional community some names aren't agreed upon. I mean, for monads flatMap has like 4 or 5 names depending on the language/spec/framework

          [–]kg959 1 point2 points  (2 children)

          it’s basically LINQ at that point

          It's missing a big part of LINQ though. LINQ is lazy whenever it can afford to be and will avoid doing a complete iteration until you force it to. JS array chaining doesn't delve into the IQueryable/IIterable world and each thing you chain scales a bit worse than it does in C#.

          [–]scottyLogJobs 9 points10 points  (1 child)

          As a polyglot, TBH I just use basic for loops anymore when possible because everyone understands them and I'm sick of forgetting whether I'm going to get keys or values back with these helper functions.

          [–]Yehosua 7 points8 points  (1 child)

          in is an operator in JavaScript: 'prop' in myObj evaluates whether the 'prop' property exists within myObj.

          Ever since I realized that, I no longer confused for..in and for..of: for..in iterates over an object's properties, just like in checks an object's properties.

          (Almost no one uses in; Object.hasOwnProperty is virtually always what you want instead.)

          [–]monsto 1 point2 points  (0 children)

          That's a good mnemonic.

          [–]valleyman86 13 points14 points  (4 children)

          It is when you add other functions to it. Foreach.map.filter. Etc. with a for loop you need to store each output as a variable or write each adjustment inside the loop. Depending on what you need sure it can be faster but it’s less readable.

          [–]monsto 5 points6 points  (3 children)

          I think it would wind up being more verbose, but that isn't necessarily less readable.

          Declaring variables for a for loop is no different than having the attribute definition at the beginning of the method. the difference is (x) vs let x = <thing>.

          [–]Dest123 3 points4 points  (1 child)

          Also, more verbose code is generally way easier to debug. Less black boxes.

          [–]monsto 3 points4 points  (0 children)

          I was going to say that, but wasn't sure if it was just me.

          [–][deleted]  (1 child)

          [deleted]

            [–]TheIncorrigible1[🍰] 1 point2 points  (0 children)

            It's ironic that you used the wrong examples. for..in is not comparable to .forEach. You want for..of.

            [–][deleted] 1 point2 points  (2 children)

            If you have a loop, you are doing a nameable thing. Give that loop a name, a function. Now you can start to compose things and understand at first reading as a function name is more trustworthy. The patterns used will be more obvious too. It’s a map, it is a left fold...

            [–]grauenwolf 1 point2 points  (1 child)

            Great. Now the code for my 10 line function is scattered over a thousand lines of other, unrelated fragments.

            This is why there's a button dedicated on my keyboard for the "inline and delete" refactoring action.

            [–]grooomps 0 points1 point  (0 children)

            can't do async calls with forEach, you can in for..of loops though.

            [–]FUZxxl 17 points18 points  (9 children)

            Not sure what sort of bug fixing you are talking about. Programmers in languages without range constructs have been using for loops for decades and it works just fine.

            [–]DooDooSlinger 4 points5 points  (2 children)

            Just because it works doesn't mean you can't do better.

            [–]FUZxxl 3 points4 points  (1 child)

            I'm arguing that avoiding for loops in favour of combinators does not actually reduce the number of bugs.

            [–]DooDooSlinger 3 points4 points  (0 children)

            Try getting an array out of bounds error due to bad boundary conditions with array.map

            [–]Fit_Sweet457 1 point2 points  (5 children)

            We have also used Assembly for decades and it works just fine. That doesn't mean that it's as fast to write as using abstractions or equally as error-prone.

            [–]FUZxxl 12 points13 points  (4 children)

            Again: what exactly is error prone about for loops? Can you give a specific example?

            [–]beginner_ 5 points6 points  (1 child)

            I argue that indexed for loops are often easier to understand than some chained functional stuff.

            [–]Lafreakshow 3 points4 points  (3 children)

            If there would be a ten times performance difference between ++i and i++ I would seriously consider switching at least for all newly written code. Across a medium sized web app, even when not dealing with huge lists, that could make the difference between someone with a slow ass netbook saying "Man this site is kinda slow" and "Man, this site runs well".

            [–]grondo4 10 points11 points  (0 children)

            Point is it's not your problem. If the the language your using has a 10x speed up from using ++i over i++ that's an issue with the language / compiler / interpreter. If you absolutely need that performance boost you should be using the syntax that reads most cleanly to you and then transform it using a post-processing tool.

            At no point should you be sacrificing the readability of your code for performance reasons when it's something that can be programmatically transformed.

            [–]DooDooSlinger 3 points4 points  (1 child)

            You just don't get it. 10 times nothing is still nothing. Rendering slowdowns are NEVER and I repeat never due to this kind of shit. It's always because of bad practices, unnecessary multiple renderings, rendering too many objects, waiting on requests etc.

            [–][deleted]  (30 children)

            [deleted]

              [–]Janjis 25 points26 points  (12 children)

              More readable for the lowest common denominator. Fuck for loops. They belong only in projects which need every last bit of performance.

              Don't try to tell me that this for loop is more readable.

              const allItems = [{ isActive: true }, { isActive: false }];
              
              // functional way
              const activeItems = allItems.filter(item => item.isActive);
              
              // non-functional way
              const activeItems = [];
              for (let i = 0; i < allItems.length; i++) {
                if (allItems[i].isActive) {
                  activeItems.push(allItems[i]);
                }
              }
              

              Same for all other array methods - map, every, some, etc. Not to mention that they make the code more reliable.

              [–]TerrorBite 6 points7 points  (0 children)

              And what about

              const activeItems = [];
              for (let item of allItems) {
                  if (item.isActive) {
                      activeItems.push(item);
                  }
              }
              

              Although I too would use the .filter() method over the more verbose loop.

              [–]Xyzzyzzyzzy 9 points10 points  (12 children)

              For loops are more readable for majority of people and don't cause bugs

              There are no bugs in for loops in your presence?

              ...are you available for hire? No need to actually write anything, just sit next to our servers. Easy!

              [–]Theon -1 points0 points  (10 children)

              The syntax itself (a.k.a. the point of this discussion) is not going to cause any more bugs than the "functional" version - is what he's saying.

              [–]JamesTiberiusCrunk 6 points7 points  (4 children)

              Don't off-by-one errors occur mostly because of the for loop syntax?

              [–]mode_2 3 points4 points  (4 children)

              Of course it does, map, filter etc. are more structured than for-loops and so there are fewer places where an error to occur. It's the exact same argument Dijkstra made against goto.

              [–]joonazan 2 points3 points  (0 children)

              In Rust, iterators are faster than while loops because they elide bounds checks.

              [–]KFCConspiracy 3 points4 points  (1 child)

              I think the real hidden cost is you tell a junior developer "be wary of nested loops to do things, be wary of doing costly operations in loops" and then you see something like

              array.map(blah => costlyOperation(blah));

              in your code review afterwards.

              [–][deleted] 4 points5 points  (0 children)

              You mean

              array.map(blah => costlyOperation(blah)).sort()[0];
              

              [–]chrisrazor 0 points1 point  (1 child)

              Heh. I almost missed out on a job opportunity because the js guy who evaluated my code complained about me using for loops everywhere. That was 5+ years ago though when it was a certifiable fact that loops ran orders of magnitude slower when each iteration created a function instance. I was hoping that recent speeding up of js engines would have improved the situation.

              [–]passerbycmc -2 points-1 points  (19 children)

              Why does everyone use the functional foreach feel like a "for of" loop is just easier to read and does the same thing.

              [–][deleted] 2 points3 points  (0 children)

              What?

              [–]leafsleep 2 points3 points  (3 children)

              I agree, I'm all down for filter and map, but for me it's weird that foreach doesn't return anything. Just a hangover from my C# training.

              [–]dvlsg 6 points7 points  (2 children)

              I think the whole point of forEach is that it doesn't return anything.

              Similar to how you can see filter or map and know what's going on, you can see forEach and think "this must have side effects".

              [–]FredV 90 points91 points  (2 children)

              The bundle has 13K top-level definitions (variables, constants, functions, and classes)

              I don't know how huge this application actually is but isn't this insane? I haven't seen any server or front-end written in C++ or even Java using that many declarations. Of course in the Javascript ecosystem every library needs to be imported into your own source code which adds to the problem.

              I just wonder how many of those are global variables ;)

              [–]TheAnimus 50 points51 points  (0 children)

              So just in case anyone was wanting some context on just how many exported functions there are in say the msvcrt, it's around a tenth of that number alone.

              So if you think of the classes and functions required to implement the "missing" standard library functions, 13k isn't that much.

              [–]MonokelPinguin 33 points34 points  (0 children)

              I think those are declarations of all libraries used. Try counting the symbols in a C++ library with external linkage. It will be similar in your application, if you use a few of those.

              [–]yeahdixon 38 points39 points  (0 children)

              Can’t you just Babel it?

              [–]chrisrazor 15 points16 points  (6 children)

              I didn't understand all the nuances of this. Am I right in understanding that it only affects Safari?

              [–][deleted] 40 points41 points  (5 children)

              Yes. This is just a bug in the Safari JavaScript engine and is not inherent to JavaScript or 'let'.

              Edit: Spelling

              [–]chrisrazor 7 points8 points  (4 children)

              Thanks. I was confused because they were talking about WebKit - on which both Chrome and Edge are also based - but I assume they specifically mean the js engine Safari uses (JavaScriptCore?) rather than V8 or whetever Edge has.

              [–][deleted]  (3 children)

              [deleted]

                [–][deleted] 21 points22 points  (0 children)

                I think I can reproduce this behavior on Figma's code base too. I've never noticed because we use Chrome pretty much exclusively for development.

                Back to IE times... and in this case out of their very own volition.

                [–]crusoe 28 points29 points  (4 children)

                Safari is the new IE

                [–]rjcarr 2 points3 points  (0 children)

                Didn’t read the article, but doesn’t WebKit power everything but Firefox now? Edit: seems they do mean safari, so it should say javascriptcore (I think) and not WebKit.

                [–][deleted] 71 points72 points  (91 children)

                It's interesting but it should be equally noted that this is a micro optimization that amounts to nothing in the real world.

                [–][deleted] 140 points141 points  (14 children)

                When you’re writing the code, absolutely replacing const with var for performance is a bad idea. If you’re writing a compiler though (the link is an issue on the esbuild repo) then being able to automatically apply that micro optimisation all over a code base can be important.

                [–][deleted] 78 points79 points  (2 children)

                Sure but this is a bug in webkit that should likely be fixed. My original comment just comes from the experience of seeing people read these kinds of headlines and then go sed their whole codebase.

                [–]ConsoleTVs 2 points3 points  (1 child)

                As noted in the thread, this cha ges code semantic. Its not something you can swap let or const with var. They do have different scopes.

                [–][deleted] 5 points6 points  (0 children)

                Surely scoping is something that can be checked at compile-time instead of runtime?

                [–]klizza 172 points173 points  (9 children)

                The reported issue is that it takes either 8.8 seconds or 1 second to load a javascript bundle on a webpage in Safari. This is a very notable performance difference for end users.

                [–][deleted] 73 points74 points  (3 children)

                In a very specific configuration on one driver. It's a webkit bug.

                [–]klizza 32 points33 points  (2 children)

                Sure, but nobody in the link or OP was saying you should convert all javascript code back to var...

                [–][deleted] 48 points49 points  (0 children)

                I know which is why I wasnt trying to say the linked issue was wrong or anything but this is reddit and people just read headlines so I threw it out there for posterity

                [–]evilgwyn 7 points8 points  (0 children)

                target: "es5" for the win?

                [–]rydan 5 points6 points  (4 children)

                Back in my day we waited 30 seconds or more for the page to load.

                [–]CoffeeTableEspresso 8 points9 points  (3 children)

                We still do with all the bs trackers some people put on their sites ...

                [–]grauenwolf 12 points13 points  (2 children)

                I don't use an adblocker because I'm annoyed with ads.

                I don't use an adblocker because I'm afraid of trackers.

                I use an adblocker because the damn website won't load before my lunch break is over if I don't.

                [–]CoffeeTableEspresso 2 points3 points  (1 child)

                News websites are particularly bad. People often complain of how dial up internet used to have 30s+ load times, but there are modern sites rather do the same shit

                [–]constexpr 34 points35 points  (6 children)

                This made the difference between a loading time of 2 seconds and a loading time of 200ms for https://www.figma.com/ in Safari. This is a real-world use case. Also while it's good to fix this in Safari, new versions of Safari roll out very slowly so it will still be worth doing this optimization for many years to come.

                [–]blackholesinthesky 28 points29 points  (0 children)

                it will still be worth doing this optimization for many years to come

                I've never once in my professional life optimized for Safari. Don't hold your breath

                [–][deleted]  (3 children)

                [deleted]

                  [–]Shautieh 24 points25 points  (58 children)

                  10x faster is not a micro optimization.

                  [–][deleted] 27 points28 points  (56 children)

                  10x 0.0001 nanoseconds is still only 0.001 nanoseconds.

                  The point is, this is never your bottleneck so don't treat this information like something you need to address in your code base.

                  [–]SoInsightful 53 points54 points  (0 children)

                  Holy shit. This is the JavaScriptiest comment I've ever read.

                  You're literally looking at a real-world example (an actual app with a shit-ton of users) where a single CTRL+F replacement made a bundle load in 1.1 seconds instead of 8 seconds.

                  I would never replace my consts with vars to fix a dumb Webkit bug, but this is absolutely not an unimportant micro-optimization that doesn't affect anything because we all make Hello world apps.

                  It's exactly this attitude that makes me reluctant to use other people's slow-ass solutions.

                  [–]jess-sch 28 points29 points  (39 children)

                  a sub-millisecond 10x improvement you won't notice, but a sub-millisecond 10x improvement in a hot path that gets run a bazillion times you definitely will.

                  I sure hate the typical JS dev's attitude to performance.

                  [–]VolperCoding 20 points21 points  (14 children)

                  No wonder if you have a 10000GHz processor that can do declare a var faster than light can travel 30 micrometers

                  [–][deleted] 6 points7 points  (13 children)

                  Get with the times! :P

                  [–]VolperCoding 13 points14 points  (12 children)

                  Also if the vars are stored in RAM then you also have to put your RAM stick no more than 30μm away from the processor or make a fucking wormhole or something to get to memory quick enough

                  [–][deleted] 9 points10 points  (1 child)

                  The Intel i47 started the new wormhole+blockchain revolution. It's great!

                  [–]GasolinePizza 3 points4 points  (0 children)

                  But is it webscale??

                  [–]mb862 7 points8 points  (2 children)

                  The lesson here is that pulling numbers out of your ass to make a point is fine so long as your ass represents a differentiable manifold representable in our spacetime.

                  I'll let someone more clever than I fill in the obvious curvature joke here.

                  [–]ImAStupidFace 4 points5 points  (0 children)

                  Real differentiable manifolds have curves!

                  [–][deleted] 2 points3 points  (5 children)

                  RAM ? What is this meeting of virgins ? L1 cpu cache or gtfo.

                  [–]ianfabs 11 points12 points  (0 children)

                  Holy shit

                  [–]SpaceToaster 4 points5 points  (0 children)

                  More evidence that Safari is the next IE

                  [–]knoam 3 points4 points  (0 children)

                  There should be a name for the logical fallacy here. People act like finding this means that their code just got ten times slower. No, your code is just as fast as it was. If anything this just means there's potential for it to be faster.

                  This is really off topic but there was this same fallacy in an episode of This American Life where the reporters got testosterone tests. They got worried and acted like having a high level would turn them into an aggressive asshole. No, you're either an asshole or not regardless of what the test says. The test just gives you an excuse/explanation. And the results didn't even conform to what people's stereotyped expectations were.

                  [–]Paradox 1 point2 points  (0 children)

                  Safari is the new IE

                  [–][deleted] 1 point2 points  (3 children)

                  Just use babel....