<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ilia</title>
    <description>The latest articles on DEV Community by Ilia (@sadiolem).</description>
    <link>https://dev.to/sadiolem</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4055355%2F2f39c17c-3390-4cd9-a976-f320afec6c47.jpg</url>
      <title>DEV Community: Ilia</title>
      <link>https://dev.to/sadiolem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sadiolem"/>
    <language>en</language>
    <item>
      <title>How Not to Lose Yourself in the Age of AI</title>
      <dc:creator>Ilia</dc:creator>
      <pubDate>Sat, 01 Aug 2026 19:43:17 +0000</pubDate>
      <link>https://dev.to/sadiolem/how-not-to-lose-yourself-in-the-age-of-ai-4754</link>
      <guid>https://dev.to/sadiolem/how-not-to-lose-yourself-in-the-age-of-ai-4754</guid>
      <description>&lt;p&gt;The promise that we'll soon stop writing code by hand is far from new. COBOL was made to look like English so that programs would be readable by more than just programmers. SQL's predecessor was called SEQUEL, literally Structured English Query Language. Then no-code platforms arrived. The amount of manual work really did go down, but programmers didn't disappear. If anything, there were more of them than before.&lt;/p&gt;

&lt;p&gt;Now it's the turn of large language models (LLM). For brevity I'll just call them models from here on. And this time we've met the final boss: for the first time, a tool genuinely works in natural human language from end to end. It became possible to write entire programs knowing nothing about programming languages.&lt;/p&gt;

&lt;p&gt;That sounds a little frightening. But we quickly reached a reassuring conclusion that only the routine work disappears, and demand grows for the people doing architecture and review. Surely there still need to be people who define the tasks and then check the generated code.&lt;/p&gt;

&lt;p&gt;But what are we going to lean on when we check that code? In sheer volume of knowledge, a model already outstrips any individual developer: it can reproduce most known algorithms and patterns, it knows a huge number of libraries, it knows the syntax. No human holds that much in their head. Competing with models on the amount of memorized information is pointless.&lt;/p&gt;

&lt;p&gt;And yet they still haven't become a full replacement for a programmer. So our value isn't only in knowledge, there's something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes us different
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The model doesn't have your context.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At least not in the form you have it. Technically, model context windows are already big enough to fit an entire library. In practice the model only sees what made it into the working session. And even when a lot of information fits, that's no guarantee the relevant connection gets noticed: models draw unevenly on different parts of a long context and can miss even explicitly stated instructions.&lt;/p&gt;

&lt;p&gt;Rules files and project descriptions help, but you can't pack the whole context into them. You can't fit ten years of experience into a single set of instructions. If understanding could be transferred as one document, we'd have been turning juniors into seniors with a README a long time ago.&lt;/p&gt;

&lt;p&gt;So a model can hold nearly all of humanity's knowledge and still be unable to replace experienced specialists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The model doesn't carry responsibility.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You're the one who gets pulled in on a weekend, who explains to the team lead or the business why production is broken, who fixes the aftermath. And the thing is, responsibility forces you to see where a decision led, and that's where experience comes from.&lt;/p&gt;

&lt;p&gt;Someone who once wiped a production database didn't just learn a new fact. They had to live through the consequences, and that kind of experience tends to stick. It's what keeps you from making the same mistake twice. A model, meanwhile, gave its answer and moved on to the next task. As long as the mistake is in the current context it can account for it, but that experience never becomes a durable habit.&lt;/p&gt;

&lt;p&gt;So our advantage really isn't the amount of knowledge. It comes out of accumulated experience and our own decisions, out of feedback from reality, out of the ability to notice when something's off, and out of having to answer for our choices. And here, it seems to me, a problem starts to take shape, because all of that is formed and sustained through practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we pick up skills
&lt;/h2&gt;

&lt;p&gt;Understanding used to arrive on its own, just in the course of the work. A task lands from an unfamiliar area, you read the documentation and Stack Overflow, try different approaches, make mistakes, debug. In the end an understanding of the implementation takes shape in your head. You remember the path to the solution, you find your way around the code faster, you can explain the choices you made and answer questions about them.&lt;/p&gt;

&lt;p&gt;Working out how a finished solution works and arriving at it yourself are not the same thing. When you look at a completed implementation, it's easy to get the feeling that it's all clear. Then you try to reproduce the same solution on your own and discover that the understanding was an illusion.&lt;/p&gt;

&lt;p&gt;A skill forms where you do the work yourself, mistakes included.&lt;/p&gt;

&lt;p&gt;These days models increasingly walk that path for us: they break down the task, pick an approach, write the code and the tests, fix the errors. If you only join at the end, it's easy to remain a spectator. The code looks comprehensible, but no understanding of the solution of your own ever appears.&lt;/p&gt;

&lt;p&gt;That said, there's no point clinging to everything either. Some skills genuinely can be let go. Why spend effort on things models already do faster? The goal isn't to refuse progress, it's to avoid losing your own understanding along with the routine work.&lt;/p&gt;

&lt;p&gt;What's left is deciding which skills to keep and which can safely be released.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to release and what to keep
&lt;/h2&gt;

&lt;p&gt;I ended up with a single criterion: does this skill help with the things we're still better at than the model?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Release.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Anything you can look up and verify quickly: exact syntax, API details, boilerplate, a ready-made implementation of an algorithm. If the answer takes a minute to find and correctness is easy to check, there's no obligation to keep it in your head.&lt;/p&gt;

&lt;p&gt;But it's important not to confuse implementation with understanding here. You can ask a model for the code of an algorithm. Understanding its complexity, its limitations, and whether it fits your particular problem is still worth doing yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep and develop.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Everything that accumulates over time: knowledge of the project, the reasons the workarounds are there, the ability to debug, a sense of the boundaries and constraints in your own specific context. Working with incomplete requirements. Working with a team. The cost (in every sense) of one decision over another.&lt;/p&gt;

&lt;p&gt;Put simply, what's worth keeping is what you can't get from a single prompt. Which means keeping for yourself the work in which that understanding appears.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like in practice
&lt;/h2&gt;

&lt;p&gt;Almost any task has at least four stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Framing&lt;/strong&gt; — what we're doing and why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contract&lt;/strong&gt; — what data goes in and out, where the boundaries are, which states are valid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acceptance criteria&lt;/strong&gt; — how we'll know the task is solved.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation&lt;/strong&gt; — code and configuration.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Framing has to stay our responsibility, because this is where context matters most. We know the business we work for, the history of the product, the verbal agreements and the constraints that never made it into the documentation. Some of that can be passed to a model, but it won't find it out on its own.&lt;/p&gt;

&lt;p&gt;Describing the contract is the next important stage. This is where gaps in the framing usually surface and where clarifying the requirements begins. Either we go and clarify the details, or we make a deliberate decision based on experience.&lt;/p&gt;

