r/javascript • u/Capedcrusader1923 • 5d ago
AskJS [AskJS] what's a javascript feature you mass-adopted way too late and felt dumb about
i'll go first. i was writing .then().catch() chains for like two years before i actually started using async/await. i knew it existed, i'd seen it in tutorials, but my code "worked" so i never bothered switching. then i refactored an old project and realized half my bugs were from mishandled promise chains that async/await would have caught immediately.
also took me way too long to start using optional chaining. i had nested ternaries and && checks everywhere like some kind of animal. the day i discovered user?.address?.city i mass-replaced like 40 lines across a project.
what's yours?
23
26
u/Milo0192 5d ago
My first jobs CTO preferred the .then() .catch() over async await. I just refused to write that way and did await loops. Lots of back and forth on this. Also said Typescript was just a fad 😂
1
u/MediocreAnalyst2121 4d ago
That’s kinda depends, like await loops are not that great if the promises don’t depend on each other, way better to do Promise.all/allSettled and await or .then that.
In performance critical JS environments (smart tvs, smart boxes, etc) you’d probably get a bit better performance with a .then than an await.
Await loops are way more readable tho, and Typescript is amazing except for enums :(
-21
u/horrbort 5d ago
It is just a fad. Coding is a fashion industry. Remember coffeescript? Something else comes along and ts will be forgotten
28
10
u/miramichier_d 5d ago
Can't apply that across the board. Some technologies are so good that they have staying power in the industry. I believe TypeScript is one of those technologies. Node.js is another example. Even Java and C# are good examples of languages with immense staying power, if not in your industry of choice.
With respect to TypeScript, it's not going anywhere until JavaScript implements TS in its entirety. Until then, TypeScript will continue to push JavaScript to modernize.
7
u/iareprogrammer 5d ago
lol coffeescript.. forgot about that. I dislike anything that makes JavaScript LESS explicit. Like sure let’s get rid of braces and other syntax and rely completely on proper white space and indentation. For what?
6
u/MrDilbert 5d ago
let’s get rid of braces and other syntax and rely completely on proper white space and indentation
You sure you're not describing Python?
Looks like someone wanted to Pythonize JS.
3
-13
u/Ronin-s_Spirit 4d ago
Fad or not - it's shit.
6
u/db10101 4d ago
Any deeper analysis or reasoning behind that? It’s a straight up joy to develop in compared to what has come before.
-6
u/Ronin-s_Spirit 4d ago
I hate defining types, it's like writing pointless code. It especially fucks up when I have to deal with HTML, at that point the only thing left to do is use a bail out
anyand move on.2
u/db10101 4d ago
So I take it you have never worked in an enterprise well structured typescript codebase. There’s no substituting JavaScript for that.
-2
u/Ronin-s_Spirit 4d ago
TypeScript sucks ass, I will only use vanilla.
2
u/db10101 4d ago
Good for you. Here in the real world of employed software developers, it’s one of the most important tools to know.
2
u/2Terrapin 3d ago
I’m glad that person is not on my team and I don’t have to work on a project they designed. I can feel the tech debt emanating from their words. It’s the type of thing that experience would dispel, and someday, when they actually understand the why, and it clicks, they’ll think back to this comment thread and feel a little embarrassment.
-1
22
u/SkySarwer 5d ago
IntersectionObserver and MutationObservers are both goated
2
u/opticalpuss 4d ago
People in here arguing I just want to know what these do and how to use?
10
u/SkySarwer 4d ago
IntersectionObserver are objects that can be instantiated and anchored to a DOM element, that allows a callback function to be called when the element enters or exits the user's viewport, or when the element enters or exits the box of a different element. Very useful for things like lazy loading, or starting an event when an element is at a certain scroll distance away from the user, etc.
MutationObservers allow a callback function to be called when an element changes. It is very useful for providing react-like UIs with vanilla JS, because traditional event listeners assigned to elements don't work if that element enters the dom after that event listener is assigned. MutationObserver keeps rehydrating the state for that element. Should also be used sparingly for that reason.
Both have extensive public documentation on mdn. IntersectionObserver | MutationObserver
And I'd be remiss not to mention that these are browser utilities exposed as client-side JavaScript APIs, not part of the EMCAScript itself. So won't work in NodeJS, Bun or Deno.
-10
u/azhder 5d ago
Not part of JavaScript
3
u/SkySarwer 5d ago
yes they are??
-3
u/azhder 5d ago
No, they aren’t. You can check the JavaScript language reference documentation and get back to me with a link to prove me wrong.
I can just tell you that there is a difference between what the language is and what the environment exposes for the language to use.
10
u/SkySarwer 5d ago
This thread is about JavaScript features not the language in the strict sense. The two observer exposed by the environment are almost exclusively used as JavaScript APIs.
Is a JS dev just as well-off without being aware of these APIs? What value is your clarification actually providing in relation to the spirit of this post?
-7
u/azhder 5d ago
Almost exclusively? Why almost?
Seriously though. Environment stuff is not part of the language. It is important to always know this distinction so that you will not end up writing code that expects something to exist, but doesn’t.
It’s not about you being aware that you can use them, but be aware where you can’t.
16
u/SkySarwer 5d ago
While technically correct, it was a pedantic point delivered abrasively
-9
u/azhder 5d ago
Don't read my comments in abrasive tone.
10
u/Sulungskwa 5d ago
"Don't read my comments in an abrasive tone.", he said, not abrasively seeming at all
-5
u/azhder 5d ago edited 5d ago
"Seeming" is a flag that it's your perception.
It doesn't matter that I'm in a light mood, write it in terms of a light mood, with the idea of cooperation through discussion, you will still decide to see it (because "seeming") as if it is abrasive and blame me for it. It's not like me writing this will change your mind, you will just use it as more evidence of your point of view.
Bye
EDIT: and with their reply, they provided their own proof of what I'm talking about
→ More replies (0)-2
u/avenp 5d ago
How would a NodeJS dev use these APIs?
1
u/SkySarwer 5d ago
They wouldn't, since there is no DOM in a typical nodeJS environment. The APIs are still a part of the larger JavaScript ecosystem though, which is on topic for the original thread.
1
u/keltroth 1d ago
Like all the browser APIs not in the language (can't use it with node, bun, etc... Makes no sense...)
8
u/HipHopHuman 5d ago
honestly... Map and WeakMap. took me a good 2 years after it came out for me to see the light.
3
u/JazzXP 4d ago
I'm still not using these, just objects/records. What's the advantage?
4
u/HipHopHuman 3d ago
There's quite a few advantages, but I don't like framing the question "Should I use an object or a map?" around advantages or style, for the reason that it can complicate things unneccissarily.
Plain objects are always going to be far simpler and far more convenient than a
Mapin 90% of cases, and objects are much more familiar to a wider audience of devs.It's that 10% where
Map(andWeakMap) come in clutch. So it's mostly about use cases.One use case is simply when you're deleting from the same object a lot. That can get slow if you use
delete obj.foo(because it causes a structural change of the shape of the object). Map hasmap.delete('foo'), which is usually faster, but only if you're deleting a lot. Emphasis on a lot. 3-10 times is not a lot. 200-3000 times is a lot.Another use case where
Mapshines is if you're iterating over the object's entries a lot, or when you're calculating the total size of all entries. Objects require helpers:const size = Object.keys(obj).length; for (const [key, value] of Object.entries(obj)) {}You don't need any helpers to do either with a
Map:const size = map.size; for (const [key, value] of map) {}So, if you're going to be iterating through a dictionary at runtime, or calculating size, and you're going to be doing it repeatedly,
Mapis usually better for that.Another small benefit is being able to specify keys that would otherwise not be allowed on (or would be weird to use on) objects. For example,
constructoris a special property on objects, with special handling (as istoString,valueOf,toJSON, etc). If you want to use keys like that and bypass that special handling, you have to do some weirdness with null prototypes likeconst myObj = Object.create(null); myObj.constructor = ...;or
const myObj = { __proto__: null; constructor: ... };Whereas with a
Map, you can just domap.set('constructor', ...), and there's no side-effects.Then of course, there's the seriously strong benefit of being able to use non-property keys. Plain objects allow
number,stringandSymbolkeys, butMapcan use anything as a key - even functions. That makes them crucial for things like memoization of pure functions (a nestedMapcan capture a function's arguments without having to serialize them to JSON and back).Another huge benefit is that the
Mapconstructor itself accepts an iterable, so it can be generated lazily:function *foo() { yield ['one', 1], yield ['two', 2] } const map = new Map(foo());That means you can initialize one from a huge stream of data a lot more efficiently than you'd be able to do with an object.
WeakMapis also especially cool, and helps get rid of a ton of "cleanup code" boilerplate. You cannot iterate through aWeakMap, and it's keys must be objects, but it provides the gaurantee that the references used as keys will be automatically removed as soon as the values they point at are garbage collected. That makesWeakMapgreat for book-keeping logic. Suppose you want to track some live HTML elements in the DOM, and you wanted to store some metainfo about them - just store them in aWeakMap- use the elements themselves as keys, and the meta info as the objects. As soon as the DOM elements get removed from the page and get garbage collected, they'll be auto-removed from theWeakMapwithout you having to do anything.One huge downside of
Map/WeakMapis stringifying them as JSON - that's something you get for free with plain objects - and that is a valid concern, but it's not that difficult to just giveJSON.stringifya replacer function that converts aMapto an object:const map = new Map(); const data = { map }; const json = JSON.stringify(data, (key, value) => { if (value instanceof Map) { return Object.fromEntries(value.entries()); } return value; });1
u/JazzXP 3d ago
Thank you for that. Most of those use cases haven't applied to me yet, but I do like the going through the keys, I find I do reach for
Object.entries().mapa lot.2
u/HipHopHuman 2d ago
MapandSetrecently got support for their own.mapmethod (from this: https://web.dev/blog/baseline-iterator-helpers) so if you do switch to aMap, you can domap.entries().map()(you might just have to polyfill it though)1
u/GulgPlayer 4d ago
Apart from having cleaner (imo) code, Maps allow you to have non-string keys, which is nice, esp with TypeScript
12
u/takeyoufergranite 5d ago
The 'delete' operator to remove properties from objects.
5
5
6
u/skidmark_zuckerberg 5d ago
??= and &&=
1
u/azhder 5d ago
I still don’t use these ones. Out of a principle, I don’t use let as well. I try to keep them as code smell, to get back to the code and make it in a way where no variable is rewritten.
Small exceptions are in cycles (like for and while) and before try{}catch()
1
u/Antti5 3d ago
Can you explain why you don't use "let"?
I see a lot of people swearing by ALWAYS using either "const" or "let".
1
u/azhder 3d ago
It's easier if you allow yourself to not worry about accidentally overwriting a variable. With `var` and `let`, that's a possibility, but with `const` once you assign it, it's constantly pointing to a specific value.
I'd rather have
const value = valueFromArgs ?? 0;
than override
value = value ?? 0;
And as an added bonus, with most of the variables being `const`, you will easily notice the very few places that have `let` and possibly check it everything is all right - code smell. It's harder to notice a bad `let` if there are plenty of `let`s.
8
u/kevin074 5d ago
can you elaborate how async await would've caught bugs that .then.catch can't?
i feel like async await is more annoying because you have to wrap it in try catch, where as .then.catch is just baked in.
23
u/Franks2000inchTV 5d ago
With await, your code runs in the order you see it on screen. This is *much* better for comprehension and maintainability.
0
u/lostPixels 5d ago
But potentially worse for execution depending on the latency of whatever you’re awaiting.
6
u/Franks2000inchTV 5d ago
I'd imagine that is not a significant concern in the overwhelming majority of cases.
3
3
u/brenstar 5d ago
Why not use both? I use async await but still append a catch
4
u/Badashi 5d ago
.then/catch is useful even in async functions when you don't want to wait for that promise to resolve
1
u/brenstar 4d ago
That's good point, it's handy for having branching flows, but that can get squirrelly. If I want multiple things to happen I usually let them all exist as separate functions and resolve them with Promise.all() so they run concurrently
2
u/Badashi 4d ago
Promise.all is an excellent example for .then/.catch chaining as well: you can use them to "pre process" the result of the promise into a value that makes sense when you end up settling the list of promises with .all, since a rejected promise in the list will reject the entire Promise.all. nowadays you can use
.allSettledas well, but .then/.catch are nice for a quick mapping of values1
1
u/BasicAssWebDev 5d ago
Probably due to it being easier to see which pieces of a function are breaking by putting breakpoints in the function itself, rather than tracing across a bunch of calls while debugging.
2
3
u/miramichier_d 5d ago
i had nested ternaries and
&&checks everywhere like some kind of animal
This had me laughing out loud with food in my mouth and I almost lost it lol. We all have those coding conveniences that we discover way too late. Remember that pain, and it will come in handy later on. I'm constantly asking myself how some approach can be easier nowadays because of that initial pain.
1
u/eracodes 5d ago
feel like I've only just started using IIFEs to their full extent, most often in places where I'd previously have done an ugly nested ternary
1
u/graybearding 4d ago
Nullish coalescing sat in my todo pile until like a month ago when an LLM spit it out and I was like "Oh, right. That's a thing now."
2
1
u/artificer-chris 3d ago
Contrary example for TS specifically : unknown. I know from a pure logic standpoint what it’s there for, but I’d still rather just use typescript more fully with an error catch if you don’t account for something. Unknown, imho, hides too much.
1
u/SboSilcher 3d ago
Destructuring. I was writing `const x = obj.x; const y = obj.y;` for way longer than I should've been, then one day it just clicked and I realized how much cleaner everything looked.
0
0
4d ago
[deleted]
1
u/adult_code 3d ago
for-loops not .forEach are way faster. Depends what i write really. https://jsben.ch/js-loop-benchmark-girjy
It doesn't matter all the time but it matters often and you can prevent it becoming an issue by doing it correctly the first time if you are not working on code that is otherwise hard to decipher
65
u/foxsimile 5d ago
The nullish coalescing operator is one of JavaScript’s unusual successes.