<?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>Forem: Felix Gerschau</title>
    <description>The latest articles on Forem by Felix Gerschau (@fgerschau).</description>
    <link>https://forem.com/fgerschau</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F236851%2F626f1a80-d3f7-4f4b-a538-222d7880231a.png</url>
      <title>Forem: Felix Gerschau</title>
      <link>https://forem.com/fgerschau</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/fgerschau"/>
    <language>en</language>
    <item>
      <title>JavaScript Event Loop And Call Stack Explained</title>
      <dc:creator>Felix Gerschau</dc:creator>
      <pubDate>Mon, 05 Oct 2020 09:36:45 +0000</pubDate>
      <link>https://forem.com/fgerschau/javascript-event-loop-and-call-stack-explained-1mfk</link>
      <guid>https://forem.com/fgerschau/javascript-event-loop-and-call-stack-explained-1mfk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on my blog: &lt;a href="https://felixgerschau.com/javascript-event-loop-call-stack/"&gt;JavaScript Event Loop And Call Stack Explained&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My goal with this article is to teach you how JavaScript works in the browser. Even though I've been working with JavaScript my whole career, I didn't get how these things work until recently.&lt;/p&gt;

&lt;p&gt;I still forget how this works from time to time. That's why I wrote this article. I hope it will make you understand these concepts as well.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to make this article as easy to understand as possible. If you have any open questions, please send me an &lt;a href="//mailto:me@felixgerschau.com"&gt;email&lt;/a&gt; or leave a comment. I will try to help you and improve the article with your feedback.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How JavaScript works in the browser
&lt;/h2&gt;

&lt;p&gt;Before I dive into the explanation of each topic, I want you to have a look at this &lt;strong&gt;high-level overview&lt;/strong&gt; that I created, which is an abstraction of how JavaScript interacts with the browser.&lt;/p&gt;

&lt;p&gt;Don't worry if you don't know what all of the terms mean. I will cover each of them in this section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UafWWVA4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://felixgerschau.com/images/content/event-loop/js-event-loop-explained.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UafWWVA4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://felixgerschau.com/images/content/event-loop/js-event-loop-explained.png" alt="High level overview of how JavaScript works in the browser"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note how most of the things in the graphic aren't part of the JavaScript language itself. Web APIs, the callback queue, and the event loop are all features that the browser provides.&lt;/p&gt;

&lt;p&gt;A representation of NodeJS would look similar, but in this article, I'll focus on how JavaScript works in the browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Call stack
&lt;/h3&gt;

&lt;p&gt;You've probably already heard that JavaScript is single-threaded. But what does this mean?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript can do one single thing at a time&lt;/strong&gt; because it has only one call stack.&lt;/p&gt;

&lt;p&gt;The call stack is a mechanism that helps the JavaScript interpreter to &lt;strong&gt;keep track of the functions that a script calls&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every time a script or function &lt;strong&gt;calls&lt;/strong&gt; a function, it's &lt;strong&gt;added to the top of the call stack&lt;/strong&gt;.&lt;br&gt;
Every time the function &lt;strong&gt;exits&lt;/strong&gt;, the interpreter &lt;strong&gt;removes it from the call stack&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A function either exits through a return statement or by reaching the end of the scope.&lt;/p&gt;

&lt;p&gt;Every time a function calls another function, it's added to the top of the stack, on top of the calling function.&lt;/p&gt;