&lt;p&gt;Beyond that, the contract gives a high-level picture of how the feature is put together: what data it needs, what goes in, what comes out, what changes in between. This is where a connection forms not just with the task but with the implementation to come.&lt;/p&gt;

&lt;p&gt;Acceptance criteria (tests or acceptance conditions) are better defined before the model writes any code. They're what separates a correct solution from a plausible one.&lt;/p&gt;

&lt;p&gt;If the model writes the implementation first and then generates tests from it, it can misread a requirement once and repeat the same mistake in the checks. The tests will be green: they're simply consistent with the code. So the criteria have to come from the framing, not from code that already exists.&lt;/p&gt;

&lt;p&gt;In principle a model can be brought into the framing, the contract, and the criteria too. It'll offer options, find edge cases, and argue with the contract you've chosen. But as a second pair of eyes, not as the sole author.&lt;/p&gt;

&lt;p&gt;Once framing, contract, and criteria are settled, implementation looks like the most natural candidate for near-total delegation. Everything's decided; all that's left is writing the code. But do that every time and you deprive yourself of practice you need.&lt;/p&gt;

&lt;p&gt;Two questions help work out which work to hand over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will this task give me new understanding?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the solution is already clear, the result is easy to check, and all that's left is assembling it from known parts, the work can go to the model almost entirely. But if the approach still has to be found, or the area is new to you, a lot will only become clear while working on it. And the more you delegate in a task like that, the less understanding you come away with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are the risks?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The higher the cost of a mistake and the harder the rollback, the less autonomy the model should get. You need to have a picture of what you'd do if something breaks. Here your involvement isn't about learning any more — it's about staying in control of the consequences.&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;LLMs don’t strip us of our skills, but for the first time we’re at a point where the end result of work can be separated from getting the experience and skills. Previously, getting a task done meant actually understanding it, but now you can get working code without ever going through that process. And the problem is that we ourselves give in to the temptation of staying in the role of the ones who just assign tasks and check results, even though the ability to do that well also came from practice. So I think we need to start asking ourselves what to delegate and what not to, so we don’t lose ourselves.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Web performance case study</title>
      <dc:creator>Ilia</dc:creator>
      <pubDate>Fri, 31 Jul 2026 21:44:06 +0000</pubDate>
      <link>https://dev.to/sadiolem/web-performance-case-study-1n1</link>
      <guid>https://dev.to/sadiolem/web-performance-case-study-1n1</guid>
      <description>&lt;p&gt;In this article I want to share my experience running a full optimization pass over a real project, with examples. In this case it's an SPA built with Vue 3, using Vuetify for part of the UI and Firebase for auth.&lt;/p&gt;

&lt;p&gt;Some context: I work as a frontend developer at a company that mostly builds MVPs, but also develops and maintains long-lived products. MVPs in particular tend to accumulate problems, because refactoring and optimization get the bare minimum of time, and the same problems repeat across projects, since we often start from the same template.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring performance
&lt;/h2&gt;

&lt;p&gt;It all starts with metrics: to make something better, you first need to know what "before" looked like. I used three tools: PageSpeed, Lighthouse, and rollup-plugin-visualizer (our project runs on Vite).&lt;/p&gt;

&lt;p&gt;You'd think PageSpeed and Lighthouse were the same thing, because they use the same engine, but in practice they report noticeably different Performance scores. In my case PageSpeed was consistently 20 points worse than Lighthouse. So which one do you believe?&lt;/p&gt;

&lt;p&gt;That's the first problem: any Performance metric is always a simulation, never reality. Your website can work perfectly on real users' devices while the Lighthouse engine tells you the opposite. And the other way around.&lt;/p&gt;

&lt;p&gt;But if your website is in production with enough traffic, PageSpeed can help: it has a section showing actual performance based on real user data.&lt;/p&gt;

&lt;p&gt;Here's an example of that field data, while PageSpeed's own score for the same page sat somewhere around 45–55, rating every individual metric noticeably worse:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2nu5xjopp4o5kdkw9wbe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2nu5xjopp4o5kdkw9wbe.png" alt=" " width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I think it's worth looking at both PageSpeed and Lighthouse in DevTools. You get far more information that way, and a better sense that both of them only roughly estimate performance by simulating particular hardware and network conditions — affected by things like where the server physically sits.&lt;/p&gt;

&lt;p&gt;The next tool is rollup-plugin-visualizer, which shows you visually what your bundle is made of, whether there's anything in there you don't want, and how much each piece weighs. I used it only because Lighthouse doesn't show the bundle tree for Vite (unlike Vue CLI with webpack).&lt;/p&gt;

&lt;p&gt;So, here's where we start:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs02wlhloutavnp8na2fl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs02wlhloutavnp8na2fl.png" alt=" " width="800" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing fonts and icons
&lt;/h2&gt;

&lt;p&gt;The biggest impact on load speed comes from whatever blocks rendering — scripts, styles, or fonts loaded in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; that block the render until they've downloaded and executed.&lt;/p&gt;

&lt;p&gt;In our case, among other things, fonts and the mdi (Material Design Icons) library had a noticeable effect.&lt;/p&gt;

&lt;p&gt;Fonts were setup like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F21i42ezl3spm83togqr5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F21i42ezl3spm83togqr5.png" alt=" " width="800" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's see what's wrong with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Every possible weight from 100 to 900 is loaded, even though the site only uses 400, 500, 600, and 700.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There's no &lt;code&gt;display=swap&lt;/code&gt;, so there's no way to show a fallback font while the main one loads (without it, users see no content at all until the font arrives).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The font loads from an external resource, Google Fonts, so it would be good to add &lt;code&gt;preconnect&lt;/code&gt; to those origins and do the DNS/TCP/TLS handshakes ahead of time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case the requests go to &lt;code&gt;https://fonts.googleapis.com&lt;/code&gt; and &lt;code&gt;https://fonts.gstatic.com&lt;/code&gt;. For the external origin the font itself is downloaded from (for Google Fonts that's &lt;code&gt;https://fonts.gstatic.com&lt;/code&gt;), you need the &lt;code&gt;crossorigin&lt;/code&gt; attribute — otherwise preconnect will only do the DNS part.&lt;/p&gt;

&lt;p&gt;Incidentally, Google Fonts now offers all of this by default, but our project was apparently created long before that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can use &lt;code&gt;preload&lt;/code&gt; to request the font at the very start of the critical rendering path, without waiting for the CSSOM to be built (by default the browser only downloads a font after it has built the CSSOM). Since the font isn't loaded after HTML and CSS parsing in that case, you may not even need the fallback font at all — which eliminates the layout shift you get when the two fonts don't match in size.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But be careful with &lt;code&gt;preload&lt;/code&gt;: you're delaying the loading and parsing of other resources, and you're downloading the font unconditionally, even if it turns out not to be used on the page. So you need to measure its effect on load and render speed and weigh up whether it's worth it.&lt;/p&gt;

