10 Things 2020 has taught me
Tags: javascript, webdev, todayilearned, tutorial
Published: 2021-03-16 12:48:51

**2020 started out rough for a lot of us.** Most of us moved out of the office, and into our couches, kitchens, closets, or otherwise improvised office areas. Whereas you might have lost some precious moments in your car or the gratuitous sneeze-in-your-face on the commute, most of us gained something far more important; _Time_.

I have tried my best to put this time to use as best I can. Whether practicing inversions on the piano, getting that extra hour of exercise, or scrolling through whatever blogs and articles I could find that seemed like my cup of tea.

I also dedicated some of this time to document things I have learned during the day. Whenever I found something, learned something new or otherwise gained insight or knowledge into an area I deemed relevant to my professional field, I would make a note of it, and when given the opportunity, test it out for myself and detail my findings and sharing them.

This could be anything from finding a new useful code snippet to gaining insight into a whole new concept or paradigm. Today I want to share with you some of my favorites from this list, and I hope you will enjoy and be inspired to take this path for yourself.

I am focusing exclusively on **JavaScript** for this article. I have learned other things as well, but I think the core audience would not deem my aspirations for lego, piano nor amateur furniture builds relevant. That being said, this is starting to feel like one of those recipe introductions that describes the soups' relationship to Napoleon's great-grandfather. Just give me soup?

Soups, ahoy. Without further ado, here are some excerpts, and my favorite things, that I learned during 2020, in the order that I learned them.

### 1. Array.sort() behaves differently across browsers

This is more of a mistake that I scratched my head over for a long time earlier this past spring. Consider the following:

When sorting an array, me, and probably a lot of other people, fell into the trap of using this simple callback: `sort((x,y) => x < y))`

However, when running this on a simple example. We get the following in Chrome and Firefox respectively:

![array_sort_1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/63i4pdemdrcltmlcfmy7.png)

The comparison callback that `sort()` accepts must return either `1`, `0` or `-1`. Since our callback returns neither, but rather booleans. The different implementations of javascript across these browsers seem to have their own quirks in how they interpret these booleans.

So while Firefox for example seem to accept, or rather interpret, booleans as `1` and `-1` respectively, there is no guarantee that other browsers do the same thing, or even that Firefox itself will continue to do so in the future.
 
**Joakim does not accurately read Array documentation. Do not be like Joakim. Read the documentation.**
 