&lt;p&gt;The order in which the &lt;em&gt;stack&lt;/em&gt; processes each function call is following the LIFO principle (Last In, First Out).&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/fgerschau/embed/Vwagxoq?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The steps of the previous example are the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The file loads and the &lt;code&gt;main&lt;/code&gt; function is being called, which stands for the execution of the entire file. This function is &lt;strong&gt;added&lt;/strong&gt; to the call stack.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main&lt;/code&gt; calls &lt;code&gt;calculation()&lt;/code&gt;, which is why it is &lt;strong&gt;added&lt;/strong&gt; to the top of the call stack.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;calculation()&lt;/code&gt; calls &lt;code&gt;addThree()&lt;/code&gt;, which again is &lt;strong&gt;added&lt;/strong&gt; to the call stack.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;addThree&lt;/code&gt; calls &lt;code&gt;addTwo&lt;/code&gt;, which is &lt;strong&gt;added&lt;/strong&gt; to the call stack.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;addOne&lt;/code&gt; doesn't call any other functions. When it exits, it is &lt;strong&gt;removed&lt;/strong&gt; from the call stack.&lt;/li&gt;
&lt;li&gt;With the result of &lt;code&gt;addOne&lt;/code&gt;, &lt;code&gt;addTwo&lt;/code&gt; exits as well and is being &lt;strong&gt;removed&lt;/strong&gt; from the call stack.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;addThree&lt;/code&gt; is being &lt;strong&gt;removed&lt;/strong&gt; as well.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;calculation&lt;/code&gt; calls &lt;code&gt;addTwo&lt;/code&gt;, which &lt;strong&gt;adds&lt;/strong&gt; it to the call stack.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;addTwo&lt;/code&gt; calls &lt;code&gt;addOne&lt;/code&gt; and &lt;strong&gt;adds&lt;/strong&gt; it to the call stack.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;addOne&lt;/code&gt; exits and is being &lt;strong&gt;removed&lt;/strong&gt; from the call stack.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;addTwo&lt;/code&gt; exits and is being &lt;strong&gt;removed&lt;/strong&gt; from the call stack.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;calculation&lt;/code&gt; can exit now with the result of &lt;code&gt;addThree&lt;/code&gt; and &lt;code&gt;addTwo&lt;/code&gt; and is being &lt;strong&gt;removed&lt;/strong&gt; from the call stack.&lt;/li&gt;
&lt;li&gt;There are no further statements or function calls in the file, so &lt;code&gt;main&lt;/code&gt; exits as well and is being &lt;strong&gt;removed&lt;/strong&gt; from the call stack.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;I called the context that executes our code &lt;code&gt;main&lt;/code&gt;, but this is not how the official name of the function. In the error messages that you can find in the browser's console, the name of this function is &lt;code&gt;anonymous&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Uncaught RangeError: Maximum call stack size exceeded
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Eas3FFZu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://felixgerschau.com/images/content/event-loop/maximum-call-stack-error.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Eas3FFZu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://felixgerschau.com/images/content/event-loop/maximum-call-stack-error.png" alt="Maximum call stack error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You probably know the call stack from debugging your code. &lt;code&gt;Uncaught RangeError: Maximum call stack size exceeded&lt;/code&gt; is one of the errors you might encounter. Below we can see a snapshot of the callstack when the error occured.&lt;/p&gt;

&lt;p&gt;Follow the stack trace of this error message. It represents the functions calls that led to this error. In this case, the error was in the function b, which has been called by a (which has been called by b and so on).&lt;/p&gt;

&lt;p&gt;If you see this specific error message on your screen, &lt;strong&gt;one of your function has called too many functions&lt;/strong&gt;. The maximum call stack size ranges from &lt;a href="https://2ality.com/2014/04/call-stack-size.html"&gt;10 to 50 thousand calls&lt;/a&gt;, so if you exceed that, it's most likely that you have an infinite loop in your code.&lt;/p&gt;

&lt;p&gt;The browser prevents your code from freezing the whole page by limiting the call stack.&lt;/p&gt;

&lt;p&gt;I re-created the error with the following code. A way to prevent this is by either not using recursive functions in the first place, or by providing a base case, which makes your function exit at some point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In summary, the call stack keeps track of the function calls in your code. It follows the &lt;em&gt;LIFO&lt;/em&gt; principle (Last In, First Out), which means it always processes the call that is on top of the stack first.&lt;/p&gt;

&lt;p&gt;JavaScript only has one call stack, which is why it can only do one thing at a time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Heap
&lt;/h3&gt;

&lt;p&gt;The JavaScript heap is &lt;strong&gt;where objects are stored&lt;/strong&gt; when we define functions or variables.&lt;/p&gt;

&lt;p&gt;Since it doesn't affect the call stack and the event loop, it would be out of the scope of this article to explain how JavaScript's memory allocation works.&lt;/p&gt;

&lt;p&gt;I plan to write a blog post on this topic. If you haven't already, make sure to &lt;a href="https://felixgerschau.substack.com/"&gt;subscribe to my newsletter&lt;/a&gt; to get notified when it's out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web APIs
&lt;/h3&gt;

&lt;p&gt;Above, I said that JavaScript can only do one thing at a time.&lt;/p&gt;

&lt;p&gt;While this is true for the JavaScript language itself, you can still &lt;strong&gt;do things concurrently in the browser&lt;/strong&gt;. As the title already suggests, this is possible through the APIs that browsers provide.&lt;/p&gt;

&lt;p&gt;Let's take a look at how we make an API request, for instance. If we executed the code within the JavaScript interpreter, we wouldn't be able to do anything else until we get a response from the server.&lt;/p&gt;

&lt;p&gt;It would pretty much make web applications unusable.&lt;/p&gt;

&lt;p&gt;As a solution to this, web browsers give us APIs that we can call in our JavaScript code. The execution, however, is handled &lt;strong&gt;by the platform itself&lt;/strong&gt;, which is why &lt;strong&gt;it won't block the call stack&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Another advantage of web APIs is that they are written in &lt;strong&gt;lower-level code&lt;/strong&gt; (like C), which allows them to do things that simply aren't possible in plain JavaScript.&lt;/p&gt;

&lt;p&gt;They enable you to make AJAX requests or manipulate the DOM, but also a range of other things, like geo-tracking, accessing local storage, service workers, and more.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're interested in what new APIs we can expect to surface in the future, check out &lt;a href="https://felixgerschau.com/web-capabilities-project-fugu-google/"&gt;my article on project Fugu&lt;/a&gt;, a cross-company effort, brought to life by Google, that intents to bring more native features to the web platform.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Callback queue
&lt;/h3&gt;