&lt;p&gt;That gives us this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fickjcvpog4a1bw6ucs6o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fickjcvpog4a1bw6ucs6o.png" alt=" " width="800" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next optimization opportunity is a variable font. In short, variable fonts are "programmable" fonts you can tune flexibly along different axes without downloading each variant separately up front, the way you have to with regular fonts — which drives up both the number of requests and the amount of data transferred.&lt;/p&gt;

&lt;p&gt;Google Fonts already has a variable version of Roboto called Roboto Flex, so let's use that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F834pzqdzwkxkj2nkvi9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F834pzqdzwkxkj2nkvi9k.png" alt=" " width="800" height="123"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For comparison, here's how many requests we had with regular Roboto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo3n47ilzned518zj1e3i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo3n47ilzned518zj1e3i.png" alt=" " width="800" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here's how many with Roboto Flex, now that we no longer need to download each weight separately:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk44b3ix9xscxytui27sl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk44b3ix9xscxytui27sl.png" alt=" " width="800" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now for the icon library. It's connected like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhaylj3p0hehkzxnehfj9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhaylj3p0hehkzxnehfj9.png" alt=" " width="799" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's the problem here? It downloads a single file containing every icon in the library, even though the vast majority of them are never used in the project.&lt;/p&gt;

&lt;p&gt;The fix is fairly simple: instead of the CDN we pull in &lt;code&gt;@mdi/js&lt;/code&gt;, which lets you import only the icons you actually use, so only those end up in the final bundle.&lt;/p&gt;

&lt;p&gt;Here's what that looks like with Vuetify:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fds7mstt9fdd8yrhl5r5v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fds7mstt9fdd8yrhl5r5v.png" alt=" " width="800" height="815"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  First results
&lt;/h2&gt;

&lt;p&gt;So far we've only optimized how fonts and icons are loaded — but those were contributing a lot to Total Blocking Time. Let's measure Performance again and compare with where we started:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc2plun7tqu47nw22jh6s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc2plun7tqu47nw22jh6s.png" alt=" " width="800" height="633"&gt;&lt;/a&gt;&lt;br&gt;
Before&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwfetu4li41ta67p0poij.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwfetu4li41ta67p0poij.png" alt=" " width="800" height="654"&gt;&lt;/a&gt;&lt;br&gt;
After&lt;/p&gt;

&lt;p&gt;We gained 10 points and noticeably reduced Total Blocking Time. But these are only the first steps, so let's keep going.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eliminating layout shift
&lt;/h2&gt;

&lt;p&gt;As I mentioned in the fonts section, layout shift is, in simple terms, content jumping around when data loads late or changes size and pushes the surrounding content out of the way. It sounds like something that has nothing to do with load speed, but since Lighthouse v10 this metric contributes a full 25% to the overall Performance score (Total Blocking Time is first, at 30%), so you can't ignore it.&lt;/p&gt;

&lt;p&gt;Right now the metric is in the red at around 0.5, and the page load timeline looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffoik5qs44clkrf9e8g4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffoik5qs44clkrf9e8g4w.png" alt=" " width="799" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that in the first seconds of loading the user sees the site's footer, and only then does everything snap into place. That happens because between the header, the text banner, and the footer there's content that loads and renders dynamically. Until it arrives, the footer takes its place.&lt;/p&gt;

&lt;p&gt;The simplest fix — though not always the best one, since the footer then gets hidden below the fold even when the main content doesn't fill the whole height — is to give the main content, which is almost always dynamic, a minimum height of, say, &lt;code&gt;100vh&lt;/code&gt;, so it occupies all the available screen height:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4q7xqi0072rwjqcvhvwq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4q7xqi0072rwjqcvhvwq.png" alt=" " width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second, more involved option is skeleton loaders: while data loads you show placeholders that mirror the structure and size of the real content, which also avoids the shift. For now we're going with the first option.&lt;/p&gt;

&lt;p&gt;Let's check what effect this had on layout shift:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzsdtsrp2lxcyecejhd72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzsdtsrp2lxcyecejhd72.png" alt=" " width="800" height="740"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We brought it to 0, and the overall score is now 56, it's roughly a 10-point gain from one small change. And indeed, in the timeline at the bottom you can see the footer is no longer visible during the first seconds and everything sits where it should.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firebase
&lt;/h2&gt;

&lt;p&gt;The short version of the problem:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F70tk2642m0qr2h0mbcz5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F70tk2642m0qr2h0mbcz5.png" alt=" " width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Almost 2 MB of JavaScript, taking up 70% of the bundle. The reason is simple: we're on Firebase 8, which doesn't support importing only the modules you need, unlike the current version 9.&lt;/p&gt;

&lt;p&gt;We upgrade Firebase to 9, rewrite our code to match the API changes, look at the bundle again, and… we've gone from 1.78 MB to 310 KB. Still a lot, but 6× better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvcyncgr39b3re5g1orgj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvcyncgr39b3re5g1orgj.png" alt=" " width="648" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But that's not all. Looking again at what gets loaded, we spot an &lt;code&gt;iframe.js&lt;/code&gt; from Firebase weighing 279 KB. A bit of digging shows it's only needed for certain auth flows — for example &lt;code&gt;signInWithPopup&lt;/code&gt; for Google or Facebook sign-in. We don't use that method, so all that code is dead weight sitting there just in case. Worth removing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp9ykkd2de2d14t5499xg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp9ykkd2de2d14t5499xg.png" alt=" " width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We started with this code, using &lt;code&gt;getAuth()&lt;/code&gt;, which pulls in a lot of unused code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpzwlw2cdhxow1gxgva0j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpzwlw2cdhxow1gxgva0j.png" alt=" " width="800" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We rewrite it to use &lt;code&gt;initializeAuth()&lt;/code&gt; with only the imports we need, and leave a comment for whoever comes next warning them to be careful with the methods that needed that &lt;code&gt;iframe.js&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fde2zhb4mj7doymekknzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fde2zhb4mj7doymekknzd.png" alt=" " width="800" height="807"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We check the bundle one more time and there's nothing extraneous left:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ej3dheb6rlo3li9b9d0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ej3dheb6rlo3li9b9d0.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Interim results
&lt;/h2&gt;

&lt;p&gt;Last time we were at a Performance score of 56; after the Firebase work we're at 75:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frccxqp74n5mexrdwpq6q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frccxqp74n5mexrdwpq6q.png" alt=" " width="800" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Async components and routes
&lt;/h2&gt;

&lt;p&gt;Looking at the final bundle, you can see that even though we're on the home page it contains other pages we don't need right now — &lt;code&gt;NotFoundPage&lt;/code&gt; and &lt;code&gt;TermsPage&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsecluy3br3ms6bhvr8jt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsecluy3br3ms6bhvr8jt.png" alt=" " width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vue Router supports dynamic imports out of the box, so pages we don't need get split into separate chunks and are requested only when required, instead of ending up in the main bundle. And yes, every other page was already wired up that way — these two were apparently just forgotten or overlooked.&lt;/p&gt;