_Chrome also used to implement different sorting algorithms [depending on the size of the array](https://bugs.chromium.org/p/v8/issues/detail?id=90#c24) although this has since been changed to always use a **stable** sorting algorithm._

[Read more about .sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)

### 2. JSON.stringifys optional replacer argument.

Everyone and their mother who has ever dabbled in web development have, or will, at some point used `JSON.stringify`. But this year it dawned on me the second argument to this function: `replacer`. Which can be used as a sort of whitelist for key value pairs when parsing JSON.

![json_stringify_1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2mot0de4qunp1jz9drti.png)

BUT replacer can also be a function, which might be used to validate, replace or parse (or anything else under the sun. Creativity hat on, gals and guys) the JSON key value pairs.
 
![json_stringify_2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/87gpt399syw126i3lnw5.png)

This comes with a slight hit to performance, as you can see for yourself in [these benchmarks](https://perf.link/#eyJpZCI6ImNveW1mczIzYjduIiwidGl0bGUiOiJKU09OLnN0cmluZ2lmeSgpIHJlcGxhY2VyIGFyZ3VtZW50IGJlbmNobWFyayIsImJlZm9yZSI6ImNvbnN0IGRhdGEgPSB7b25lOiBcIm9uZVwiLCB0d286IDIsIHRocmVlOiBcInRocmVlXCIsIGZvdXI6IFwiZm91clwiLCBmaXZlOiA1fSIsInRlc3RzIjpbeyJuYW1lIjoiU3RyaW5naWZ5IHdpdGhvdXQgcmVwbGFjZXIiLCJjb2RlIjoiSlNPTi5zdHJpbmdpZnkoZGF0YSkiLCJydW5zIjpbNjY4MDAwLDY4MzAwMCw4ODUwMDAsMjUxMDAwLDkwMDAsMjAwMDAwLDI3MTAwMCw3MzQwMDAsMTY3MDAwLDI4ODAwMCwyODMwMDAsMjEwMDAsNTg0MDAwLDQ1MDAwLDEwMDAwLDQzODAwMCw5MDAwLDk1MDAwLDE0NTAwMCwxMTYwMDAsOTgwMDAsMTAwMDAsOTAwMCwzMzIwMDAsMjU3MDAwLDkwMDAsOTAwMCw0NTUwMDAsMjM0MDAwLDczMTAwMCw5MDAwLDI2NDAwMCw5MDAwLDUyMDAwMCwxMDAwMCw5MDAwLDcxMDAwLDgzNDAwMCw5MDAwLDc3MDAwLDkwMDAsNTc2MDAwLDE2MjAwMCw5MDAwLDkwMDAsODY1MDAwLDEwMDAwLDEwMDAwLDM0MDAwLDQ1MDAwLDY4MDAwLDIxNjAwMCw5MzkwMDAsOTAwMCwzNzYwMDAsMTk0MDAwLDIyNzAwMCw3MDAwLDI2MDAwMCwxMDAwMCw2MjUwMDAsOTAwMCw5ODAwMCwyNTkwMDAsMTU3MDAwLDEwMDAsOTAwMCwzNTEwMDAsMzAyMDAwLDEwMDAwLDE0MTAwMCwxNDc4MDAwLDE5MzAwMCw0OTYwMDAsMzg1MDAwLDU0NDAwMCwxNzEwMDAsOTAwMCw5MjAwMCw2NTQwMDAsMTI5MDAwLDkwMDAsMzc0MDAwLDEwMDAwLDk4MjAwMCwxNDcwMDAsMjIwMDAsMzA0MDAwLDU3NjAwMCwyMDAwLDExNTAwMCw1MTEwMDAsOTAwMCw1MzAwMCwxMDAwMCw5MDAwLDI2MDAwLDQwNzAwMCw2ODAwMCw3MjAwMF0sIm9wcyI6MjM3MTIwfSx7Im5hbWUiOiJTdHJpbmdpZnkgd2l0aCByZXBsYWNlciBhcyB3aGl0ZWxpc3QiLCJjb2RlIjoiSlNPTi5zdHJpbmdpZnkoZGF0YSwgW1wib25lXCIsIFwidGhyZWVcIiwgXCJmaXZlXCJdKSIsInJ1bnMiOls1MjIwMDAsNjgzMDAwLDcyNjAwMCwyMzYwMDAsOTAwMCwxNDIwMDAsMjMzMDAwLDAsMTI0MDAwLDI3MjAwMCwxMTEwMDAsMjkwMDAsNTQ1MDAwLDM3MDAwLDEwMDAsMzUxMDAwLDkwMDAsNDcwMDAsOTgwMDAsOTgwMDAsNjIwMDAsMTAwMDAsOTAwMCwyOTcwMDAsMTQ5MDAwLDYyOTAwMCw5MDAwLDE1OTAwMCwxODQwMDAsNTQ2MDAwLDkwMDAsMTg5MDAwLDkwMDAsNDUwMDAwLDEwMDAwLDkwMDAsMzYwMDAsMCwzNDQwMDAsNTYwMDAsOTAwMCwzODMwMDAsOTQwMDAsOTUyMDAwLDk5MDAwLDY5NzAwMCwxMDAwMCwxMDAwMCw0MDAwMCw0MTAwMCw0NzAwMCwyMDAwMDAsNzczMDAwLDkwMDAsMzE3MDAwLDE2MjAwMCwxNjAwMDAsODU5MDAwLDE5MDAwMCw5MDAwLDUxODAwMCwxMDAwMCw5ODAwMCwxMDAwMCw5ODAwMCwxMTEwMDAsOTAwMCwzNzAwMDAsMTkwMDAwLDkwMDAsOTkwMDAsOTAwMCwxNTYwMDAsNDU5MDAwLDMzNjAwMCw1MjUwMDAsMTE3MDAwLDEwMDAwLDYzMDAwLDYwNjAwMCwxMTAwMDAsOTAwMCwzMzEwMDAsOTAwMCw5MDAwLDEyMDAwMCwzNDAwMCwzMDQwMDAsNDc1MDAwLDEwMDAsOTAwMDAsNDE0MDAwLDgzMDAwLDkwMDAsMzUwMDAwLDMwMjAwMCwxODAwMCwzNjkwMDAsODI4MDAwLDEwMDAwXSwib3BzIjoyMDE3ODB9LHsibmFtZSI6IlN0cmluZ2lmeSB3aXRoIHJlcGxhY2VyIGNhbGxiYWNrIiwiY29kZSI6IkpTT04uc3RyaW5naWZ5KGRhdGEsICh2YWwpID0%2BIE51bWJlci5pc0ludGVnZXIodmFsKSA%2FIHZhbC50b1N0cmluZygpIDogdmFsKSIsInJ1bnMiOlsxMDQ1MDAwLDY2MjAwMCw1MzMwMDAsMTAwMCw5MDAwLDEwMDAwMCwxOTgwMDAsNDEwMDAsMTAwMDAwLDE3MDAwLDIyMDAwMCwxMTAwMCwxMTAwMCwwLDcwMDAsMzE1MDAwLDg1NDAwMCw1MDAwMCw5MDAwLDUzMDAwLDEzMDAwLDkwMDAsMTAwMDAsMjAzMDAwLDE1OTAwMCw5MDAwLDkwMDAsNzMwMDAsMTc0MDAwLDUwNzAwMCw5MDAwLDE4NjAwMCw1OTUwMDAsNDEyMDAwLDkwMDAsOTAwMCwxMDAwMCw2MTcwMDAsMTk2MDAwLDM3MDAwLDkwMDAsMzg2MDAwLDc5MDAwLDAsMTEwMDAsMCwxMDAwMCwxMzAwMCwzNDIwMDAsMTAwMCwyODAwMCw3NjAwMDAsNzI5MDAwLDkwMDAsMTU2MDAwLDM4MDAwLDEzMzAwMCwwLDk4MDAwLDkwMDAsNDg5MDAwLDEwMDAwLDYyMzAwMCwxMTAwMCwxMDAwMDAsMjcwMDAsMTAwMCwyODAwMDAsMTAwMDAsMTAwMDAsNTEwMDAsMTAwODAwMCw0OTAwMCw0NDMwMDAsMjk5MDAwLDI1OTAwMCwxMTQwMDAsMTcwMDAsMTkyMDAwLDU0NjAwMCwxMjIwMDAsMTAwMCwzMDMwMDAsOTAwMCw5MDAwLDEwMDAwMCwxMTAwMCwyMTQwMDAsNDM0MDAwLDEwMDAsNzYwMDAsMjk3MDAwLDUwMDAwLDMxNTAwMCwxMDAwLDkwMDAsOTAwMCwyMzEwMDAsMzIwMDAsNTgwMDAwXSwib3BzIjoxNzYzNjB9XSwidXBkYXRlZCI6IjIwMjEtMDMtMTBUMDg6Mzc6MjYuMDEzWiJ9), but for the average usecase it should not be a significant difference.

[Read more about JSON.stringify()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)

### 3. Array.filter() does not work with Promises

I tend to work a lot with array methods. A really common pattern would be: Perform a number of asynchronous operations, iterate over said operations to manipulate the data & filter out unwanted things.

I first ran in to this during the summer, when in my project, we used a function to check the users access levels, when performing certain operations. Let's call it `userCan`. By having this function return true or false, it could seamlessly be used as a `filter` callback to determine whether the user had relevant permissions for any given set of actions.

![filter_1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8ph059u9575f29hmqjz.png) 

Consider `actions` a batch of requests the user has made. We need to make sure only the actions the user has permission to do gets executed. Simplified code, but you get the gist:

![filter_3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5d2v4ingkoxlvrjrynwv.png)
 
Short and sweet. But what happens when we introduce asynchronous operations in `userCan`?

![filter_4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/as0sblsgjwbz52jqah2j.png) 

Suddenly every user action is allowed! The user should not have permission to `DROP_DATABASE`. Why is this happening?

Well, Unfortunately `Array.filter()` is a synchronous function, and therefore does not support Promises. Due to this, `filter()` will not await `userCan` to resolve a value, but just accept the Promise as a truthy value.

To get around this, we need to get a bit creative. There are a few ways to work around this, the most common, and the way I would recommend, would be to use `.map()` in conjunction with `.filter()`.

![filter_5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8p5nocab1xkyjss5jl09.png)

What we are doing here is using the asynchronous supported `.map()` to check the given predicate, and when all Promises has resolved, filter out the falsy values from the resulting array.

You could also do this with `.reduce()`, but I find it a bit more convoluted.

![filter_6](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/30tvlikk2zvtyhjsifj3.png) 

Neat, ain't it?

[Read more about .filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)

### 4. Nullish coalescing vs the logical OR operator

A lot of people, myself included, probably feel very familiar writing something like the following, to have a fallback in case `baz` is `undefined`: 

```
const foo = baz || "fallback"
```

`||` checks for falsy values such as `false`, `null` and `0`. But there might be cases where you need to treat `0` as an actual value, or otherwise more explicitly handle nullish values.

![nullish](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ai8rwv56h5ymun1vpi6h.png)
 
Nullish coalescing differs from `||` in that it only returns it's right-hand side operand when its left-hand side value is `null` or `undefined`.

Nullish coalescing was introduced in TypeScript as of **version 3.7** and is currently supported in the latest version of all major browsers and **Node.js 14**

[More about Nullish Coalescing here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator)

### 5. Console.table()

This blew my feeble mind when I ran into it the first time this summer. We're all experienced developers, so we use `console.log` as frequently as possible as it is possibly the strongest debugging tool there is! Well, here I am to tell you, that  `console.table()` exists and how great it is:

![console_table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bcbc43zrcmt1fpvjpsp7.png)

Whenever you're working with long arrays of  objects, this can be a lifesaver.

[More about console.table() here](https://developer.mozilla.org/en-US/docs/Web/API/Console/table)
 
### 6. The Promise constructor anti-pattern

The Promise constructor anti-pattern, or the deferred anti-pattern, refers to creating new objects, or in this case new Promises without reason. This is something I was very guilty of when I just started out as a junior developer and began delving into Promises.

It complicates code and prevents rejections and errors from being properly propagated.

I didn't know this was a recognized anti-pattern, and I myself just kind of naturally removed myself from the habit, until I learned more about it this year. It's easy to fall into this kind of way of working when you're new to Promises, and might not know that performing asynchronous operations already returns a Promise, which you in turn can chain.

![promise_1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/98tp5ldyr4065np0skt5.png)

Rather than explicitly creating a new Promise, it is adviced to just use the original one returned from the async function we are calling in the first place:

![promise_3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jpyxc4hrmvepkthp1wyb.png)

Doesn't that look a lot prettier?

[Read more about the Promise constructor anti-pattern here](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it)

### 7. Catch awaited errors

Now to something a little more bite sized. We all know you handle resolved and rejected promises by using `then` and `catch`. But if you want to catch an error using **async/await** you, to my knowledge, needed to wrap it in a _try/catch_ block, like so:

![catch_1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w77xvropho5fnzjr3lzq.png)
 
But to my own amusement and amazement, I recently found that you can in fact use `.catch()` on awaited Promises.

![catch_2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k4sca69yg3cn1t2w3q1e.png)
 
Granted, this makes a lot of sense when you think about it, given that async/await is really just syntactic sugar on top of Promises.

That being said, one might present the argument that one should stick to one convention or the other, and while I would usually agree with this sentiment, I just find it really handy in some cases. **What do you think?**

### 8. Using optional chaining for function calls.

This might be common knowledge, and as someone who rigorously uses optional chaining, I wonder why it never occurred to me to try this; You can use optional chaining for function calls?

![optional_1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/57rtruthopibgpvl5pcz.png)

It's beautiful.. And often comes in handy when working with React components for instance, which may or may not have event handlers such as `onClick`. No more `onClick={onClick && () => onClick(param)}`.

[Learn more about optional chaining here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining)

### 9. Utilizing Web Workers

JavaScript run-times are single-threaded environments, meaning code executions within a program can not be run in parallel, in contrast to for example Java and C#. This means that it's code execution by nature is _blocking_. We have to wait for one piece of code to finish, before moving on to the next.

Not to be confused with Promises, or [Node.js Child Processes](https://nodejs.org/api/child_process.html), **Web Workers** are a means to bring this multi-threaded behaviour to JavaScript. They can be utilized for a multitude of things, but probably most commonly used to delegate CPU intensive tasks to other threads, preventing long interruptions and user interface blockers. 

Similar to event listeners and `Socket.io`, workers communicate with each other using a messaging system and is very simple to get up and running.

![worker_1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lswx02xj8sapg447x7ns.png)

For the worker to listen and respond to the messages sent by the main thread, we just need to define the `onmessage` handler and we're good to go.

![worker_2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ig7drfgm23obzg8oxa8f.png) 

All we need to do now is make sure our main thread has some way to handle the messages sent back by our worker.

![worker_3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0l8b928y8tee7yz6iv2h.png)

While Web Workers can be very useful, they do come with [some limitations](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers#APIs_available_in_workers), such as not having access to the DOM.

[Read more about Web Workers here](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)

### 10. Not depending on dependencies 

Last, but not least, I want to give this honorary position in the list to one thing that probably taught me the most during this year.

Earlier last spring, **Deno** launched version 1.0 with an array of interesting features. Deno is a new, secure JavaScript and TypeScript runtime by Node.js creator [Ryan Dahl (ry)](https://github.com/ry).

_I'm not going to go deep into Deno here, but [here](https://deno.land)'s a link if you want to learn more about it._

Me, being an avid Node.js engineer, jumped at the opportunity to discover what it can do. I dedicated a weekend to trying to write a file- & web server that:

* Has live reload

* Supports client routing

* Requires zero configuration..

.. and at the same time being **completely dependency free**. Meaning no third-party packages can be used. The resulting project is called [Denoliver](https://github.com/joakimunge/denoliver), and I went on to release version 2.0 later in 2020.

I learned an absolute truckload _(no swearing here!)_ from this experiment. There's something highly intriguing having to solve problems most commonly solved with `npm install solution`. 

I cannot recommend this approach enough. It really was an amazing journey. If you want to check out the project yourself for inspiration, or to contribute, you can find it [here](https://github.com/joakimunge/denoliver).

{% github joakimunge/denoliver %}

### Closing

2020 has been an interesting time for everyone. I am very fortunate to be able to say that I have grown a lot during this time, and I have to give this small process a lot of credit as to why that is.

It might seem like a peripheral thing, but I highly recommend taking a couple of minutes each day to reflect over what knowledge you have gained and jot it down in your medium of choice. Nothing is too big, or too small. By the end of the year, or possibly a lot sooner than that, you will be amazed with the knowledge you have gained.

Hope you enjoyed the little tidbits of my journal today.

**What have you learned this year?**