&lt;p&gt;With the features of web APIs, we're now able to do things concurrently outside of the JavaScript interpreter. But what happens if we want our JavaScript code to react to the result of a Web API, like an AJAX request for instance?&lt;/p&gt;

&lt;p&gt;That's where callbacks come into play. Through them, web APIs allow us to &lt;strong&gt;run code after the execution of the API call&lt;/strong&gt; has finished.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  What is a callback?
&lt;/h4&gt;

&lt;p&gt;A callback is a function that's passed as an argument to another function. The callback will usually be executed &lt;em&gt;after&lt;/em&gt; the code has finished.&lt;/p&gt;

&lt;p&gt;You can create callback functions yourself by writing functions that accept a function as an argument. Functions like that are also known as &lt;em&gt;higher-order functions&lt;/em&gt;. Note that callbacks aren't by default asynchronous.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;div class="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;a&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;a&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;b&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="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;100&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;c&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;setTimeout&lt;/code&gt; adds a timeout of x ms before the callback will be executed.&lt;/p&gt;

&lt;p&gt;You can probably already think of what the output will look like.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;setTimeout&lt;/code&gt; is being executed concurrently while the JS interpreter continues to execute the next statements.&lt;/p&gt;

&lt;p&gt;When the timeout has passed &lt;em&gt;and&lt;/em&gt; the call stack is empty again, the callback function that has been passed to &lt;code&gt;setTimeout&lt;/code&gt; will be executed.&lt;/p&gt;

&lt;p&gt;The final output will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;a
c
b
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  But what about the callback queue?
&lt;/h5&gt;

&lt;p&gt;Now, after &lt;code&gt;setTimeout&lt;/code&gt; finishes its execution, it doesn't immediately call the callback function. But why's that?&lt;/p&gt;

&lt;p&gt;Remember that JavaScript can only do one thing at a time?&lt;/p&gt;

&lt;p&gt;The callback we passed as an argument to &lt;code&gt;setTimeout&lt;/code&gt; &lt;strong&gt;is written in JavaScript&lt;/strong&gt;. Thus, the JavaScript interpreter needs to run the code, which means that it needs to use the call stack, which again means that we have to &lt;strong&gt;wait until the call stack is empty&lt;/strong&gt; in order to execute the callback.&lt;/p&gt;

&lt;p&gt;You can observe this behavior in the following animation, which is visualizing the execution of the code we saw above.&lt;/p&gt;

&lt;p&gt;Calling &lt;code&gt;setTimeout&lt;/code&gt; triggers the execution of &lt;strong&gt;the web API, which adds the callback to the callback queue&lt;/strong&gt;.&lt;br&gt;
The event loop then takes the callback from the queue and adds it to the stack as soon as it's empty.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Jk5Be0Z5y4I"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Multiple things are going on here at the same time. Follow the path that the execution of &lt;code&gt;setTimeout&lt;/code&gt; takes, and in another run, focus on what the call stack does.&lt;/p&gt;

&lt;p&gt;Unlike the call &lt;em&gt;stack&lt;/em&gt;, the callback queue follows the FIFO order (First In, First Out), meaning that the calls are processed in the same order they've been added to the queue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event loop
&lt;/h3&gt;

&lt;p&gt;The JavaScript event loop takes the first call in the callback queue and adds it to the call stack as soon as it's empty.&lt;/p&gt;

&lt;p&gt;JavaScript code is being run in a run-to-completion manner, meaning that if the call stack is currently executing some code, the event loop is blocked and &lt;strong&gt;won't add any calls from the queue until the stack is empty again&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's why it's important not to block the call stack by running computation-intensive tasks.&lt;/p&gt;

&lt;p&gt;If you execute too much code or clog up your callback queue, your website will become unresponsive, because it's not able to execute any new JavaScript code.&lt;/p&gt;

&lt;p&gt;Event handlers, like &lt;code&gt;onscroll&lt;/code&gt;, add more tasks to the callback queue when triggered. That's why you should debounce these callbacks, meaning they will only be executed every x ms.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  See it for yourself
&lt;/h4&gt;

&lt;p&gt;Add the following code to your browser console. As you scroll, you can observe how often the callback prints &lt;code&gt;scroll&lt;/code&gt;.&lt;/p&gt;


&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onscroll&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  setTimeout(fn, 0) or setImmediate()
&lt;/h4&gt;

&lt;p&gt;We can take the above-described behavior to our advantage if we want to execute some tasks &lt;strong&gt;without blocking the main thread&lt;/strong&gt; for too long.&lt;/p&gt;

&lt;p&gt;Putting your asynchronous code in a callback and setting &lt;code&gt;setTimeout&lt;/code&gt; to 0ms will allow the browser to do things like updating the DOM before continuing with the execution of the callback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Job queue and asynchronous code
&lt;/h3&gt;

&lt;p&gt;In the overview that I showed in the beginning, I was leaving out one additional feature that's important to know.&lt;/p&gt;