&lt;p&gt;We fix &lt;code&gt;router.js&lt;/code&gt;, replacing the static imports with dynamic ones:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi1vhzb8id0vahuszqhbc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi1vhzb8id0vahuszqhbc.png" alt=" " width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By the way, back when the project was on Vue CLI, a side effect of dynamic imports was that each chunk generated a prefetch — and with enough of them that hurt load speed, because the browser had to make a lot of extra requests for things it didn't need right then:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8iv99tanfven3e9hszkb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8iv99tanfven3e9hszkb.png" alt=" " width="800" height="769"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To prevent that, I configured webpack to skip prefetching:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqel1lywrsxscdtln4ue1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqel1lywrsxscdtln4ue1.png" alt=" " width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to keep prefetch for specific routes, you can enable it per route with a &lt;code&gt;webpackPrefetch: true&lt;/code&gt; comment on the dynamic import: &lt;code&gt;import(/* webpackPrefetch: true */ './somePage.vue')&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Another problem with dynamic routes: if a component had logic tied to route information (say, checking &lt;code&gt;$route.name&lt;/code&gt; to work out that we're on the login page and hide the footer), it could misbehave, because at the moment the condition was evaluated the route itself might not have loaded yet.&lt;/p&gt;

&lt;p&gt;So in places like that we had to write conditions so that the component, or part of it, only rendered once the route had loaded and therefore had a &lt;code&gt;name&lt;/code&gt; property, with the dependent logic running after that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpqh6crc3jq2xnzn6rrx2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpqh6crc3jq2xnzn6rrx2.png" alt=" " width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now for async components. The idea is roughly the same as with routes: we can load them only when we need them. We only started doing this after moving to Vue 3, where it's quite simple and convenient.&lt;/p&gt;

&lt;p&gt;For example, we have a global component for error notifications that sits unused most of the time and is only needed when an error actually occurs (the same goes for plenty of modals). A good candidate for an async component.&lt;/p&gt;

&lt;p&gt;Let's rewrite its import using &lt;code&gt;defineAsyncComponent&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcbui0jsgs7df4pew70eo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcbui0jsgs7df4pew70eo.png" alt=" " width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By the way, the overall Performance score didn't move after all these changes, so there's nothing to show. But that's only because we removed a couple of lightweight routes and one small component — the bigger and more complex the project, the more you stand to gain from these Vue and Vue Router features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing requests
&lt;/h2&gt;

&lt;p&gt;On top of everything else, we can reduce both the number and the size of requests.&lt;/p&gt;

&lt;p&gt;For example, on the pages listing athletes or coaches on the platform we were requesting 50 people per paginated page — even though in practice a user on a phone initially sees only 3–5 cards, and on desktop 10–15, depending on screen size. The obvious fix: cut the number of athletes and coaches requested to 15 per page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjn7i8vimtjx4qkx77el9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjn7i8vimtjx4qkx77el9.png" alt=" " width="800" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next: the site has a lot of images (competition photos and their thumbnails, user avatars), so for images that aren't visible on screen at load time, or that sit behind pagination, I add &lt;code&gt;loading="lazy"&lt;/code&gt;. We have a shared image component, so that's what I change:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzgfwrpuf57b7l8t61xgo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzgfwrpuf57b7l8t61xgo.png" alt=" " width="800" height="676"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I decided not to use a dedicated lazy-loading library, because support for the attribute is already close to 93%.&lt;/p&gt;

&lt;p&gt;We could also add an SVG sprite to cut down the number of image requests, since besides the mdi icons we have a lot of custom ones. That task is still in progress, though.&lt;/p&gt;

&lt;p&gt;Then we go through the project looking for chains of &lt;code&gt;await&lt;/code&gt;ed requests where each one waits for the previous to finish, even though in some cases they don't depend on each other and could run in parallel with &lt;code&gt;Promise.all()&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6w35mk0rftx201m3aqai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6w35mk0rftx201m3aqai.png" alt=" " width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Equally important: look at what the backend actually returns, and talk to the backend developers. Tell them when responses contain unused fields that bloat the payload, or suggest splitting large endpoints into several smaller ones where the situation allows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vue 3
&lt;/h2&gt;

&lt;p&gt;Another improvement to the Performance score came from migrating the project from Vue 2 to Vue 3, so if you're still deciding whether to make that move, this can be one more argument in favor.&lt;/p&gt;

&lt;p&gt;I found the numbers on the speed difference between Vue versions here. In practice, for us the difference in Performance was 10–15 points in Vue 3's favor. I'm sure everyone's results will differ, but that was our experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redesign
&lt;/h2&gt;

