13 ms·
Using const/let instead of var can make JavaScript code run 10× slower in Webkit
- russellbeattie 6y agoWhile we're all here.. Fellow JS developers, please, for the love of all that's good, stop using const for everything. If you want a strongly typed language with immutable variables, just go use another language already. Just use let unless you actually need a const. (I don't care if I get a million down votes, I really don't. You're all misusing const and you know it. It's a shitty hack turned into a fad by someone who didn't understand the language.)
- jpcooper 6y agoCould you explain why? I don’t really know JS.
- defen 6y agoconst prevents rebinding a name but doesn't affect the variable's mutability. const foo = {}; foo = 42; //not allowed foo.bar = 'baz'; //this is fine
- Arelius 6y agoSure, this describes the problems with JS's const, but doesn't really describe why it shouldn't be used?
- lhorie 6y agoMost JS people consider it perfectly fine to use it. It's a just a tool. A minority wants to make a storm in a cup of water because they read this[1] [1] https://jamie.build/const https://jamie.build/const
- edf13 6y agoHe’s an angry chap isn’t he?
- lhorie 6y agoIf you ever feel compelled to google him, you may want to grab some popcorn first :)
- giantDinosaur 6y agoHmm, some good points there. I think I'll avoid const now.
- yashap 6y agoI didn’t think any of these points were very strong. const x = {immutableValue} That tells me the thing is fully immutable. Whether it’s a global variable or not, that’s still nice to know when reading the code! Likewise: let x = {immutableValue} const x = {mutableValue} These tell me different things. The first tells me I should look out for re-assignment, the second that I should look out for mutation of the value. In contrast, this: let x = {mutableValue} Clearly has the most cognitive load. Anything could happen with this. If it’s a bigger, more complex function/whatever, “what happens to x, it could be anything” is just one more thing to fit in my head as I try to figure out what this code does. Enough little uncertainties like this, and I have to give up understanding by reading entirely, and resort to a debugger. Had the author limited the scope of what was possible, it’d be a bit easier to understand, with really no drawbacks. It’s not the end of the world, but “small, simple, easy thing I can do to make the code easier to understand for future readers” ... why not do that?
- giantDinosaur 6y agoReally, I just have a somewhat FP bias, and I'd really enjoy it if const was actually immutable, since it'd be a nice concise way of expressing that. It's just not as useful as you'd think given how often it seems to be used (by contrast I almost never see anyone actually making anything immutable in JS).
- Lio 6y agoYes but why do you consider that bad? It’s the same behaviour in many other languages. Why would rebinding variables ever be a good thing?
- mmis1000 6y agoIsn't that literally the same as java or a const pointer in c/c++? const fixed the pointer but don't prevent user change the value in the storage it point to.
- jpcooper 6y agoThere are two possibilities in C++. I am not sure what the situation is in Java. It is possible to define a pointer to an object whose contents may not be changed. This is done with ‘const * type object’. If you want a pointer whose value must not change, but do not care about the contents of the pointed to object, you would write ‘type * const object’.
- eMSF 6y agoYou ought to have mentioned that pointers of the latter type are quite rare in C. A mention of const pointer practically always means a pointer-to-const: a pointer you can't write through. Often you can still "re-bind" such pointer to another object – in both ways the polar opposite of JS const. Of course, in C++ there are const references as well, and in this case const also means you can't modify the referenced object (in any case in C++ you can never re-bind a reference).
- jansan 6y agoIt's the same in Java and never caused any problems. You just have to understand what const does. What the OP is looking for is Object.seal() and Object.freeze(). This is a pointless discussion.
- dtf 6y agoThere's a record & tuple proposal that would address this use case (currently served by tools such as Immer): const foo = #{}; foo = 42; //not allowed foo.bar = 'baz'; //not allowed https://2ality.com/2020/05/records-tuples-first-look.html https://2ality.com/2020/05/records-tuples-first-look.html
- afiori 6y agoconst is useful when multiple part of a program might refer to the same object/value, blocking rebindings is what you need to keep all the references in sync.
- andrethegiant 6y agoYour efforts are better spent contributing upstream: https://github.com/eslint/eslint/blob/master/docs/rules/prefer-const.md https://github.com/eslint/eslint/blob/master/docs/rules/pref...
- lhorie 6y agoImmutable references, mutable data structures. You're welcome to go use another language that doesn't have a formal spec, if you're so inclined to disagree with what the spec for this one says.
- yashap 6y agoPeople (more or less) can’t use another language if they’re targeting the browser. Also, in general, using the most limited constructs that fit your use case makes a tonne of sense for code cleanliness, in any language. For example, in a language supporting private/protected/public properties and methods, you should always default to private, as that’s most limited and easiest to reason about. Then make it more public as necessary. Same goes for const vs. let - const is more limited, it’s a better default choice, only use let if you actually need to re-assign it. Using const means there’s one less thing for readers of the code to worry about, it’s a variable that CAN’T be reassigned, the same way you don’t have to worry about a private method being called externally. This is, essentially, the “principle of least power.”
- annoyingconst92 6y agoThe problem is that, when prototyping and iterating a design I often don't know in advance what should be private or const and what shouldn't be. And when interactively experimenting in the DevTools console I often want to redefine `const shadowMapSize=1024` to `shadowMapSize=2048` but const breaks interactive console redefinition. I have to save the js file to disk and edit shadowMapSize there, then reload the code. This is the workflow for a static language like C++, not a dynamic language like Lisp or JavaScript.
- yashap 6y agoThis seems like a realllly weak reason to write less maintainable code (harder than it needs to be for future readers to reason about). For workflows like this, you can easily use let/var while prototyping. Then once you’re done and are cleaning up the code, writing tests, etc., switch to const if the reference is never re-assigned. It’s the same in every language - when prototyping, go wild with god functions, mutable state, public everything, whatever, but clean it up and make it readable/maintained before it gets merged to master. Also, if you’re talking about leaving mutability like this in the code long term, this really only applies to GLOBAL mutable state, and global mutable state is a terrible thing for code maintainability in any language. If it’s not global, you can’t fiddle with it later in the console anyways. Littering your program with global mutable state just because “someday, someone may want to fiddle with this in the console, and this makes that slightly easier”, that’s just not a reasonable argument.
- wiredearp 6y agoThe keyword instructs the human to immediately unassign any mental overhead reserved for tracking changes to the value while `let` or `var` indicates that further digestion is required to determine potential. I see some value in that. Stop using `const` for declaring named functions, though.
- jonny_wonny 6y agoYou should focus less on constraining yourself to arbitrary ideologies and focus more on writing good code that’s easier to maintain and understand.
- Dylan16807 6y agoCould you explain what you think an "actual need" for const looks like?
- russellbeattie 6y agoEXACTLY.
- Dylan16807 6y agoWell, the thing is, if your answer is "never" then I'm less inclined to agree with you. I think "don't use it ever" is a much weaker argument than "here's where you should and shouldn't use it".
- MaxBarraclough 6y agoWhy? What's the problem? const improves readability, and the ability to reason about code. It lessens the need to exhaustively scan the code looking for other assignments to the variable.
- deleted 6y ago[deleted]
- jansan 6y agoYou seem to be confusing const iwth the functionality of Object.seal() and Object.freeze(). While const only makes the reference immutable, with Object.freeze() you can actually make the data immutable. Once you got this, there is not problem with using const all the time.
- zaksoup 6y agoI don't mean this as a call-out but I thought this comment from the maintainer was really interesting: > 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. I'm more and more concerned that the monoculture of chrome for developer tooling is making the web a worse place...
- saagarjha 6y agoLooks like the JavaScriptCore people are on it :) As an aside, I’ve been seeing a number of articles show up that basically go like “Chrome implements x efficiently but semantically equivalent y poorly, you should use always use x”. I really hope we don’t end up with JavaScript code being written to be optimized well on one particular implementation of a JavaScript engine…it’s interesting to see this in this area specifically because other VMs (e.g. Java) have knobs you can turn yourself but with JavaScript your code runs without much input on your side, so methods to influence the VM are much more specific…
- yladiz 6y agoThis has been happening for a long time, sadly. Years ago Chrome had poor optimization around try-catch and this meant it couldn't be used in the application I was working on, as we pretty much targeted only Chrome. I guess by the time async-await got into the engine try-catch was optimized enough and now this doesn't seem to be an issue. Hopefully this changes, even slowly, but it'll probably take a while since Chrome's got so much share.
- smt88 6y agoJS is so ultra-optimized by modern browsers that we're going to run into cases like this. It's inevitable. Hopefully they're always treated like bugs and not something we need to work around.
- olliej 6y agoThe JSC team (and I suspect V8 and SM) always treat performance cliffs caused by normal/sensible code patterns as a bug. The problem is that when implementing improvements it's easy to forget every mostly-equivalent thing and so miss obvious things (often the entire fix in the end is "if (canDoItFast) doTheExistingFastThing()"
- whoisburbansky 6y agoReading the issue comments, I still don't quite get why this is the case. Anybody with a better handle on PL theory and/or JS internals care to ELI5?
- saagarjha 6y agoPerhaps the linked, seemingly related WebKit bug may be interesting? https://bugs.webkit.org/show_bug.cgi?id=199866 https://bugs.webkit.org/show_bug.cgi?id=199866
- whoisburbansky 6y agoTLDR seems like var isn't scope-bound, but let is, and actually calculating the scope for let statements is what's causing the slowdown?
- morelisp 6y agoDamn you Olin Shivers!
- winstonewert 6y agowild speculation: let/const is implemented by creating a new scope with every let or const declaration. Looking up variable then ends up tracing linearly through all of these scopes. Bundlers end up creating a huge number of let/const and thereby scopes. Then every variable reference ends up scanning through this huge linear list of scopes to find the variable it refers to.
- brundolf 6y agoWhy would there be a whole new scope for every declaration, instead of just each block? To prevent access within the block but before the declaration?
- nightcracker 6y ago
- preommr 6y agoTrying to optimize for browsers is an abyss. There's a handful of really unintuitive behavior because js is slow but modern browsers have put in herculean efforts to optimize the engines rather than tackle the language. It's kind of pointless to even try and optimize for things like this because there's a very good chance that it can change in the news few weeks/months/years.
- colordrops 6y agoThe Chrome team's direct advice is to not optimize this way, and rather to write as idiomatically as possible, because it is likely that they are aware of the issue (e.g. it's a new language feature and they are collecting usage data before doing optimizations), and it will improve with time.
- satori99 6y agoI can't even remember the last time I used var when writing JavaScript. Scoped const/let are just easier to reason with. This seems bad.
- brundolf 6y agoIt's incredible that such a common case can be affected so dramatically and yet nobody noticed it until now. Really hammers home the problem of having a browser monoculture.
- coddle-hark 6y agoDoes it? It’s not like people are constantly running comparison benchmarks of var/const/let between browsers.
- brundolf 6y agoIf every large JS app on Safari is 10x slower than it is on Chrome, and the user base of Safari has been dealing with that since who-knows-when, and no developer noticed because they're all testing on Chrome, that's a problem.
- microcolonel 6y agoIt's Apple's problem to solve though, I mean, outside of developers writing code that's more efficient to begin with so it doesn't really matter when it's 10x slower, but they should probably be doing that anyway.
- mattnewton 6y agoOr they are all compiling their JavaScript to legacy JavaScript specs for WebKit.
- asdfasgasdgasdg 6y agoYeah. A problem Safari's developers should address. Apple is not a wee baby company that lacks the resources to keep up with Chrome in any dimension.
- oeoeoeioe 6y agoMisleading title? It seems far more likely this is specifically related to the js engine than the renderer.
- nemothekid 6y agoAre there any browsers using Webkit that aren't using JavascriptCore? Now that Chrome uses Blink, I'm pretty sure anyone using v8 is probably using Blink as well?
- why_only_15 6y agoAs I recall some samsung browsers and the like use it? Webkit is removing support for non-JSC engines, and I remember the samsung people as well as some others being upset about this.
- om2 6y agoWe removed support for non-JSC engines immediately after the Blink form.
- gsnedders 6y agoAnd Blink likewise removed support for non-V8. All the major browser engines are relatively tightly coupled to the JS engine at this point (not impossibly so, but there's definitely a tighter coupling than there was historically).
- om2 6y agoIt would be easier to swap JS engines than other browser engine components probably, but yeah, not trivial. The patches to make WebKit support choice of JSC or V8 were janky in the first place and constrained what we could do.
- Arelius 6y agoI agree, while it may not be entirely technically accurate to say WebKit, I do think it's specific enough, and also a more broadly known technology than Javascript Core
- cosmosgenius 6y agoNot sure if its still valid, but i remember doing a performance testing for "hello world"*10mil in nodejs and golang around 4-5 years back. What i noticed was "var" and "const" gave comparable results to golang, but "let" was around 100x slower for no reason. It was just a single variable declaration with "print" statement called multiple times.
- judge2020 6y agoIf it was written like while true { let hello = "world"; } The scope would keep getting freed then re-allocated, which will be slower than simply continuously setting an existing variable's memory location over and over again.
- ihuman 6y agoIf that was the reason, then shouldn't "const" be as slow as "let"?
- kjksf 6y agoIt should be valid to move `const` outside of the loop, since by definition it cannot be changed. `let` can be changed so cannot be optimized out this way (at least not without doing more complex analysis and proving that the variable is not being changed).
- charliesome 6y agoWhile the creation and destruction of a scope every loop iteration is the correct mental model for what this code does, there's no reason that implementations must actually perform any allocations - especially for an example like this where it is trivially determinable that no bindings escape the immediate scope.
- chrismorgan 6y agoThat would apply to a pure interpreter, but all JS runtimes will do at least some optimisations, even on their baseline profile.
- daurnimator 6y agoI ran into this when working on fengari: debugging with V8 people, using `const`/`let` pushes the variable onto a stack of things to pop at end of scope; while `var` does not. This was accepted as intentional and that if I really cared about speed I would use `var`...
- afiori 6y agoI would expect that a let at a function scope should be equivalent to a var inside a block
- niq999 6y agoI still have a silly dream that one day Javascript will split the numeric type into 32-bit floats and ints by default, like Ruby does. I wonder how much of the existing ecosystem that would break.
- spleen 6y agoThey are actually 64-bit floats (doubles) and unlimited integers in Ruby.
- mmis1000 6y agoAnd now JS also have unlimited integers
- ficklepickle 6y agoWe've got various number types in array form: {u}int{8,16,32}, floats too. I feel like that is about the best we can do without harming backwards compatibility. They are there when needed, but we are stuck with the ambiguous "number" type in general.
- forgotmypw17 6y agoI appreciate all the new features in new JS, and I will continue using the oldest features possible for everything because they are likely the most tested, and least complicated. It also allows me to build sites which work in Netscape 3.0 and up without any special compatibility modes. :)
- johnfn 6y agoCareful. The newer features of JS are generally added because they are less complicated than the features they're succeeding. For instance, "var" may seem easier, but "const" is definitely less complicated. "var" has unintuitive edge cases with closures that "const" does not. `var` is also scoped to the nearest function rather than the nearest block, a "feature" that has tripped up many a new JS developer. `const` has none of these surprises.
- annoyingconst92 6y agoExcept `const` ruins interactive rapid prototyping using the browser DevTools console. If `width` was declared `const width = 800` you can't interactively experiment by setting `width=1024` because you get `..TypeError: Assignment to constant....`
- johnfn 6y agoI mean, it's literally a constant. Of course you can't redefine it. You said it was a constant! :P That's like saying that declaring a variable as "8" instead of 8 ruins rapid prototyping because now you can't multiply it.
- Dylan16807 6y agoMore like replacing declarations with magic number literals. And that does hurt interactive prototyping if it happens a lot!
- annoyingconst92 6y ago> Of course you can't redefine it. Well, you can redefine it by editing its source code file on disk. (Unless the file is read-only.) But it's a lot faster to be able to redefine it interactively inside the DevTools console and I wish there was a "dev" setting that allowed this. Also, you said "you declared it" but usually it wasn't me who declared it constant. Rather, some other programmer thought `width=800` or `numColumns=80` should be declared constant. "Variables aren't; constants won't be." No coder is an island: one programmer's bad `const` can't make life harder for other coders. Related: One reason I use Chromium browsers instead of Firefox is because in Firefox DevTools console once you declare `class A {}` you can't interactively change it to, say, add a constructor like `class A { constructor (foo) { this.foo = foo } }` During learning and experimentation this is lousy; you can't interactively iterate at the console prompt like a proper dynamic language. You must instead put your code in an external file and set up a "save file and re-run everything" system just like static languages like C++ require.
- Santosh83 6y agoSo this is why we need multiple browser implementations. Competition fosters excellence. Imagine if Chromium had 100% market capture. Would they be incentivised to fix this?
- asdfasgasdgasdg 6y agoThis problem doesn't exist at all in a world where chromium is the only browser, because there is no other party to get it wrong. Note that this is a problem with safari mishandling something, not chrome. That doesn't mean a single browser world is better. Just this particular instance if anything is a point in the pro column for browser monoculture.
- olliej 6y agoBug that is tracking this in webkit land is https://bugs.webkit.org/show_bug.cgi?id=199866 https://bugs.webkit.org/show_bug.cgi?id=199866
- olliej 6y agoFollow up: If you ever encounter a case where webkit/jsc is significantly slower than other engines they will happily take bug reports at bugs.webkit.org as the JSC team is always looking for tests that show suboptimal compilation that occurs in the real world.
- snemvalts 6y agoSafari is plagued with these issues, it's the new IE. The whole focus seems to be on implementing privacy features to advertise Apple's privacy focus. CSS bugs are not fixed and newer APIs are not implemented.
- dimeatree 6y agoThis takes me back to VB6 days where placing a dim in the sub would be too costly if that sub was called iteratively and using a global was the only way to optimize it because of the poor stack allocations. Would love to see what semantics are making let/const abysmal.
- netheril96 6y agoThe question is: does JavascriptCore implement other ES6/ES7/ES8 features just as inefficiently? Does it mean we should always transpile to ES5 even on browsers that support more modern variants?
- netheril96 6y agoSomehow people here are blaming Chrome for a bug in Safari.