&lt;p&gt;In addition to the callback queue, there's another &lt;strong&gt;queue that exclusively accepts promises&lt;/strong&gt;‚Äîthe &lt;strong&gt;job queue&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Promises: A quick recap
&lt;/h4&gt;

&lt;p&gt;EcmaScript 2015 (or ES6) first introduced promises, even though it has been available before in Babel.&lt;/p&gt;

&lt;p&gt;Promises are another way of handling asynchronous code, other than using callbacks. They allow you to easily chain asynchronous functions without ending up in what's called &lt;em&gt;callback hell&lt;/em&gt; or &lt;em&gt;pyramid of doom&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;setTimeout&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;Print this and wait&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;setTimeout&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;Do something else and wait&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setTimeout&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="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With a but of imagination, you can see how chaining callbacks can end up in a &lt;em&gt;pyramid of doom&lt;/em&gt;‚Äîor straight ugly code.&lt;/p&gt;

&lt;p&gt;With promises, this code can become much more readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// A promise wrapper for setTimeout&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&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;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;Hi after 1 second&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&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;then&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;Hi after 2 seconds&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code looks even more readable with the &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;logDelayedMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&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;await&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&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="nx"&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;Hi after 1 second&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&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="nx"&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;Hi after 2 seconds&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;logDelayedMessages&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;That was a quick recap on how promises work, but in this article, I won't dive deeper into this topic.&lt;br&gt;
Check out the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"&gt;MDN web docs&lt;/a&gt; in case you want to learn more about them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Where do promises fit in?
&lt;/h4&gt;

&lt;p&gt;Why am I talking about promises here?&lt;/p&gt;

&lt;p&gt;Having the bigger picture in mind, promises behave a little differently than callbacks because &lt;strong&gt;they have their own queue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;job queue&lt;/strong&gt;, also known as the promise queue, &lt;strong&gt;has priority over the callback queue&lt;/strong&gt;, just like a fast-track queue at an amusement park.&lt;/p&gt;

&lt;p&gt;The event loop will take calls from the promise queue first, before processing the callback queue.&lt;/p&gt;

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

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="nx"&gt;resolve&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;then&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;c&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Taking into consideration your knowledge about how callback queues are working, you might think that the output will be &lt;code&gt;a d b c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But because the &lt;strong&gt;promise queue has priority over the callback queue&lt;/strong&gt;, &lt;code&gt;c&lt;/code&gt; will be printed before &lt;code&gt;b&lt;/code&gt;, even though both are asynchronous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;a
d
c
b
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



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

&lt;p&gt;I hope you now have a better understanding of what is happening behind the scenes of your JavaScript code. As I already mentioned in the beginning, if you have any questions or feedback please leave a comment.&lt;/p&gt;

&lt;p&gt;I've learned this stuff on the internet as well, here are the resources that have helped me grasp this topic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/8aGhZQkoFbQ"&gt;What the heck is the event loop anyway? | Philip Roberts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best talk/video out there on this topic. I highly recommend you check it out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop"&gt;Concurrency model and the event loop - MDN Web Docs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://latentflip.com/loupe"&gt;JavaScript visualizer&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A tools that lets you visualize how your code is being executed.&lt;/p&gt;