&lt;p&gt;Something outside my control contributed too: a redesign of the home page (keeping in mind that the Performance score on other pages obviously didn't change as a result). Instead of one large banner at the top, the page got several smaller, lighter images, which can also be loaded with &lt;code&gt;loading="lazy"&lt;/code&gt;. That was worth roughly another 10 points:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl4qcp9du5ce5optbr3jc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl4qcp9du5ce5optbr3jc.png" alt=" " width="800" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PWA
&lt;/h2&gt;

&lt;p&gt;Finally, we converted our SPA into a Progressive Web App, which lets us cache almost any resource the site uses — CSS, JS, fonts, images. From then on they're served from cache without being re-downloaded until a new release goes out. And while this doesn't affect load speed on a first visit, it significantly speeds up loading and navigation on subsequent ones.&lt;/p&gt;

&lt;p&gt;But caching is a hidden devil. It's important to be sure that when the site's code is updated, users always get the latest version and don't get stuck on a stale cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0msi6ym3vtq3mrxcd98j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0msi6ym3vtq3mrxcd98j.png" alt=" " width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's sum up and draw some conclusions from the optimization work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We doubled Performance (from 30–40 to 70–80 points).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The most noticeable results came from loading fonts properly (including using a variable font), from the icon library, and from the modular Firebase 9.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Given how much fonts matter, discuss the topic with your designer up front so they can use variable fonts where possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Layout shift is an important factor in the Performance score. Bringing it to 0 gives a meaningful boost, and also improves the actual experience of using the site.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vue 3 gave a decent gain, which is one more argument for migrating from Vue 2.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Async components, async routes, lazy loading, SVG sprites, request optimization — these give fairly limited results, but the payoff grows with the size and complexity of the project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sometimes changing the design is enough: making it lighter. But it's important to account for this from the start, sometimes by talking your designer out of things like very large images.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Going PWA can bring a significant Performance improvement through caching.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Understanding `this` in JavaScript</title>
      <dc:creator>Ilia</dc:creator>
      <pubDate>Thu, 30 Jul 2026 17:31:34 +0000</pubDate>
      <link>https://dev.to/sadiolem/understanding-this-in-javascript-1703</link>
      <guid>https://dev.to/sadiolem/understanding-this-in-javascript-1703</guid>
      <description>&lt;p&gt;There are three things you can watch forever: fire burning, water flowing, and frontend developers writing yet another article about &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Still, that pile of articles exists for a reason. The topic really is confusing for a lot of people. There are plenty of good articles that get it right, but mostly from a purely practical angle, without digging into how it actually works underneath. Articles that go deep on the theory are literally a handful.&lt;/p&gt;

&lt;p&gt;In this article I'll try to open the topic up from the theoretical side, starting from the ECMAScript specification, and then derive the practical rules for determining &lt;code&gt;this&lt;/code&gt; from that theory.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reference Record type
&lt;/h2&gt;

&lt;p&gt;One of the foundational concepts for determining the value of &lt;code&gt;this&lt;/code&gt; is the Reference Record.&lt;/p&gt;

&lt;p&gt;A Reference Record is one of the ECMAScript specification types (not to be confused with JavaScript's own types, or the spec pedants will come for you) used internally by the language. It has the following fields: Base, ReferencedName, Strict, and ThisValue. Let's go through them in order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Base&lt;/strong&gt; — a value equal to one of the JavaScript data types, or an Environment Record (another specification type).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ReferencedName&lt;/strong&gt; — a String, Symbol, or Private Name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strict&lt;/strong&gt; — a Boolean.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ThisValue&lt;/strong&gt; — one of the JavaScript data types.&lt;/p&gt;

&lt;p&gt;In plain terms: Base can be, for example, an object or an Environment Record (essentially a special object that holds all the local variables); ReferencedName is the name of an object property or an identifier; Strict indicates strict mode; and ThisValue is related to the &lt;code&gt;super&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;From here on I'll leave out the Strict and ThisValue fields unless we need them for something specific.&lt;/p&gt;

&lt;p&gt;So how do we tell what counts as this type? It's fairly simple. The interpreter treats something as a Reference in two cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When we use a &lt;strong&gt;property accessor&lt;/strong&gt;, meaning dot or bracket notation: &lt;code&gt;obj.name&lt;/code&gt;, &lt;code&gt;obj['name']&lt;/code&gt;, or &lt;code&gt;obj.method()&lt;/code&gt;. Incidentally, the usual phrasing about &lt;code&gt;this&lt;/code&gt; is that it equals whatever sits to the left of the dot, which conveniently forgets the bracket variant.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1ikzokqh52dycbevbm3t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1ikzokqh52dycbevbm3t.png" alt=" " width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;And when we're dealing with an &lt;strong&gt;identifier&lt;/strong&gt; — variables, properties, or functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr77u0ykfs857mopspad0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr77u0ykfs857mopspad0.png" alt=" " width="795" height="80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In every other case — with operators (&lt;code&gt;x + y&lt;/code&gt;, &lt;code&gt;x ? y : z&lt;/code&gt;, &lt;code&gt;!x&lt;/code&gt;) and literals (&lt;code&gt;"abc"&lt;/code&gt;, &lt;code&gt;[1, 2, 3]&lt;/code&gt;, and so on) — we get other types.&lt;/p&gt;

&lt;p&gt;For example, say we have a &lt;code&gt;person&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dasha&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;catName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catName&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Walking through this code, the interpreter sees that a property accessor is being used to reach the &lt;code&gt;catName&lt;/code&gt; property, so what we have is a Reference Record expression that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;Base:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;ReferencedName:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;catName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or take a variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's an identifier, so it's a Reference too, and it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;Base:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;ReferencedName:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A note on the global object: it's the object that, depending on the environment and on strict mode, can have different values: in a browser it's &lt;code&gt;window&lt;/code&gt;, or &lt;code&gt;undefined&lt;/code&gt; in strict mode. Rather than list every possible value each time, I'll just use the word "global" from here on.&lt;/p&gt;

&lt;p&gt;So we can say that the value of Base is the context that ReferencedName lives in.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;this&lt;/code&gt; and the Reference type
&lt;/h2&gt;

&lt;p&gt;Now that we've worked out what a Reference Record is, we can move on to how it helps us determine the value of the &lt;code&gt;this&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;The point is that the main case where the value of &lt;code&gt;this&lt;/code&gt; depends on context is when we're dealing with a Reference, and the value we use is the Base field.&lt;/p&gt;

&lt;p&gt;To see how that works in practice, let's look at a few examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dasha&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;catName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The object's method is called through a dot, which means we have a Reference where Base equals &lt;code&gt;person&lt;/code&gt; and therefore &lt;code&gt;this&lt;/code&gt; equals &lt;code&gt;person&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCatName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCatName&lt;/span&gt;

&lt;span class="nf"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And what happens here? Calling the identifier &lt;code&gt;getCatName&lt;/code&gt; is also a Reference, but Base will be global, and therefore &lt;code&gt;this&lt;/code&gt; equals global.&lt;/p&gt;

&lt;p&gt;All of this follows from the spec's algorithm for calling a function. In the first example we passed the check at the first step, whose first sub-step (IsPropertyReference means we're calling a property of an object) leads to taking &lt;code&gt;this&lt;/code&gt; from Base.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffcsk7rtba66mst7p8wsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffcsk7rtba66mst7p8wsp.png" alt=" " width="799" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the second example we land in the second sub-step, since the value isn't a property reference, and Base is set to the Environment Record, which in this case is the global object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4idlt3tman5s2caafshx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4idlt3tman5s2caafshx.png" alt=" " width="799" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's look at a more complex, classic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;)();&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;)();&lt;/span&gt;
&lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first case the expression uses the grouping operator &lt;code&gt;()&lt;/code&gt;, which on its own doesn't affect the returned value, so the Reference type is preserved and the function returns &lt;code&gt;'Thomas'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the second case grouping is used as well, but with the &lt;code&gt;||&lt;/code&gt; operator added, which forces the expression to be evaluated and the Reference type to be lost, so &lt;code&gt;this&lt;/code&gt; becomes global. On top of that, in strict mode, trying to execute the line &lt;code&gt;this.catName&lt;/code&gt; gives an error, because &lt;code&gt;this&lt;/code&gt; will be &lt;code&gt;undefined&lt;/code&gt; and we're effectively reaching into &lt;code&gt;undefined.catName&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the third case an operator is used, but without the parentheses, so the result is a call to &lt;code&gt;person.getCatName()&lt;/code&gt; in dot notation with the Reference type intact, and the function returns &lt;code&gt;'Thomas'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This tells us that calling the same function in different ways can produce different values of &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Callbacks deserve a separate mention: there, the value of &lt;code&gt;this&lt;/code&gt; depends on the specific function the callback is passed to. That's especially true for external APIs like &lt;code&gt;addEventListener()&lt;/code&gt; or &lt;code&gt;setTimeout()&lt;/code&gt;, which are part of the HTML specification, where the value of &lt;code&gt;this&lt;/code&gt; is something you simply have to memorize rather than derive from the rules.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;this&lt;/code&gt; inside a click handler callback on &lt;code&gt;document&lt;/code&gt; returns &lt;code&gt;document&lt;/code&gt; itself — the element the listener is attached to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whereas inside &lt;code&gt;forEach&lt;/code&gt;, &lt;code&gt;this&lt;/code&gt; is already global:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Arrow functions
&lt;/h2&gt;

&lt;p&gt;Arrow functions are a case of their own when determining &lt;code&gt;this&lt;/code&gt;, because according to the specification they simply don't have one, they take it from the parent lexical environment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnvzud48quapyu6giqa6m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnvzud48quapyu6giqa6m.png" alt=" " width="800" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It follows that for arrow functions, the value of &lt;code&gt;this&lt;/code&gt; is fixed not when the function is called but when it's created. And that can lead to some unexpected results.&lt;/p&gt;

&lt;p&gt;Let's go through a few examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;catName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catName&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parent lexical environment for the arrow function &lt;code&gt;getCatName&lt;/code&gt; here is the outer global Environment Record. Since an object literal (creating an object directly with &lt;code&gt;{}&lt;/code&gt;) doesn't create a lexical environment of its own, the arrow function takes &lt;code&gt;this&lt;/code&gt; from wherever the &lt;code&gt;person&lt;/code&gt; object was created. So calling &lt;code&gt;person.getCatName()&lt;/code&gt; returns &lt;code&gt;undefined&lt;/code&gt;, or throws in strict mode.&lt;/p&gt;

&lt;p&gt;What if we wrap the arrow function call in a regular function?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;catName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catName&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;wrapperFoo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrapperFoo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing changes. &lt;code&gt;this&lt;/code&gt; for &lt;code&gt;getCatName()&lt;/code&gt; has already been set statically, and it doesn't matter how or where we call it.&lt;/p&gt;

&lt;p&gt;But if the arrow function is defined inside a regular function to begin with, then &lt;code&gt;this&lt;/code&gt; comes from that regular function, and calling &lt;code&gt;person.wrapperFoo2()&lt;/code&gt; returns &lt;code&gt;'Thomas'&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;catName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catName&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;wrapperFoo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;wrapperFoo2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrapperFoo2&lt;/span&gt;&lt;span class="p"&gt;()();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's an example that highlights the fact that &lt;code&gt;this&lt;/code&gt; is fixed when the function is created rather than when it's called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;catName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;wrapperFoo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrapperFoo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ‘Thomas’&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember how, when we were talking about the Reference type, we said this kind of assignment and calling a function without dot notation loses &lt;code&gt;this&lt;/code&gt;? For an arrow function that's not a problem, because the value of &lt;code&gt;this&lt;/code&gt; was already fixed at creation time and doesn't depend on how the function is called.&lt;/p&gt;

&lt;p&gt;That's exactly what makes arrow functions useful as callbacks, which, as mentioned above, can end up with all sorts of values for &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It also affects &lt;code&gt;bind()&lt;/code&gt;, &lt;code&gt;call()&lt;/code&gt;, and &lt;code&gt;apply()&lt;/code&gt;, which don't override &lt;code&gt;this&lt;/code&gt; for arrow functions. That's spelled out in the spec for these methods too:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpzhp8mgr19vowdvh87r9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpzhp8mgr19vowdvh87r9.png" alt=" " width="800" height="56"&gt;&lt;/a&gt;&lt;br&gt;
bind()&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft9uqyo6e95jifru6frfb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft9uqyo6e95jifru6frfb.png" alt=" " width="800" height="39"&gt;&lt;/a&gt;&lt;br&gt;
call() and apply()&lt;/p&gt;
&lt;h2&gt;
  
  
  Methods bind, call, apply
&lt;/h2&gt;

&lt;p&gt;These methods let you set &lt;code&gt;this&lt;/code&gt; explicitly when calling a function, passing it as the first argument. But &lt;code&gt;bind()&lt;/code&gt; occupies a special place among them, because it produces a &lt;strong&gt;bound function&lt;/strong&gt;. Its defining feature is a fixed &lt;code&gt;this&lt;/code&gt; value held in the BoundThis field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhpi8wvk8brfcmtp28nue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhpi8wvk8brfcmtp28nue.png" alt=" " width="800" height="154"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's look at an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;getOwnerName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ownerName&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ownerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;Dasha&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;boundGetOwnerName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getOwnerName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;boundGetOwnerName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By binding &lt;code&gt;owner&lt;/code&gt; as the first argument to &lt;code&gt;bind()&lt;/code&gt;, we set it as the value of &lt;code&gt;this&lt;/code&gt;, and it stays tied to that function regardless of how the function is called. Even if it's later called with &lt;code&gt;call()&lt;/code&gt; or &lt;code&gt;apply()&lt;/code&gt;, they can no longer override the &lt;code&gt;this&lt;/code&gt; that &lt;code&gt;bind()&lt;/code&gt; locked in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;anotherOwner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ownerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ilia&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;boundGetOwnerName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;anotherOwner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;boundGetOwnerName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;anotherOwner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This follows from the spec too, which says that when these methods are applied to a bound function, the &lt;code&gt;this&lt;/code&gt; argument is ignored:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwrda3nn2lld563we5qqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwrda3nn2lld563we5qqr.png" alt=" " width="800" height="42"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;call() and apply()&lt;/p&gt;

&lt;p&gt;So in our example the cat always stays attached to the original owner we tied it to. And even if we try to override &lt;code&gt;this&lt;/code&gt; with &lt;code&gt;bind()&lt;/code&gt; a second time, we won't manage it.&lt;/p&gt;

&lt;p&gt;There is one exception to this rule, though: the &lt;code&gt;this&lt;/code&gt; value passed to &lt;code&gt;bind()&lt;/code&gt; is ignored if the function is invoked with the &lt;code&gt;new&lt;/code&gt; operator. Per the spec, that's because the constructor path, [[Construct]], simply has no step where BoundThis is applied, unlike the ordinary [[Call]] path:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5opupxrfwrrw4occvzhr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5opupxrfwrrw4occvzhr.png" alt=" " width="799" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;new&lt;/code&gt; operator
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;new&lt;/code&gt;, everything looks straightforward at first glance: &lt;code&gt;this&lt;/code&gt; takes the value of the newly created object that the constructor returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newCat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;newCat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="c1"&gt;// ‘Thomas’&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or an empty object, if the function is just called with &lt;code&gt;new&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// {}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another example, with a class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;Thomas&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Thomas&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cat2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;Lesya&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;cat2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCatName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Lesya&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there's a subtlety hidden in the phrase "the object that is returned". If the function being called explicitly returns an object, that object becomes the result of &lt;code&gt;new&lt;/code&gt;, and the object created by the constructor is lost:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lesya&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newCat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;newCat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// ‘Lesya’, not ‘Thomas’&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's why. When &lt;code&gt;new Cat()&lt;/code&gt; is called, the engine runs the internal [[Construct]] method:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;ConstructorKind is checked, and if this is a base constructor (that is, no &lt;code&gt;extends&lt;/code&gt;), OrdinaryCreateFromConstructor is called. A new empty object is created and given &lt;code&gt;Cat.prototype&lt;/code&gt; as its prototype. That object is stored in &lt;code&gt;thisArgument&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OrdinaryCallBindThis takes the created object and binds it as &lt;code&gt;this&lt;/code&gt; inside the function body. From that point on, every reference to &lt;code&gt;this&lt;/code&gt; in the constructor body points at this new object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OrdinaryCallEvaluateBody executes the function's code. This is where &lt;code&gt;this.name = 'Thomas'&lt;/code&gt; fires, the property is written to the object from step 1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the function explicitly returned an object (&lt;code&gt;result.[[Value]]&lt;/code&gt; is an Object), that object becomes the result of &lt;code&gt;new&lt;/code&gt;. The object from step 1 is lost.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the function returned a primitive, or returned nothing, &lt;code&gt;thisArgument&lt;/code&gt; is returned, the object from step 1.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F96misev1cqnmywjo2277.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F96misev1cqnmywjo2277.png" alt=" " width="800" height="706"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's step 4 that explains the last example. An object is returned there, so step 4 fires and the &lt;code&gt;this.name = 'Thomas'&lt;/code&gt; from the constructor body is lost.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;super&lt;/code&gt; keyword. Two things are worth pointing out here.&lt;/p&gt;

&lt;p&gt;First: in a derived constructor you can't touch &lt;code&gt;this&lt;/code&gt; before &lt;code&gt;super()&lt;/code&gt; has been called, doing so throws an error.&lt;/p&gt;

&lt;p&gt;Second: even when we call a method through &lt;code&gt;super&lt;/code&gt;, say &lt;code&gt;super.getName()&lt;/code&gt;, &lt;code&gt;this&lt;/code&gt; inside it won't refer to the object &lt;code&gt;super&lt;/code&gt; points at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Parent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Parent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Name:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Parent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Child&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;testSuperMethod&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;testSuperMethod&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// "Name: Child", not “Name: Parent”&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So even when methods are called through &lt;code&gt;super&lt;/code&gt;, the &lt;code&gt;this&lt;/code&gt; context stays bound to the current object.&lt;/p&gt;

&lt;p&gt;And this brings us back to the Reference type, incidentally, because evaluating &lt;code&gt;super.getName()&lt;/code&gt; ultimately gives us a Reference with the ThisValue field set and Base holding the current object where &lt;code&gt;super&lt;/code&gt; was called:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq9huper9w23om3yipp3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq9huper9w23om3yipp3m.png" alt=" " width="800" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7b6jo8v59737fak6e0xh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7b6jo8v59737fak6e0xh.png" alt=" " width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's one more case worth covering separately. We've already seen that an arrow function in an object literal loses &lt;code&gt;this&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might expect classes to behave the same way. But they don't:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="nx"&gt;getName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getName&lt;/span&gt;
&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// 'Thomas' — this is not lost&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why? As we know, an object literal &lt;code&gt;{}&lt;/code&gt; doesn't create a lexical environment of its own, so the arrow function takes &lt;code&gt;this&lt;/code&gt; from outside. But properties declared directly in the class body — class fields — are initialized inside the constructor, where &lt;code&gt;this&lt;/code&gt; is already bound to the new instance. It's effectively equivalent to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thomas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The arrow function captures &lt;code&gt;this&lt;/code&gt; from the constructor and keeps it forever, like any other arrow function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Let's boil the whole article down to a short algorithm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Arrow function?&lt;/strong&gt; → &lt;code&gt;this&lt;/code&gt; is taken from the outer lexical environment at creation time. Ignores bind/call/apply, and can't be called with &lt;code&gt;new&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Called with &lt;code&gt;new&lt;/code&gt;?&lt;/strong&gt; → &lt;code&gt;this&lt;/code&gt; is the new object (unless the function explicitly returns a different object). Overrides bind.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Called through bind?&lt;/strong&gt; → &lt;code&gt;this&lt;/code&gt; is BoundThis. Not overridable via call/apply.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Called through call/apply?&lt;/strong&gt; → &lt;code&gt;this&lt;/code&gt; is the first argument.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Called through a dot or brackets?&lt;/strong&gt; → &lt;code&gt;this&lt;/code&gt; is the object to the left of the dot. Exception: &lt;code&gt;super.method()&lt;/code&gt;, where &lt;code&gt;this&lt;/code&gt; stays the current object rather than the prototype.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Everything else&lt;/strong&gt; → &lt;code&gt;this&lt;/code&gt; is global (or &lt;code&gt;undefined&lt;/code&gt; in strict mode).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. We've covered all the main cases and some of the edge cases for determining &lt;code&gt;this&lt;/code&gt;, working from the operations described in the ECMAScript specification, which should help build a more fundamental understanding of the topic, and with it, help solve concrete problems in practice.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Optimizing Images for Users on Slow Connections with the Network Information API</title>
      <dc:creator>Ilia</dc:creator>
      <pubDate>Thu, 30 Jul 2026 17:04:07 +0000</pubDate>
      <link>https://dev.to/sadiolem/optimizing-images-for-users-on-slow-connections-with-the-network-information-api-3o4j</link>
      <guid>https://dev.to/sadiolem/optimizing-images-for-users-on-slow-connections-with-the-network-information-api-3o4j</guid>
      <description>&lt;p&gt;Most of us are used to treating fast, stable internet as a given. But there are still scenarios where it isn't: on the road between towns or inside buildings that block the signal for one reason or another.&lt;/p&gt;

&lt;p&gt;In this article I'll look at one optimization technique that uses the Network Information API. It's an API with a large set of information about the connection, though browser support isn't great yet. That's not a reason to skip it for users whose browsers do support it — roughly 76% of users globally. The code examples are in Vue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The image component and imagekit
&lt;/h2&gt;

&lt;p&gt;I'll start with some background. Our project has an &lt;code&gt;AppImage&lt;/code&gt; component responsible for all images, and we host them with imagekit.io. Leaving out the details that don't matter here, a simplified &lt;code&gt;AppImage&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMedia&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/composables/media.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;imgId&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;withDefaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defineProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;imgId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getImageById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMedia&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;srcAttrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getImageById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imgId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;srcset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;getImageById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imgId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; 2x`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
    &lt;span class="na"&gt;v-bind=&lt;/span&gt;&lt;span class="s"&gt;"srcAttrs"&lt;/span&gt;
    &lt;span class="na"&gt;:height=&lt;/span&gt;&lt;span class="s"&gt;"height"&lt;/span&gt;
    &lt;span class="na"&gt;:width=&lt;/span&gt;&lt;span class="s"&gt;"width"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It contains a &lt;code&gt;getImageById&lt;/code&gt; function that hits imagekit with the image id and the &lt;code&gt;w&lt;/code&gt; and &lt;code&gt;h&lt;/code&gt; parameters to request that image at particular dimensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getImageById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`?tr=w-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`,h-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service also has a &lt;code&gt;q&lt;/code&gt; parameter, which takes values from 1 to 100 and controls the quality of the returned image. Here, for example, are two images at &lt;code&gt;q=90&lt;/code&gt; and &lt;code&gt;q=20&lt;/code&gt;, weighing 31 KB and 3 KB respectively:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fse1runsswmivobwqyhzy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fse1runsswmivobwqyhzy.png" alt=" " width="799" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's the parameter I'll be changing based on the user's connection speed. If you don't use a service like this, it'll be more work, but you can still prepare images at different quality levels separately and swap them in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using effectiveType to detect connection speed
&lt;/h2&gt;

&lt;p&gt;We need a service that tracks connection information and changes image quality in response. Let's call it &lt;code&gt;handleNetwork&lt;/code&gt; and declare the variables we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imagesQuality&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isSlowConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// we will use it later&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleNetwork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;imagesQuality&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default value for &lt;code&gt;imagesQuality&lt;/code&gt; is set to maximum quality. We'll only degrade on an explicit signal.&lt;/p&gt;

&lt;p&gt;The Network Information API gives us the &lt;code&gt;effectiveType&lt;/code&gt; property, available via &lt;code&gt;navigator.connection.effectiveType&lt;/code&gt;. It can take several values — &lt;code&gt;slow-2g&lt;/code&gt;, &lt;code&gt;2g&lt;/code&gt;, &lt;code&gt;3g&lt;/code&gt;, &lt;code&gt;4g&lt;/code&gt; — each corresponding to a particular connection speed, even when the user is on wifi or a wired connection. Here's a table with a short explanation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj7syddwxdlzer43yz1qz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj7syddwxdlzer43yz1qz.png" alt=" " width="799" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are the values we'll key off when changing &lt;code&gt;imagesQuality&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To initialize and track changes to &lt;code&gt;effectiveType&lt;/code&gt;, we need to add a listener for the &lt;code&gt;change&lt;/code&gt; event on &lt;code&gt;navigator.connection&lt;/code&gt;, plus an &lt;code&gt;updateNetworkState&lt;/code&gt; function to handle the updates.&lt;/p&gt;

&lt;p&gt;Important: always check that the browser supports the API, with a simple &lt;code&gt;'connection' in navigator&lt;/code&gt; check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateNetworkState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;updateNetworkState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateNetworkState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's write &lt;code&gt;updateNetworkState&lt;/code&gt;. It's just the &lt;code&gt;switch&lt;/code&gt; that sets &lt;code&gt;imagesQuality&lt;/code&gt; — the support check is already done above, at the only place this function is called from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateNetworkState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;effectiveType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slow-2g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
      &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Changing image quality
&lt;/h2&gt;

&lt;p&gt;Back to &lt;code&gt;AppImage&lt;/code&gt;: we import our service and do two things.&lt;/p&gt;

&lt;p&gt;1) Pass the &lt;code&gt;quality&lt;/code&gt; variable as a new parameter to &lt;code&gt;getImageById&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;2) If &lt;code&gt;imagesQuality&lt;/code&gt; is below 20, drop the &lt;code&gt;srcset&lt;/code&gt; attribute holding the 2x image — on a slow connection there's no point downloading higher-resolution images&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;imagesQuality&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;handleNetwork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;srcAttrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getImageById&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;srcset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;getImageById&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; 2x`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One detail matters here: &lt;code&gt;handleNetwork&lt;/code&gt; is called at setup level rather than inside the &lt;code&gt;computed&lt;/code&gt;, and the value is read out of &lt;code&gt;imagesQuality&lt;/code&gt; once.&lt;/p&gt;

&lt;p&gt;If you call the service inside the &lt;code&gt;computed&lt;/code&gt;, or put &lt;code&gt;imagesQuality.value&lt;/code&gt; in there, then when the connection degrades, &lt;code&gt;src&lt;/code&gt; recalculates for every image already on screen. A different &lt;code&gt;q&lt;/code&gt; means a different URL: the browser fires a batch of fresh requests over the connection that just got worse, to replace images that are already downloaded and already visible. You end up with an optimization that makes things worse at exactly the moment the connection slows down.&lt;/p&gt;

&lt;p&gt;The updated &lt;code&gt;getImageById&lt;/code&gt; with a &lt;code&gt;quality&lt;/code&gt; parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getImageById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`?tr=q-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,w-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`,h-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. You can check it in the Network tab of your dev tools: switch the profile to 3G and then, say, go to the next page of pagination — the new images come down at reduced quality, while the ones already rendered stay put and aren't requested again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F74hzs8fcmeye0d46fp2v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F74hzs8fcmeye0d46fp2v.png" alt=" " width="799" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing background-image
&lt;/h2&gt;

&lt;p&gt;The next opportunity is turning off background images set through CSS. Background images are usually purely decorative and carry no valuable information, so on a slow connection they can be sacrificed and skipped in favor of a solid color.&lt;/p&gt;

&lt;p&gt;For that we'll use the &lt;code&gt;isSlowConnection&lt;/code&gt; flag we declared at the very beginning. We extend the &lt;code&gt;switch&lt;/code&gt; so it changes this variable alongside image quality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;effectiveType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slow-2g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nx"&gt;isSlowConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
    &lt;span class="nx"&gt;isSlowConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
    &lt;span class="nx"&gt;isSlowConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And below that we add a class toggle on &lt;code&gt;body&lt;/code&gt; — you can name the class whatever you like, but it's better to use a distinctive prefix to avoid style conflicts — which lets us target the right styles with a CSS selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateNetworkState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;effectiveType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slow-2g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="nx"&gt;isSlowConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
      &lt;span class="nx"&gt;isSlowConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;imagesQuality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
      &lt;span class="nx"&gt;isSlowConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cs-slow-connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSlowConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For instance, we have a background image on the competition page. Let's write styles so that when the &lt;code&gt;cs-slow-connection&lt;/code&gt; class is present, the background image is replaced with a solid fill in a similar color:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.event-header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;::before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("/img/event-default-img.webp")&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.cs-slow-connection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.event-header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;::before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#e4e4e4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpc216dx5wp9ysb7xh9tr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpc216dx5wp9ysb7xh9tr.png" alt=" " width="799" height="295"&gt;&lt;/a&gt;&lt;br&gt;
4g&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz6qvrsc91nbvbobe04v5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz6qvrsc91nbvbobe04v5.png" alt=" " width="799" height="295"&gt;&lt;/a&gt;&lt;br&gt;
slow 3g&lt;/p&gt;

&lt;p&gt;In the second case there's no image request at all, which takes at least some of the load off an already struggling connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other possibilities
&lt;/h2&gt;

&lt;p&gt;I've shown just two examples of using the Network Information API to optimize images, but the possibilities go much further. You can load placeholders instead of video, skip images entirely on 2g, try not to load non-essential fonts, even swap out or drop whole components — and so on.&lt;/p&gt;

&lt;p&gt;But I hope these examples at least sparked some interest in this API, and drew attention to the problems that come with a bad connection.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