&lt;p&gt;More artiles you might be interested in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/pragmatic-programmer-20th-anniversary-favorite-topic-summary/"&gt;My 9 favorite topics of "The Pragmatic Programmer"&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reading is a great way of improving your programming skills. In this article, I share my key-takeaways of my favorite programming book.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/how-to-make-your-react-app-a-progressive-web-app-pwa/"&gt;How to Make your React App a Progressive Web App (PWA)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A full walk-through of how you can make your React app a &lt;em&gt;Progressive&lt;/em&gt; Web App (it's easier than it sounds).&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Measuring the Performance of JavaScript Functions</title>
      <dc:creator>Felix Gerschau</dc:creator>
      <pubDate>Sun, 03 May 2020 10:20:04 +0000</pubDate>
      <link>https://forem.com/fgerschau/measuring-the-performance-of-javascript-functions-h6m</link>
      <guid>https://forem.com/fgerschau/measuring-the-performance-of-javascript-functions-h6m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post was &lt;a href="https://felixgerschau.com/measuring-the-performance-of-java-script-functions"&gt;first published on my blog&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Measuring the time it takes to execute a function is always a good idea to &lt;strong&gt;prove&lt;/strong&gt; that some implementation is more performant than the other. It's also a good way to ensure that performance didn't suffer after some change and to track down bottlenecks.&lt;/p&gt;

&lt;p&gt;Good performance contributes to good user experience. And a good user experience makes users come back. Like &lt;a href="http://www.mcrinc.com/Documents/Newsletters/201110_why_web_performance_matters.pdf"&gt;this research&lt;/a&gt; for example shows, &lt;strong&gt;88% of online consumers&lt;/strong&gt; are less likely to return after a poor user experience due to performance issues.&lt;/p&gt;

&lt;p&gt;That's why it's important to be able to recognize bottlenecks in your code and measure the improvements. Especially when developing JavaScript for the browser it's important to be aware that every line of JavaScript you write can potentially block the DOM since it's a single-threaded language.&lt;/p&gt;

&lt;p&gt;In this article, I will explain how you can measure the performance of your functions and what to do with the results, you get from them.&lt;/p&gt;

&lt;p&gt;The functions I mention here are good for debugging JavaScript functions at a low level. If you want to make sure that your application stays fast, even after more features get added, consider the implementation of a &lt;a href="https://felixgerschau.com/getting-into-performance-budgets"&gt;performance budget&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perfomance.now
&lt;/h2&gt;

&lt;p&gt;The performance API provides access to the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp"&gt;DOMHighResTimeStamp&lt;/a&gt; through its function &lt;code&gt;performance.now()&lt;/code&gt;, which returns the time passed since the page loaded in milliseconds, with a precision of up to &lt;strong&gt;5µs&lt;/strong&gt; (in the fractional).&lt;/p&gt;

&lt;p&gt;So in practice you need to take two timestamps, save them in a variable and then rest the second from the first one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;t0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// some code&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;t1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;milliseconds&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Output (Chrome):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;0.6350000001020817 "milliseconds"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Output (Firefox):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;1 milliseconds
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we can see that the result in Firefox is quite different to Chrome. This is because Firefox, as of version 60, is reducing the precision of the performance API to 2ms. You can find more information about this at the end of this post.&lt;/p&gt;

&lt;p&gt;The performance API offers much more functionality than only returning a timestamp. It's able to measure &lt;em&gt;navigation timing, user timing or resource timing&lt;/em&gt;.&lt;br&gt;
Check &lt;a href="https://blog.logrocket.com/how-to-practically-use-performance-api-to-measure-performance/"&gt;this article&lt;/a&gt; out which explains it more in detail.&lt;/p&gt;

&lt;p&gt;For our use-case, however, we only want to measure the performance of a single function so a timestamp will be enough.&lt;/p&gt;
&lt;h5&gt;
  
  
  Isn't that the same as Date.now?
&lt;/h5&gt;

&lt;p&gt;Now you could think, hey, I could also use &lt;code&gt;Date.now&lt;/code&gt; for that.&lt;/p&gt;

&lt;p&gt;Yes you can, but that has drawbacks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Date.now&lt;/code&gt; returns, in &lt;em&gt;milliseconds&lt;/em&gt;, the time passed since the Unix epoch ("1970-01-01T00:00:00Z") and depends on the system clock. This doesn't only mean that it's &lt;strong&gt;not as precise&lt;/strong&gt;, but it's also &lt;strong&gt;not always incrementing&lt;/strong&gt;. Here's how a WebKit engineer (Tony Gentilcore) explains it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Perhaps less often considered is that Date, based on system time, isn't ideal for real user monitoring either. Most systems run a daemon which regularly synchronizes the time. It is common for the clock to be tweaked a few milliseconds every 15-20 minutes. At that rate about 1% of 10 second intervals measured would be inaccurate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Console.time
&lt;/h2&gt;

&lt;p&gt;This API is really easy to use. Simply put &lt;code&gt;console.time&lt;/code&gt; before and &lt;code&gt;console.timeEnd&lt;/code&gt; after the code you want to measure, calling the function with the same &lt;code&gt;string&lt;/code&gt; argument. You can use up to 10,000 timers simultaneously on one page.&lt;/p&gt;

&lt;p&gt;The precision is the same as of the performance API but this again depends on the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// some code&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="nx"&gt;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This automatically generates a human-readable output like the following:&lt;/p&gt;

&lt;p&gt;Output (Chrome):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;test: 0.766845703125ms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Output (Firefox):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;test: 2ms - timer ended
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The outputs here are again very similar to the performance API.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;console.time&lt;/code&gt; has the advantage that it is &lt;strong&gt;easier to use&lt;/strong&gt; since it doesn't require calculating the difference between two timestamps manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reduced Time Precision
&lt;/h2&gt;

&lt;p&gt;If you measure your function with the APIs mentioned above in different browsers you might notice that the &lt;strong&gt;results vary&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is due to browsers trying to &lt;strong&gt;protect users&lt;/strong&gt; against &lt;a href="https://en.wikipedia.org/wiki/Timing_attack"&gt;timing attacks&lt;/a&gt; and &lt;a href="https://pixelprivacy.com/resources/browser-fingerprinting/"&gt;fingerprinting&lt;/a&gt;,&lt;br&gt;
which can be used by hackers to identify users if the timestamp is too accurate.&lt;/p&gt;

&lt;p&gt;Browsers like Firefox, for example, try to prevent this by &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp"&gt;reducing the precision&lt;/a&gt; to 2ms (version 60).&lt;/p&gt;
&lt;h2&gt;
  
  
  Things to Keep in Mind
&lt;/h2&gt;

&lt;p&gt;Now you have the tools you need to measure how fast your JavaScript functions are. But there are some pitfalls that are better to be avoided:&lt;/p&gt;
&lt;h3&gt;
  
  
  Divide and Conquer
&lt;/h3&gt;

&lt;p&gt;You noticed something is slow when filtering some results but you don't know where the bottleneck is.&lt;/p&gt;

&lt;p&gt;Instead of making wild guesses what part of the code is slow, you can use these above-mentioned functions to measure it.&lt;/p&gt;

&lt;p&gt;To trace it down first place your &lt;code&gt;console.time&lt;/code&gt; statements around the block of code that is slow. Then measure how different parts of them perform. If one is slower than the others, continue there and go deeper every time until you find the bottleneck.&lt;/p&gt;

&lt;p&gt;The less code you have between those statements, the less likely it is that you're tracking something you're not interested in.&lt;/p&gt;
&lt;h3&gt;
  
  
  Be Aware of the Input Values
&lt;/h3&gt;

&lt;p&gt;In a real-world application, the input values of a given function can change a lot. Just measuring the speed of the function for any random value doesn't give us &lt;em&gt;any&lt;/em&gt; valuable data we can actually use.&lt;/p&gt;

&lt;p&gt;Be sure to run your code with the same input values.&lt;/p&gt;
&lt;h3&gt;
  
  
  Run the Function Multiple Times
&lt;/h3&gt;

&lt;p&gt;Let's say you have a function that iterates over an array, does some calculations with each of its values and returns an array with the results. You want to find out whether &lt;code&gt;forEach&lt;/code&gt; or a simple &lt;code&gt;for&lt;/code&gt; loop is more performant.&lt;/p&gt;

&lt;p&gt;Those are the functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;testForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&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="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-forEach&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&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="nx"&gt;index&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&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="mf"&gt;1.2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.1&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="nx"&gt;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-forEach&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;testFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&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="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-for&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.1&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="nx"&gt;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-for&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&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;And you test them like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;testForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;testFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you run the above functions in Firefox you'll get an output similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;test-forEach: 27ms - timer ended
test-for: 3ms - timer ended
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Looks like forEach is way slower, right?&lt;/p&gt;

&lt;p&gt;Let's have a look if we run the same functions twice, using the same input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;testForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;testForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;testFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;testFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;test-forEach: 13ms - timer ended
test-forEach: 2ms - timer ended
test-for: 1ms - timer ended
test-for: 3ms - timer ended
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If we call the &lt;code&gt;forEach&lt;/code&gt; test a second time it performs just as well as the &lt;code&gt;for&lt;/code&gt; loop. It's probably not worth using &lt;code&gt;forEach&lt;/code&gt; anyway, given the slower initial value.&lt;/p&gt;

&lt;h3&gt;
  
  
  ...and in multiple browsers
&lt;/h3&gt;

&lt;p&gt;If we run the above code in Chrome the result suddenly looks different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;test-forEach: 6.156005859375ms
test-forEach: 8.01416015625ms
test-for: 4.371337890625ms
test-for: 4.31298828125ms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's because Chrome and Firefox have different JavaScript engines have different kind of performance optimizations. It's good to be aware of these differences.&lt;/p&gt;

&lt;p&gt;In this case, Firefox is doing a better job of optimizing the use of &lt;code&gt;forEach&lt;/code&gt; with the same input.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;for&lt;/code&gt; performs better on both engines so it's probably better to stick to the &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;

&lt;p&gt;This is a good example of why you should measure in multiple engines. If you only measured in Chrome you might have come to the conclusion that &lt;code&gt;forEach&lt;/code&gt; is not so bad in comparison to &lt;code&gt;for&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Throttle your CPU
&lt;/h3&gt;

&lt;p&gt;Those values don't seem like much. Be aware that your development machine is usually much faster than the average mobile phone that your website is being viewed on.&lt;/p&gt;

&lt;p&gt;To get a feeling of how this looks like, browsers have a feature that lets you throttle your CPU performance.&lt;/p&gt;

&lt;p&gt;With this those 10 or 50ms quickly become 500ms.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measure Relative Performance
&lt;/h3&gt;

&lt;p&gt;These raw results actually don't only depend on your hardware but also on the current load on your CPU and your JavaScript thread. Try to focus on the relative improvement of your measurements since these numbers can look very different the next time you restart your computer.&lt;/p&gt;

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

&lt;p&gt;In this article, we have seen some JavaScript APIs we can use to measure performance and then how to use them in the &lt;em&gt;"real world"&lt;/em&gt;. For simple measurements, I find that it's easier to use &lt;code&gt;console.time&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I feel like many frontend developers don't give enough thought to performance on a daily basis, even though it has a direct impact on revenue.&lt;/p&gt;

&lt;p&gt;How do you make sure that you don't forget about performance in daily business? Feel free to send me an email or tweet with your ideas!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webperf</category>
    </item>
    <item>
      <title>How to communicate with Service Workers</title>
      <dc:creator>Felix Gerschau</dc:creator>
      <pubDate>Sat, 22 Feb 2020 11:24:40 +0000</pubDate>
      <link>https://forem.com/fgerschau/how-to-communicate-with-service-workers-3c2l</link>
      <guid>https://forem.com/fgerschau/how-to-communicate-with-service-workers-3c2l</guid>
      <description>&lt;p&gt;&lt;a href="https://felixgerschau.com/how-to-communicate-with-service-workers"&gt;First published on my blog&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;MessageChannel, Broadcast API and Client API compared&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Service Workers are great. They allow web developers to implement native-like features that before were exclusive to native applications. Such features are for example &lt;em&gt;push notifications&lt;/em&gt; or &lt;em&gt;background syncs&lt;/em&gt; for offline capabilities.&lt;/p&gt;

&lt;p&gt;They are the core of progressive web apps. But after setting them up it seems to be difficult to do more complex things that involve interaction with your web application.&lt;/p&gt;

&lt;p&gt;In this post, I'll showcase the options that are available and compare them in the end.&lt;/p&gt;




&lt;h2&gt;
  
  
  Service Workers vs Web Workers
&lt;/h2&gt;

&lt;p&gt;If you look up the API of Service Workers you will see that Web Workers and Service Workers actually have very similar interfaces. But despite their similarities, their intent and capabilities are very different:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E9vxCypV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rj4uca0kfwm7cts8ocwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E9vxCypV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rj4uca0kfwm7cts8ocwu.png" alt="Service Worker vs Web Worker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"&gt;Service Workers&lt;/a&gt; can intercept requests and replace them with items from their own cache, thus they behave like a proxy server. They offer &lt;strong&gt;offline capabilities&lt;/strong&gt; to web applications.&lt;br&gt;
They can be used across &lt;strong&gt;multiple tabs&lt;/strong&gt; and even continue to be alive when all tabs are closed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers"&gt;Web workers&lt;/a&gt;, on the other hand, have a different purpose. They offer &lt;strong&gt;multi-threading&lt;/strong&gt; to the single-threaded JavaScript language and are used for performing &lt;em&gt;computation heavy&lt;/em&gt; tasks that should not interfere with the responsiveness of the UI.&lt;br&gt;
They are limited to &lt;strong&gt;only one tab&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of them have in common that they don't have access to the DOM and communicate using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage"&gt;postMessage&lt;/a&gt; API. You can think of them as Web Workers with expanded capabilities.&lt;/p&gt;

&lt;p&gt;If you want to learn more about these two, check out this &lt;a href="https://www.youtube.com/watch?v=OgLemdR65pE&amp;amp;feature=youtu.be"&gt;talk&lt;/a&gt; which, event though is a little old, gives a good overview of this topic. Being 2020, the &lt;a href="https://caniuse.com/#search=service%20worker"&gt;browser support of Service Workers&lt;/a&gt; has improved a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to talk to Service Workers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Select the Service Worker you want to send a message to
&lt;/h3&gt;

&lt;p&gt;For any origin, it is possible to have multiple Service Workers. The following returns the active Service Worker that currently controls the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you want to access other Service Workers you can access them through the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration"&gt;registration&lt;/a&gt; interface, which gives you access to Service Workers in the following states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ServiceWorkerRegistration.&lt;strong&gt;installing&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;ServiceWorkerRegistration.&lt;strong&gt;waiting&lt;/strong&gt; - This Service Worker is &lt;em&gt;installed&lt;/em&gt; but not active yet&lt;/li&gt;
&lt;li&gt;ServiceWorkerRegistration.&lt;strong&gt;active&lt;/strong&gt; - This Service Worker is controlling the current page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can get access to the registration interface in a few different ways. One of them is calling &lt;code&gt;navigator.serviceWorker.ready&lt;/code&gt;.&lt;br&gt;
This returns a promise that resolves with a registration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;registration&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="c1"&gt;// At this point, a Service Worker is controlling the current page&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Have a look at &lt;a href="https://bitsofco.de/the-service-worker-lifecycle/"&gt;this article&lt;/a&gt; if you want to learn more about the lifecycle&lt;br&gt;
of Service Workers.&lt;/p&gt;
&lt;h3&gt;
  
  
  Send the message
&lt;/h3&gt;

&lt;p&gt;As I already mentioned, Service Workers communicate through the &lt;code&gt;postMessage&lt;/code&gt; API. This doesn't only allow them to exchange data with the JavaScript main thread, but it's also possible to send messages from one Service Worker to another.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.js - Somewhere in your web app&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;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MESSAGE_IDENTIFIER&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// service-worker.js&lt;/span&gt;
&lt;span class="c1"&gt;// On the Service Worker side we have to listen to the message event&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;message&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;event&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MESSAGE_IDENTIFIER&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="c1"&gt;// do something&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;A use case for this one-way communication would be to call &lt;code&gt;skipWaiting&lt;/code&gt; in the waiting Service Worker, which will then pass on to become active and control the page. This is already implemented in the Service Worker that is shipped with Create-React-App. I used this technique for showing an update notification in a progressive web app, which I explain in &lt;a href="https://dev.to%7B%%20post_url%202020-01-27-cra-pwa-update-notification%20%%7D"&gt;this post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But what if you want to send a message back to the &lt;code&gt;Window&lt;/code&gt; context or even to other Service Workers?&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Worker - Client communication
&lt;/h2&gt;

&lt;p&gt;There are a few ways of sending messages to the client(s) of a Service Worker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API"&gt;Broadcast Channel API&lt;/a&gt;, which allows communication&lt;br&gt;
between browsing contexts. This API allows communication between contexts without a reference.&lt;br&gt;
This is currently supported for Chrome, Firefox, and Opera. Set's up a many to many broadcast communication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel"&gt;MessageChannel&lt;/a&gt; API&lt;br&gt;
It can be used to set up a 1-to-1 communication between the Window and the Service Worker context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Clients"&gt;Clients&lt;/a&gt; interface of the Service Worker&lt;br&gt;
It can be used for broadcasting to one or more clients of the Service Worker.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll give you a short example of each of them and then compare them to each other to see which one might be the best for your use case.&lt;/p&gt;

&lt;p&gt;I didn't include &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith"&gt;FetchEvent.respondWith()&lt;/a&gt;&lt;br&gt;
since this only applies to fetch events and is currently not supported by Safari.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using the MessageChannel API
&lt;/h3&gt;

&lt;p&gt;As the name already tells us, the MessageChannel API sets up a channel through which messages can be sent.&lt;/p&gt;

&lt;p&gt;The implementation can be boiled down to 3 steps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up event listeners on both sides for the 'message' event&lt;/li&gt;
&lt;li&gt;Establish the connection to the Service Worker by sending the port and storing it in the Service Worker.&lt;/li&gt;
&lt;li&gt;Reply to the client with the stored port&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A fourth step could be added if we want to close the connection by calling &lt;code&gt;port.close()&lt;/code&gt; in the Service Worker.&lt;/p&gt;

&lt;p&gt;In practice that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.js - somewhere in our main app&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messageChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MessageChannel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// First we initialize the channel by sending&lt;/span&gt;
&lt;span class="c1"&gt;// the port to the Service Worker (this also&lt;/span&gt;
&lt;span class="c1"&gt;// transfers the ownership of the port)&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;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INIT_PORT&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="nx"&gt;messageChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port2&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Listen to the response&lt;/span&gt;
&lt;span class="nx"&gt;messageChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="c1"&gt;// Print the result&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Then we send our first message&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;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREASE_COUNT&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// service-worker.js&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;getVersionPort&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INIT_PORT&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;getVersionPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREASE_COUNT&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;getVersionPort&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;count&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;h3&gt;
  
  
  Using the Broadcast API
&lt;/h3&gt;

&lt;p&gt;The Broadcast API is very similar to the MessageChannel but it takes away the need to pass the port to the Service Worker.&lt;/p&gt;

&lt;p&gt;In this example, we see that we just need to set up a channel on both sides with the same name &lt;code&gt;count-channel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We could add the same code to other WebWorkers or Service Workers who will receive all those messages then as well.&lt;/p&gt;

&lt;p&gt;Here we see the same example from above but with the Broadcast API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.js&lt;/span&gt;
&lt;span class="c1"&gt;// Set up channel&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;broadcast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BroadcastChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count-channel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Listen to the response&lt;/span&gt;
&lt;span class="nx"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Send first request&lt;/span&gt;
&lt;span class="nx"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREASE_COUNT&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// service-worker.js&lt;/span&gt;
&lt;span class="c1"&gt;// Set up channel with same name as in app.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;broadcast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BroadcastChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count-channel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREASE_COUNT&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;broadcast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;count&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;h3&gt;
  
  
  Using the Client API
&lt;/h3&gt;

&lt;p&gt;The Client API also doesn't require to pass a reference to the channel.&lt;/p&gt;

&lt;p&gt;On the client-side, we listen to the response of the service worker and in the Service Worker we select the client we want to send the response to with the filter options that the &lt;code&gt;self.clients.matchAll&lt;/code&gt; function provides us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.js&lt;/span&gt;
&lt;span class="c1"&gt;// Listen to the response&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;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;REPLY_COUNT_CLIENTS&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;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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="c1"&gt;// Send first request&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;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREASE_COUNT_CLIENTS&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// service-worker.js&lt;/span&gt;
&lt;span class="c1"&gt;// Listen to the request&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;message&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;event&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREASE_COUNT&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="c1"&gt;// Select who we want to respond to&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matchAll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;includeUncontrolled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;window&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;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;clients&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;clients&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Send a response - the clients&lt;/span&gt;
        &lt;span class="c1"&gt;// array is ordered by last focused&lt;/span&gt;
        &lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;REPLY_COUNT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;count&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="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;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;postMessage&lt;/code&gt; API offers a simple and flexible interface that allows us to send messages to Service Workers.&lt;/p&gt;

&lt;p&gt;The Broadcast Channel API is the easiest-to-use option to respond to the client, but unfortunately, does not have very good browser support.&lt;/p&gt;

&lt;p&gt;From the remaining two I like the Client API better since this doesn't require passing a reference to the Service Worker.&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>serviceworker</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
