<?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: Matt</title>
    <description>The latest articles on DEV Community by Matt (@mattdclarke).</description>
    <link>https://dev.to/mattdclarke</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%2F463838%2F01b657f8-f512-4534-90bb-3272f555c993.png</url>
      <title>DEV Community: Matt</title>
      <link>https://dev.to/mattdclarke</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mattdclarke"/>
    <language>en</language>
    <item>
      <title>What is a closure? Example use cases in JavaScript and React</title>
      <dc:creator>Matt</dc:creator>
      <pubDate>Mon, 09 May 2022 15:02:51 +0000</pubDate>
      <link>https://dev.to/mattdclarke/what-is-a-closure-example-use-cases-in-javascript-and-react-2e6j</link>
      <guid>https://dev.to/mattdclarke/what-is-a-closure-example-use-cases-in-javascript-and-react-2e6j</guid>
      <description>&lt;h2&gt;
  
  
  What is a closure?
&lt;/h2&gt;

&lt;p&gt;If you are not completely new to JavaScript and are unfamiliar with closures, you have probably used a closure without knowing it. A closure is when a function has access to variables (can read and change them) defined in its outer scope,  even when the function is executed outside of the scope where it was defined.  A closure is a function enclosing a reference (variable) to its outer scope. Functions can access variables outside of their scope.&lt;/p&gt;

&lt;p&gt;Here is a simple example where an outer function that returns an inner function has access to a variable in the outer 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;function&lt;/span&gt; &lt;span class="nx"&gt;outerFunction&lt;/span&gt;&lt;span class="p"&gt;()&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;outerFuncVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;outside&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="nx"&gt;innerFunction&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="s2"&gt;`The value is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;outerFuncVar&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="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;innerFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Console output: &lt;code&gt;The value is: outside&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;The outer function returns an inner function that "closes" over the outer function variable &lt;code&gt;outerFuncVar&lt;/code&gt;. This is why it is called a closure. The &lt;code&gt;outerFunction&lt;/code&gt;, which returns the &lt;code&gt;innerFunction&lt;/code&gt;, can be called anywhere outside of its scope and the &lt;code&gt;innerFunction&lt;/code&gt; will have access to, it can remember, the &lt;code&gt;outerFuncVar&lt;/code&gt;. When it is called, it can read the value of this variable.&lt;/p&gt;

&lt;p&gt;Let's modify the above example so that the &lt;code&gt;outerFunction&lt;/code&gt; variable can be changed and new value is logged after 5 seconds has passed:&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="nx"&gt;outerFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&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;outerFuncVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&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;innerFunction&lt;/span&gt;&lt;span class="p"&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="s2"&gt;`The value is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;input&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="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;5000&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="nx"&gt;innerFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;outerFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new value&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;Console output: &lt;code&gt;The value is: new value&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Even after &lt;code&gt;outerFunction&lt;/code&gt; has finished executing in the above example, the &lt;code&gt;outerFuncVar&lt;/code&gt; is still accessible 5 seconds after the function was called. JavaScript automatically allocates memory when variables are initially declared. After a function returns, its local variables may be marked for garbage collection and removed from memory. Garbage collection is a type of automatic memory management used by JavaScript to free memory when an allocated block of memory, such as a variable and its value, is not needed anymore. &lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;outerFuncVar&lt;/code&gt; was garbage collected right after the function call, it would cause an error because the  &lt;code&gt;outerFuncVar&lt;/code&gt; would no longer exist. The &lt;code&gt;outerFuncVar&lt;/code&gt; is not garbage collected because JavaScript works out that the nested &lt;code&gt;innerFunction&lt;/code&gt; may still be called as it is used in a closure. JavaScript does memory management for us, unlike low-level languages such as C.&lt;/p&gt;

&lt;p&gt;You can also see this persistence of the closures reference to an outer variable by returning the &lt;code&gt;innerFunction&lt;/code&gt; from the &lt;code&gt;outerFunction&lt;/code&gt; and storing it in a variable before executing the &lt;code&gt;innerFunction&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="nx"&gt;outerFunction&lt;/span&gt;&lt;span class="p"&gt;()&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;outerFuncVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;outside&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="nx"&gt;innerFunction&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="s2"&gt;`The value is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;outerFuncVar&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="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;innerFunction&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;innerFunct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;outerFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;innerFunct&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Console output: &lt;code&gt;The value is: outside&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;If the outer function is a nested function itself , such as &lt;code&gt;outerOuterFunction&lt;/code&gt; in the code below, all of the closures will have access to all of their outer function scopes. In this case the &lt;code&gt;innerFunction&lt;/code&gt; closure has access to the &lt;code&gt;outerFunction&lt;/code&gt; and &lt;code&gt;outerOuterFunction&lt;/code&gt; variables:&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="nx"&gt;outerOuterFunction&lt;/span&gt;&lt;span class="p"&gt;()&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;outerOuterFuncVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;outside outside&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;outerFunction&lt;/span&gt;&lt;span class="p"&gt;()&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;outerFuncVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;outside&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="nx"&gt;innerFunction&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="s2"&gt;`The outerFunction value is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;outerFuncVar&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;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="s2"&gt;`The outerOuterFunction value is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;outerOuterFuncVar&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;innerFunction&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;outerFunct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;outerOuterFunction&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;innerFunct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;outerFunct&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;innerFunct&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Console output: &lt;br&gt;
&lt;code&gt;The outerFunction value is: outside&lt;/code&gt;&lt;br&gt;
&lt;code&gt;The outerOuterFunction value is: outside outside&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Multiple instances of a closure can also be created with independent variables that they close over. Let's look at a counter 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;function&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;step&lt;/span&gt;&lt;span class="p"&gt;)&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="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;increaseCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;step&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;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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;add3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;counter&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="c1"&gt;// returns increaseCount function. Sets step and count to 3&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;add5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// returns increaseCount function. Sets step and count to 5&lt;/span&gt;

&lt;span class="nx"&gt;add3&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 3&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;add3&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 6&lt;/span&gt;

&lt;span class="nx"&gt;add5&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 5&lt;/span&gt;
&lt;span class="nx"&gt;add5&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 10&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;add5&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;When the &lt;code&gt;counter&lt;/code&gt; function is called using &lt;code&gt;counter(3)&lt;/code&gt;, an instance of the &lt;code&gt;increaseCount&lt;/code&gt; function is created that has access to the &lt;code&gt;count&lt;/code&gt; variable. &lt;code&gt;step&lt;/code&gt; is set to 3, it's the function parameter variable, and &lt;code&gt;count&lt;/code&gt; is set to 3 (&lt;code&gt;count += step&lt;/code&gt;). It is stored in the variable &lt;code&gt;add3&lt;/code&gt;. When the &lt;code&gt;counter&lt;/code&gt; function is called again using &lt;code&gt;counter(5)&lt;/code&gt;, a new instance of &lt;code&gt;increaseCount&lt;/code&gt; is created that has access to the &lt;code&gt;count&lt;/code&gt; variable of this new instance. &lt;code&gt;step&lt;/code&gt; is set to 5 and &lt;code&gt;count&lt;/code&gt; is set to 5 (&lt;code&gt;count += step&lt;/code&gt;). It is stored in the variable &lt;code&gt;add5&lt;/code&gt;. Calling these different instances of the closure increments the value of &lt;code&gt;count&lt;/code&gt; in each instance by the &lt;code&gt;step&lt;/code&gt; value. The &lt;code&gt;count&lt;/code&gt; variables in each instance are independent.  Changing the variable value in one closure does not effect the variable values in other closures.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  A more technical definition of a closure
&lt;/h2&gt;

&lt;p&gt;A closure is when a function remembers and has access to variables in its lexical / outer scope even when the function is executed outside of its lexical scope. Closures are created at function creation time. Variables are organized into units of scope, such as block scope or function scope. Scopes can nest inside each other. In a given scope, only variables in the current scope or at a higher / outer scope are accessible. This is called lexical scope. Lexical, according to the dictionary definition,  means relating to the words or vocabulary of a language. In this case, you can think of it as how scoping occurs in the JavaScript language. Lexical scoping uses the location of where a variable is declared in the source code to determine where the variable is available in the source code. Scope is determined at compile time, more specifically lexing time, by the compiler of the JavaScript Engine used to process and execute the code. The first stage of compilation involves lexing / parsing. Lexing is when the code is converted into tokens, which is part of the process of converting code into machine readable code. You can read about how the JavaScript engine works in this article: &lt;a href="https://dev.to/lydiahallie/javascript-visualized-the-javascript-engine-4cdf"&gt;JavaScript Visualized: the JavaScript Engine&lt;/a&gt;. &lt;/p&gt;




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

&lt;h2&gt;
  
  
  Why are closures important? Some examples
&lt;/h2&gt;

&lt;p&gt;Here are a few examples of where closures are used in JavaScript and React.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Async code
&lt;/h4&gt;

&lt;p&gt;Closures are commonly used with async code, for example: sending a POST request using the Fetch API:&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="nx"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;response&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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;data&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="s2"&gt;`&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="s2"&gt; from &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/answer&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;When &lt;code&gt;getData&lt;/code&gt; is called, it finishes executing before the fetch request is complete. The inner function &lt;code&gt;fetch&lt;/code&gt; closes over the &lt;code&gt;url&lt;/code&gt; function parameter variable. This preserves the &lt;code&gt;url&lt;/code&gt; variable.  &lt;/p&gt;

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

&lt;h4&gt;
  
  
  Modules
&lt;/h4&gt;

&lt;p&gt;The JavaScript module pattern is a commonly used design pattern in JavaScript to create modules. Modules are useful for code reuse and organization.  The module pattern allows functions to encapsulate code like a class does. This means that the functions can have public and private methods and variables. It allows for controlling how different parts of a code base can influence each other. Closures are required for this, for functional modules. Functional modules are immediately invoked function expressions (IIFE).  The IIFE creates a closure that has methods and variables that can only be accessed within the function, they are private. To make methods or variables public, they can be returned from the module function. Closures are useful in modules because they allow module methods to be associated with data in their lexical environment (outer scope), the variables in the module:&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;var&lt;/span&gt; &lt;span class="nx"&gt;myModule&lt;/span&gt; &lt;span class="o"&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;privateVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;publicVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12345&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;privateMethod&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="nx"&gt;privateVar&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;publicMethod&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;publicVar&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&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;publicVar&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;publicMethod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publicMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;publicVar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publicVar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;alterPrivateVarWithPublicMethod&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;privateVar&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="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;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;myModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicVar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 12345&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;myModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alterPrivateVarWithPublicMethod&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="nx"&gt;myModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicMethod&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 12346&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;myModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alterPrivateVarWithPublicMethod&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 5&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;myModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;privateVar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// undefined&lt;/span&gt;
&lt;span class="nx"&gt;myModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;privateMethod&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Uncaught TypeError: myModule.privateMethod is not a function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h4&gt;
  
  
  Functional programming - currying and composition
&lt;/h4&gt;

&lt;p&gt;Currying a function is when a function that takes multiple arguments is written in such a way that it can only take one argument at a time. It returns a function that takes the next argument, which returns a function that takes the next argument, ... this continues until all of the arguments are provided and then it returns value. It allows you to break up a large function into smaller functions that each handle specific tasks. This can make functions easier to test. Here is an example of a curried function that adds three values together:&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="nx"&gt;curryFunction&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="k"&gt;return&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="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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&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="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;c&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;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;curryFunction&lt;/span&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="c1"&gt;// 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Composition is when functions are combined to create larger functions, it is an important part of functional programming. Curried functions can be composed into large, complex functions. Composition can make code more readable because of descriptive function names. The following is a simple example of currying and composition where there are two number functions (for simplicity): &lt;code&gt;five&lt;/code&gt; and &lt;code&gt;six&lt;/code&gt; that use the &lt;code&gt;n&lt;/code&gt; function, which allows them to be called alone or composed with other functions such as the &lt;code&gt;plus&lt;/code&gt; function. The &lt;code&gt;isEqualTo&lt;/code&gt; function checks if two numbers are the same.&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;var&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digit&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="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;operator&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="nx"&gt;operator&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;digit&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;var&lt;/span&gt; &lt;span class="nx"&gt;five&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;six&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&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;plus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&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;prev = &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// prev = 6&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;curr&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="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;curr&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;function&lt;/span&gt; &lt;span class="nx"&gt;isEqualTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;comparator&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;comparator = &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;comparator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// comparator = 5&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;comparator&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;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;five&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 5&lt;/span&gt;

&lt;span class="c1"&gt;// values calculated from the inside to the outside&lt;/span&gt;
&lt;span class="c1"&gt;// 1. six() =&amp;gt; result1&lt;/span&gt;
&lt;span class="c1"&gt;// 2. plus(result1) =&amp;gt; result2&lt;/span&gt;
&lt;span class="c1"&gt;// 3. five(result2) =&amp;gt; final 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;five&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;six&lt;/span&gt;&lt;span class="p"&gt;())));&lt;/span&gt; &lt;span class="c1"&gt;// 11&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;isEqualTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;five&lt;/span&gt;&lt;span class="p"&gt;())(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;You can read more about currying and composition in this article: &lt;a href="https://www.freecodecamp.org/news/how-to-use-currying-and-composition-in-javascript"&gt;How to use Currying and Composition in JavaScript&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Here is an example of a debounce function, from &lt;a href="https://www.joshwcomeau.com/snippets/javascript/debounce/"&gt;https://www.joshwcomeau.com/snippets/javascript/debounce/&lt;/a&gt;,  that returns a function and makes use of a closure, like the counter example that we used earlier:&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;debounce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wait&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;args&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&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;callback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;wait&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; &lt;/p&gt;

&lt;p&gt;Modern front end frameworks/libraries like React make use of a composition model where small components can be combined to build complex components. &lt;/p&gt;

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

&lt;h3&gt;
  
  
  React
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Making hooks
&lt;/h4&gt;

&lt;p&gt;Here is a function that mimics the &lt;code&gt;useState&lt;/code&gt; hook. The initial value, the state getter, is enclosed in the closure and acts like stored state:&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="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;)&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;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initial&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="c1"&gt;// why is the state value a function? No re-render in vanilla JavaScript like in React.&lt;/span&gt;
    &lt;span class="c1"&gt;// if you just use the value (no function), then change it with the setter function(setState) and then the log value, it will reference a "stale" value (stale closure) -&amp;gt; the initial value not the changed value&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;str&lt;/span&gt;&lt;span class="p"&gt;,&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&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;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;state1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setState1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setState2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob&lt;/span&gt;&lt;span class="dl"&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;state1&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// hello&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;state2&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Bob&lt;/span&gt;
&lt;span class="nx"&gt;setState1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;goodbye&lt;/span&gt;&lt;span class="dl"&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;state1&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// goodbye&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;state2&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Bob&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see a better implementation where the state value is not a function check out the following article - &lt;a href="https://www.swyx.io/hooks/"&gt;Getting Closure on React Hooks&lt;/a&gt;.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  Closures remember the values of variables from previous renders - this can help prevent async bugs
&lt;/h4&gt;

&lt;p&gt;In React, if you have an async function that relies on props that may change during the async function execution, you can easily end up with bugs if you use class components due to the props value changing. Closures in React functional components make it easier to avoid these types of bugs. Async functions, that use prop values, use closures to preserve the prop values at the time when the function was created. Each time a component renders, a new props object is created. Functions in the component are re-created. Any async functions that use variables from the props (or elsewhere), remember the variables due to closure. If the component that an async function is in is re-rendered and the props change (new values) during the async function call, the async function call will still reference the props from the previous render, where the function was defined,  as the values were preserved due to closure. You can see an example of this in the article -  &lt;a href="https://epicreact.dev/how-react-uses-closures-to-avoid-bugs/"&gt;How React uses Closures to Avoid Bugs&lt;/a&gt;.&lt;/p&gt;




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

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

&lt;p&gt;We learned what closures are using some examples and saw some example use cases in JavaScript and React. To learn more about closures, you can check the articles linked below. &lt;/p&gt;




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

&lt;h2&gt;
  
  
  References / Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures"&gt;MDN Closures article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/get-started/ch3.md"&gt;You Don't Know JS book - Getting Started - Chapter 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/get-started/apB.md"&gt;You Don't Know JS book - Getting Started - Appendix B&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://whatthefuck.is/closure"&gt;Dan Abramov Closure article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://coryrylan.com/blog/javascript-module-pattern-basics"&gt;JavaScript Module Pattern Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/conceptual_articles/module-design-pattern-in-javascript"&gt;Module Design Pattern in JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/how-to-use-currying-and-composition-in-javascript/"&gt;How to use Currying and Composition in React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.swyx.io/hooks/"&gt;Getting Closure on React Hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://epicreact.dev/how-react-uses-closures-to-avoid-bugs"&gt;How React uses Closures to Avoid Bugs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Implement Depth-First Search in a Binary Search Tree with JavaScript</title>
      <dc:creator>Matt</dc:creator>
      <pubDate>Thu, 30 Dec 2021 15:55:46 +0000</pubDate>
      <link>https://dev.to/mattdclarke/implement-depth-first-search-in-a-binary-search-tree-with-javascript-1p96</link>
      <guid>https://dev.to/mattdclarke/implement-depth-first-search-in-a-binary-search-tree-with-javascript-1p96</guid>
      <description>&lt;p&gt;Binary search trees are a useful data structure for storing data in an ordered format that makes searching for values, insertion and deletion quick. Real-world applications include their use in search algorithms, 3D game engines and graphics. In this article, we will learn about a type of tree traversal algorithm called depth-first search that can be used to explore a binary search tree. We will learn how to implement the 3 types of depth-first search algorithms: pre-order, in-order and post-order using recursion. Tree traversal algorithms are a common subject in coding interview questions. &lt;/p&gt;




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

&lt;h2&gt;
  
  
  What is a Binary Search Tree?
&lt;/h2&gt;

&lt;p&gt;A tree is a type of data structure. It is non-linear, which makes it a good data structure to store and search for data. Search time in a linear data structure, such as an array or linked list, increases proportionally as the size of the data set increases. A tree data structure splits up the data, decreasing the search time.&lt;/p&gt;

&lt;p&gt;A tree data structure, unsurprisingly, looks like a tree when visualized. Normally it looks like an upside-down tree. It is made up of nodes that store data. The nodes are connected by edges, also known as branches. A parent node branch connects to a child node. The first node in the tree is known as the root node. It is positioned at the top of the upside-down tree. The root is connected to subtrees. A Subtree refers to all of the descendants (children, grandchildren, ...) of a node. At the ends of the branches, the nodes that have no children are referred to as leaves.&lt;/p&gt;

&lt;p&gt;Trees are recursive data structures. What this means is that each node (that is not a leaf) is a parent of its children and each child is a parent of its children, whose children are parents of its children and so on. We will see, later in this article, that recursion can be used for the algorithms used to traverse trees. There are iterative solutions using while loops, but the simplest solutions are recursive.&lt;/p&gt;

&lt;p&gt;A binary tree is a particular type of tree where each node has, at most, 2 children. A binary search tree is a type of binary tree that has ordered nodes. For any node in the binary search tree, the values of the nodes in all of the left child subtree nodes are less than the value of the parent node. The  values of the nodes in all of the right child subtree nodes are greater than or equal to the value of the parent node. This affects the insertion order when the tree is created. This can be seen in the diagram below. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39sg41eqanz2m6a3og3a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39sg41eqanz2m6a3og3a.png" alt="Components of a binary search tree"&gt;&lt;/a&gt;&lt;/p&gt;
Components of a binary search tree.

 

&lt;p&gt; &lt;br&gt;
 &lt;/p&gt;
&lt;h3&gt;
  
  
  Why is a binary search tree useful?
&lt;/h3&gt;

&lt;p&gt; &lt;/p&gt;
&lt;h4&gt;
  
  
  Fast search, insert and delete
&lt;/h4&gt;

&lt;p&gt;One measure of an algorithm's efficiency is its time complexity. It is an approximate measure of how long an algorithm takes to execute as the size of the data set, that the algorithm operates on, increases. The smaller the value, the better the algorithm. Time complexity is formally described using big O notation. You can think of the &lt;em&gt;O&lt;/em&gt; as meaning "on the order of". It's a measure of the worst case for an algorithm. For example, a linear search algorithm (starts the search from the beginning of the data structure and checks each element sequentially) that searches for an element in a linked list or an array of size n will take ~&lt;em&gt;O&lt;/em&gt;(n) steps. This is read as "big &lt;em&gt;O&lt;/em&gt; of n" or "on the order of n".  If there are 16 elements in the linear data structure, it will take 16 steps (worst case) to find the element using a linear search algorithm. &lt;/p&gt;

&lt;p&gt;Binary search tree algorithms that search for an element in a binary search tree have a logarithmic run time, &lt;em&gt;O&lt;/em&gt;(log n). This means that as the size of the data structure increases, the time taken for the operation increases logarithmically. This is much faster than a linear search. If there are 16 elements in a binary search tree. It will take &lt;em&gt;O&lt;/em&gt;(log(16)) = 4 steps to find an element in a binary search tree. The logarithm is base 2. This difference becomes very pronounced as the data set size increases. If there are 1 048 576 elements. The linear search algorithm will take  1 048 576 steps to find an element in the worst case. The binary search tree algorithm will take 20 steps in the worst case.&lt;/p&gt;

&lt;p&gt;Insertion and deletion are also quick in a binary search tree. When data is inserted, it is stored by reference. This means that a new piece of memory is created when it is a node is added to a binary search tree and it points to the parent node that it is connected to. The nodes can be spread out in memory. If you were to insert or delete an element from the middle of an array, many operations would need to be performed to shift the values in the array. This is because values in an array are all next to each other in memory. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;
&lt;h5&gt;
  
  
  Why is the search time in a binary search tree logarithmic?
&lt;/h5&gt;

&lt;p&gt;A logarithm is defined as the inverse function to exponentiation. What this means is that if you have a logarithm, say log2(16). You can get the answer by asking: "What power do I have to raise 2 to get an answer of 16?". This can be written as 2&lt;sup&gt;?&lt;/sup&gt; = 16. Divide and conquer algorithms that continually divide a data structure in half are logarithmic (base 2). This includes binary search tree algorithms. Logarithms that are base 2 can be considered as divisions by 2. &lt;/p&gt;

&lt;p&gt;log2(16) = 4 can be read as: "I have to raise 2 to the power of 4 to get an answer of 16".  This is equivalent to: "16 requires 4 divisions by 2 to reach a value of 1".  &lt;/p&gt;

&lt;p&gt;16 / 2 = 8    -&amp;gt;    8 / 2 =  4    -&amp;gt;    4 / 2 = 2    -&amp;gt;    2 /2 = 1.     &lt;/p&gt;

&lt;p&gt;For example, if you have 16 elements in a binary search tree, like in the image below, the time complexity is &lt;em&gt;O&lt;/em&gt;(log n). This means it will take &lt;em&gt;O&lt;/em&gt;(log(16)) or 4 steps, in the worst case, to find an element. This is equal to the height of the tree. When searching for an item, starting at the root, the correct direction, left or right, can be chosen at each step because the nodes are ordered. At each step, the number of nodes to search is halved. The problem size is halved with each step. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfz1mviw7csiuiy0p6vl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfz1mviw7csiuiy0p6vl.png" alt="Binary search tree. The height is equal to the logarithm (base 2) of the number of nodes."&gt;&lt;/a&gt;&lt;/p&gt;
Binary search tree. The height is equal to the logarithm (base 2) of the number of nodes. For each node traversed in the tree, the number of nodes remaining to search is halved.

 

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

&lt;p&gt;The binary search trees used in this article are balanced. This means that the nodes are spread out well. The height of a tree is the number of nodes between the root node and a leaf node. A tree may have many different heights.  If the difference between the maximum height and minimum height is 1 or 0, then the tree is balanced. &lt;/p&gt;

&lt;p&gt;Logarithmic search times occur for balanced trees. The more unbalanced a binary search tree becomes, the slower the search time. The search time becomes more linear as the tree starts to become more linear (&lt;em&gt;O&lt;/em&gt;(n)). There are self-balancing trees that can be used for dynamic data sets. This is beyond the scope of this article - you can read more about them in this Wikipedia article: &lt;a href="https://en.wikipedia.org/wiki/Self-balancing_binary_search_tree" rel="noopener noreferrer"&gt;Self-balancing binary search tree&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0k9n23r420pz5d0sxx57.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0k9n23r420pz5d0sxx57.png" alt="sequence of binary search trees - from balanced to unbalanced"&gt;&lt;/a&gt;&lt;/p&gt;
The more unbalanced a binary search tree becomes,  the more it starts to resemble a linear data structure. The search time also increases.

 



&lt;p&gt; &lt;br&gt;
 &lt;/p&gt;
&lt;h2&gt;
  
  
  Exploring a binary search tree: Depth-first search
&lt;/h2&gt;

&lt;p&gt;Various algorithms allow you to visit each node in a tree instead of searching for a specific value. These algorithms are used to explore the data: each node's value is read and can be checked or updated. They can be broadly divided into depth-first and breadth-first search.&lt;/p&gt;

&lt;p&gt;Breadth-first, also known as level-order, search algorithms read the value of all the nodes at a particular level in a tree before moving on to the next level. The progression of the algorithm as it traverses the tree and reads the node values is breadth-first. It starts at the root node and moves down the tree level by level. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fworw11rci7ugvljbgf64.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fworw11rci7ugvljbgf64.gif" alt="Breath-first search - algorithm steps"&gt;&lt;/a&gt;&lt;/p&gt;
Breath-first search in a binary search tree.

 

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

&lt;p&gt;Depth-first search algorithms first read all of the node values in a particular subtree. The subtree is traversed deeply, all the way to the bottom leaves, before moving on to the next subtree. We will explore depth-first search algorithms in more detail.  &lt;/p&gt;

&lt;p&gt;There are 3 types of depth-first search: pre-order, in-order and post-order. In these algorithms, the root, the left subtree of the root and the right subtree of the root are traversed. The difference between them is the order in which the node values are read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; pre-order:    root -&amp;gt; left subtree -&amp;gt; right subtree&lt;/li&gt;
&lt;li&gt; in-order:       left subtree -&amp;gt; root -&amp;gt; right subtree&lt;/li&gt;
&lt;li&gt; post-order:  left subtree -&amp;gt; right subtree -&amp;gt; root&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flts7cv5dkkwqodrqfn7q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flts7cv5dkkwqodrqfn7q.gif" alt="The 3 types of depth-first search algorithms "&gt;&lt;/a&gt;&lt;/p&gt;
Depth-first search in a binary search tree. The 3 types of search algorithms are shown: pre-order, in-order and post-order.

 

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

&lt;p&gt;In pre-order search, the root value is read first and then the subtree values are read. In in-order search, the first node read is the left-most node in the BST. The last node read is the right-most node in the BST.  In post-order search, the leaves are read first and then the roots are read.   &lt;/p&gt;

&lt;p&gt;Let's explore how this traversal occurs through each node. The following CodePen shows the three types of depth-first search tree traversal algorithms. Click on the buttons to visualize the traversal and see the order in which the nodes are visited and read. Notice that in-order traversal prints the values of the nodes in order. &lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/MattDC1/embed/MWEpqJe?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
CodePen showing depth-first search tree traversal algorithms in a binary search tree. Modified from:  https://codepen.io/mehmetakifakkus/pen/bqVjXX

 




&lt;p&gt; &lt;br&gt;
 &lt;/p&gt;
&lt;h3&gt;
  
  
  Implement depth-first search in JavaScript
&lt;/h3&gt;

&lt;p&gt;Let's implement the 3 types of depth-first search algorithms. The inspiration for writing this article came from doing a &lt;a href="https://www.freecodecamp.org/learn/coding-interview-prep/data-structures/use-depth-first-search-in-a-binary-search-tree" rel="noopener noreferrer"&gt;freeCodeCamp challenge on using depth-first search in a binary search tree&lt;/a&gt;.  You can try the challenge before continuing. &lt;/p&gt;

&lt;p&gt;The implementations used here make use of recursive functions. This means that the functions call themselves. The recursion stops when the base case is reached. In the depth-first search algorithms implemented here, the root node is passed in as an argument to the recursive algorithm function. Its left child or right child is recursively passed in as an argument to the same function. The left and right children are subtrees of the parent node. The recursion stops when the left node and the right node of the node being traversed is null. In other words,  when a node with no children, a leaf, is reached. During the recursion, the value of the current node is added to an array. The output of the algorithms is an array of the visited nodes. The order of the array elements is equal to the order in which the nodes were read.  &lt;/p&gt;

&lt;p&gt;The code below will be used as a base for implementing the algorithms. We will implement the algorithms as methods within a &lt;code&gt;BinarySearchTree&lt;/code&gt; function.  There is an &lt;code&gt;add&lt;/code&gt; method that will be used to add nodes to the tree when we test the algorithm. The &lt;code&gt;Node&lt;/code&gt; function is used by the &lt;code&gt;add&lt;/code&gt; method to create nodes. There is also a &lt;code&gt;displayTree&lt;/code&gt; function that will be used to visualize the tree, as a string, in the console. For simplicity, no duplicate values will be allowed in the binary search tree.  From now on, binary search tree will be abbreviated as BST.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// converts created binary search tree into a JSON string&lt;/span&gt;
&lt;span class="c1"&gt;// JSON.stringify(value, replacer, space)&lt;/span&gt;
&lt;span class="c1"&gt;// tree will be the passed in BST&lt;/span&gt;
&lt;span class="c1"&gt;// null means that all properties are included in the JSON string&lt;/span&gt;
&lt;span class="c1"&gt;// 2 adds some white space to the JSON string output to make it more readable&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;displayTree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tree&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Node&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;span class="c1"&gt;// give node a value&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// node has no children initially&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;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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="nf"&gt;BinarySearchTree&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// root is initially empty - no nodes&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;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// add node to tree&lt;/span&gt;
  &lt;span class="c1"&gt;// value and current node (currNode) passed in as arguments&lt;/span&gt;
  &lt;span class="c1"&gt;// the default value of currNode is this.root&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;add&lt;/span&gt; &lt;span class="o"&gt;=&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;currNode&lt;/span&gt; &lt;span class="o"&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;root&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;// create a new node&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newNode&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;Node&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="c1"&gt;// if no nodes in tree, make newly added node the root&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;root&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;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// no duplicate values allowed - for simplicity &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;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;currNode&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// add node to left subtree&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;currNode&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;span class="c1"&gt;// if no left child, add new node as left child - base case&lt;/span&gt;
        &lt;span class="c1"&gt;// else recursively call add() again - currNode changes - moving down tree&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newNode&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="nf"&gt;add&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;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// add node to right subtree&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newNode&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="nf"&gt;add&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;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&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;p&gt; &lt;/p&gt;

&lt;p&gt;The 3 algorithms for pre-order, in-order and post-order are very similar. They will be added as methods to &lt;code&gt;BinarySearchTree&lt;/code&gt;. They all share the following code:&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;traversefunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// different for each method&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;traversefunction&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;root&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;values&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; &lt;/p&gt;

&lt;p&gt;The first thing we check is if the root is null, which would mean the BST has no nodes. If this is the case we return null as there is no BST to traverse. The output of the method is stored in the &lt;code&gt;value&lt;/code&gt; array and is returned from the function. &lt;/p&gt;

&lt;p&gt;Each method has a traverse function used to traverse the tree. It is initially called with the root node as an argument. These traversal functions are recursively called to traverse the BST tree. These traversal functions are where the methods differ. The traversal functions differ in the order of execution of the current node value being pushed into the array.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// PRE-ORDER&lt;/span&gt;

&lt;span class="c1"&gt;// add current node value&lt;/span&gt;
&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&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="c1"&gt;// if left child node exists - traverse left subtree&lt;/span&gt;
&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traversePreOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// if right child node exists - traverse right subtree&lt;/span&gt;
&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traversePreOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// IN-ORDER&lt;/span&gt;

&lt;span class="c1"&gt;// if left child node exists - traverse left subtree&lt;/span&gt;
&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traversePreOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="c1"&gt;// add current node value&lt;/span&gt;
&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&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="c1"&gt;// if right child node exists - traverse right subtree&lt;/span&gt;
&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traversePreOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// POST-ORDER&lt;/span&gt;

&lt;span class="c1"&gt;// if left child node exists - traverse left subtree&lt;/span&gt;
&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traversePreOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="c1"&gt;// if right child node exists - traverse right subtree&lt;/span&gt;
&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traversePreOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="c1"&gt;// add current node value&lt;/span&gt;
&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Before we continue with explaining each method in detail, let's briefly learn about the call stack so that we can better understand the recursive function calls in the algorithms. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;
&lt;h4&gt;
  
  
  What is the call stack?
&lt;/h4&gt;

&lt;p&gt;A call stack is a mechanism used by the JavaScript Engine interpreter to keep track of function calls.  The JavaScript engine is the program that reads, interprets, optimizes and executes JavaScript code. It converts human-readable JavaScript code into machine-readable code. When a function is called, the JavaScript Engine interpreter adds it to the top of the call stack and starts executing the function. If the function calls another function, which may be the same function (recursive function call), the newly called function is added to the top of the call stack. The call stack uses the last-in-first-out (LIFO) principle. When the current function, which is at the top of the call stack, completes its execution it is popped off the call stack.  A functions execution is complete when it returns a value or reaches the end of its scope. The interpreter then resumes execution of the code from where it left off on the call stack, which is the function that is now at the top of the call stack.  The GIF below shows an example of how function calls are added and removed from the call stack. This example does not show, for simplicity, the execution of the &lt;code&gt;main&lt;/code&gt; function, which is the execution of the whole script. You can read more about the call stack in this article: &lt;a href="https://felixgerschau.com/javascript-event-loop-call-stack/" rel="noopener noreferrer"&gt;JavaScript Event Loop And Call Stack Explained&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8q56l0evxs47uzzn0d5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8q56l0evxs47uzzn0d5.gif" alt="Call stack animation"&gt;&lt;/a&gt;&lt;/p&gt;
Simplified example showing how functions are added and removed from the call stack during code execution.

 



&lt;p&gt; &lt;/p&gt;
&lt;h4&gt;
  
  
  Pre-order
&lt;/h4&gt;

&lt;p&gt;Let's Implement the &lt;code&gt;preOrder&lt;/code&gt; method. In your code editor or your browser dev tools add the   &lt;code&gt;displayTree&lt;/code&gt;, &lt;code&gt;Node&lt;/code&gt; and &lt;code&gt;BinarySearchTree&lt;/code&gt; functions from the code above. Add the &lt;code&gt;preorder&lt;/code&gt; method, displayed in the code below, to the &lt;code&gt;BinarySearchTree&lt;/code&gt; function:&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preOrder&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;traversePreOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&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="c1"&gt;// add current node (subtree root)&lt;/span&gt;
        &lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traversePreOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// traverse left subtree&lt;/span&gt;
        &lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traversePreOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// traverse right subtree&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;traversePreOrder&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;root&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;values&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; &lt;/p&gt;

&lt;p&gt;At the bottom of the script, add the code displayed below. We create a new BST called &lt;code&gt;testBST&lt;/code&gt;, it is an instance of the &lt;code&gt;BinarySearchTree&lt;/code&gt; object that contains the &lt;code&gt;preOrder&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt; method. Then we add nodes to it using the &lt;code&gt;add&lt;/code&gt; method. The BST has the same nodes as the interactive CodePen BST shown earlier. &lt;/p&gt;

&lt;p&gt;We then console log the the created BST to visualize it using the &lt;code&gt;displayTree&lt;/code&gt; function and then console log the &lt;code&gt;preorder&lt;/code&gt; method to see its output. &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;var&lt;/span&gt; &lt;span class="nx"&gt;testBST&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;BinarySearchTree&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&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="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&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="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&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;Binary search tree: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&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="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;Binary search tree: pre-order search &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preOrder&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;

&lt;p&gt;The output of the console logs should be:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

binary search tree:  {
  "value": 5,
  "left": {
    "value": 3,
    "left": {
      "value": 2,
      "left": null,
      "right": null
    },
    "right": {
      "value": 4,
      "left": null,
      "right": null
    }
  },
  "right": {
    "value": 8,
    "left": {
      "value": 6,
      "left": null,
      "right": null
    },
    "right": {
      "value": 9,
      "left": null,
      "right": null
    }
  }
}

Binary search tree: pre-order search  Array(7) [ 5, 3, 2, 4, 8, 6, 9 ]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;

&lt;p&gt;You can compare the console logged BST JSON string to the BST in the CodePen example, the trees are the same. The output of the pre-order search also matches the output of the pre-order search in the CodePen example.&lt;/p&gt;

&lt;p&gt;Now let's go through the execution of the function calls step by step to understand the traversal, order of the recursive function calls and the order in which the values are read and added to the values array. The following slide show shows how the &lt;code&gt;traversePreOrder&lt;/code&gt; function within the &lt;code&gt;preOrder&lt;/code&gt; method is recursively called. It shows how the recursively called &lt;code&gt;traversePreOrder&lt;/code&gt; function is added to and removed from the call stack during the execution of the &lt;code&gt;preOrder&lt;/code&gt; method. The BST traversal is visually shown in the middle. The addition of node values to the values array is shown at the bottom left. Note that the stack continues to grow until a leaf node is reached, the maximum stack height occurs when a leaf is reached. The maximum stack height of the &lt;code&gt;traversePreOrder&lt;/code&gt; functions (ignoring the &lt;code&gt;preOrder&lt;/code&gt; function on the stack) is 3, which is equal to the height of the BST. The space complexity of the tree is O(h), where h is the height of the tree. We learnt earlier that an algorithm's time complexity is an approximate measure of how long an algorithm takes to execute as the size of the data set, that the algorithm operates on, increases. An algorithm's space complexity is an approximate measure of how much memory is needed to execute the algorithm as the size of the data set increases.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="speakerdeck-iframe ltag_speakerdeck" src="https://speakerdeck.com/player/f99bcacebc19423d9e4856b3a7f420d9"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
Execution of the `preOrder` method. The recursive calls of the `traversePreOrder` function are shown alongside the traversal of the Binary Search Tree as each line of code is executed.

 




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

&lt;h4&gt;
  
  
  In-order
&lt;/h4&gt;

&lt;p&gt;Let's Implement the &lt;code&gt;inOrder&lt;/code&gt; method.  In the code you used for the &lt;code&gt;preOrder&lt;/code&gt; method, add the following &lt;code&gt;inOrder&lt;/code&gt; method to the &lt;code&gt;BinarySearchTree&lt;/code&gt; function:&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inOrder&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;traverseInOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traverseInOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&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;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traverseInOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;traverseInOrder&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;root&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;values&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; &lt;/p&gt;

&lt;p&gt;Add the following console log at the end of the script to test the method:&lt;/p&gt;

&lt;div class="highlight js-code-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="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;Binary search tree: in-order search &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inOrder&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;The output of the added console log should be:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;Binary&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt;  &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&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="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;Now let's go through the execution of the function calls step by step to understand the algorithm. The following slide show shows how the &lt;code&gt;traverseInOrder&lt;/code&gt; function is recursively called. If you compare the call stack execution to the &lt;code&gt;traversePreOrder&lt;/code&gt; function in the previous section, you will notice that the order of recursive function calls is the same. The point at which the current node value is pushed into the values array differs. This is the same for the &lt;code&gt;traversePostOrder&lt;/code&gt; method that will be described in the next section.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="speakerdeck-iframe ltag_speakerdeck" src="https://speakerdeck.com/player/3f853fba74cf4afbb838209d8fe43db7"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
Execution of the `inOrder` method. The recursive calls of the `traverseInOrder` function are shown alongside the traversal of the Binary Search Tree as each line of code is executed.

 




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

&lt;h4&gt;
  
  
  Post-order
&lt;/h4&gt;

&lt;p&gt;Let's Implement the last method, the &lt;code&gt;postOrder&lt;/code&gt; method. Add the following. Add the following &lt;code&gt;postOrder&lt;/code&gt; method to the &lt;code&gt;BinarySearchTree&lt;/code&gt; function:&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postOrder&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;traversePostOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traversePostOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;traversePostOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currNode&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;span class="nf"&gt;traversePostOrder&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;root&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;values&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; &lt;/p&gt;

&lt;p&gt;Add the following console log at the end of the script to test the method:&lt;/p&gt;

&lt;div class="highlight js-code-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="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;Binary search tree: post-order search &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;testBST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postOrder&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;The output of the added console log should be:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;Binary&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt;  &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&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;4&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="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;Now let's go through the execution of the function calls step by step to understand the algorithm. The following slide show shows how the &lt;code&gt;traversePostOrder&lt;/code&gt; function is recursively called.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="speakerdeck-iframe ltag_speakerdeck" src="https://speakerdeck.com/player/b1704f10589d4d6b8843f071a57b8865"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
Execution of the `postOrder` method. The recursive calls of the `traversePostOrder` function are shown alongside the traversal of the Binary Search Tree as each line of code is executed.

 




&lt;p&gt; &lt;br&gt;
 &lt;/p&gt;

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

&lt;p&gt;Binary search trees are a useful data structure that can be explored using depth-first search algorithms. The 3 types of depth-first search algorithms: pre-order, in-order and post-order can be implemented using recursion. They are very similar algorithms, they only differ in the  order in which the node values are read. Understanding these algorithms can help you pass your next coding interview and you may even find yourself using them in a real-world application. &lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Here are some useful links for further study:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1) &lt;a href="https://www.freecodecamp.org/learn/coding-interview-prep/#data-structures" rel="noopener noreferrer"&gt;freeCodeCamp Coding Interview Prep - Data Structures&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2) &lt;a href="https://felixgerschau.com/javascript-event-loop-call-stack/" rel="noopener noreferrer"&gt;JavaScript Event Loop And Call Stack Explained&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3) &lt;a href="https://pythontutor.com/" rel="noopener noreferrer"&gt;Python tutor&lt;/a&gt;: Visualize execution of code (Python, Java, C, C++, JavaScript, or Ruby) - line by line&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>algorithms</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to rate limit a login route in Express using node-rate-limiter-flexible and Redis</title>
      <dc:creator>Matt</dc:creator>
      <pubDate>Mon, 31 May 2021 20:09:37 +0000</pubDate>
      <link>https://dev.to/mattdclarke/how-to-rate-limit-a-login-route-in-express-using-node-rate-limiter-flexible-and-redis-1i1k</link>
      <guid>https://dev.to/mattdclarke/how-to-rate-limit-a-login-route-in-express-using-node-rate-limiter-flexible-and-redis-1i1k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Rate limiting is a method used for controlling network traffic. It limits the number of actions a user can make per unit of time &lt;sup&gt;&lt;a href="https://www.cloudflare.com/learning/bots/what-is-rate-limiting/" rel="noopener noreferrer"&gt;1&lt;/a&gt;&lt;/sup&gt;. In this tutorial, we will rate limit a login route to help protect it from &lt;a href="https://www.kaspersky.com/resource-center/definitions/brute-force-attack" rel="noopener noreferrer"&gt;brute force attacks&lt;/a&gt;. This limits the number of password guesses that can be made by an attacker. We'll use the npm package &lt;a href="https://www.npmjs.com/package/rate-limiter-flexible" rel="noopener noreferrer"&gt;node-rate-limiter-flexible&lt;/a&gt; to count and limit the number of login attempts by key. Each key will have a points value that will count the number of failed login attempts. The keys will expire after a set amount of time. The key-value pairs will be stored in &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt;, which is an open-source in-memory data structure store. It has many different use cases. We will use it as a simple database. Redis is simple to use and very fast. We'll create an online instance of Redis, connect it to an express application, and then use the Redis command-line interface (redis-cli) to view the database. A prerequisite for this tutorial is an ExpressJS application with a login route and user authentication. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0duyg6kymp7yu4g0jz2i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0duyg6kymp7yu4g0jz2i.png" alt="Overview of tutorial: Express application with rate limiting on the log in route."&gt;&lt;/a&gt;&lt;/p&gt;
Express application with rate limiting on the login route. The key for a particular user stores the number of failed logins. If the number of failed logins exceeds the set maximum number of failed logins, then the route will be blocked. The keys expire after a set amount of time.

  

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

&lt;p&gt;We will use two types of keys to count the number of failed logins. One will be a string made using the user's IP address. The other will be a string made by joining the user's email address and IP address. When a user attempts to log in, if the user exists and the password is not correct, the two keys will be created for the user. &lt;/p&gt;

&lt;p&gt;For example, the keys stored in Redis may look like this after a failed login attempt where the password was incorrect:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;key 1:&lt;/strong&gt; &lt;code&gt;"login_fail_ip-192.168.1.1" : 1&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;key 2:&lt;/strong&gt; &lt;code&gt;"login_fail_username_and_ip-example@example.com_192.168.1.1" : 1&lt;/code&gt; &lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Express app with login route and login authentication (login with username or email)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Registered users stored in a database&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




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

&lt;h2&gt;
  
  
  Set up the rate-limiting middleware
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Middleware used that is not necessary for rate-limiting
&lt;/h3&gt;

&lt;p&gt;This example is from an Express application that uses MongoDB as a database to store the users' data. The following libraries, which will be used in this example, are not necessarily required to set up login rate limiting. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://www.passportjs.org/" rel="noopener noreferrer"&gt;passport&lt;/a&gt; -  authentication middleware&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original" rel="noopener noreferrer"&gt;util.promisify()&lt;/a&gt; - a method defined in the utilities module of the Node.js standard library. It converts methods that return responses using a callback function to instead return responses in a promise object. The syntax is much cleaner.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/connect-flash" rel="noopener noreferrer"&gt;connect-flash&lt;/a&gt; - middleware for flash messages notifying a user if the login was successful or not&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Submitted data on the &lt;code&gt;request.body&lt;/code&gt; is parsed as a JSON object by the built-in middleware function in Express: &lt;code&gt;Express.json()&lt;/code&gt;. The data is stored in JSON format as it is a commonly used, organized, and easily accessible text-based format &lt;sup&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON" rel="noopener noreferrer"&gt;2&lt;/a&gt;&lt;/sup&gt;.  &lt;/p&gt;

&lt;p&gt;These were added as application-level middleware in &lt;code&gt;app.js&lt;/code&gt; using &lt;code&gt;app.use()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rate-limiting middleware
&lt;/h3&gt;

&lt;p&gt;The rate-limiting middleware used is a modification of the &lt;a href="https://www.npmjs.com/package/rate-limiter-flexible" rel="noopener noreferrer"&gt;node-rate-limiter-flexible&lt;/a&gt; library example of how to protect a &lt;a href="https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection" rel="noopener noreferrer"&gt;login endpoint&lt;/a&gt;.  This rate-limiting middleware is written for an Express application using a Redis store, but the same idea can be applied to rate-limiting middleware with other Node.js frameworks such as Koa, Hapi, and Nest or a pure NodeJS application &lt;sup&gt;&lt;a href="https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection" rel="noopener noreferrer"&gt;3&lt;/a&gt;&lt;/sup&gt;. We'll create 2 rate limiters. The first blocks the login route, for one hour, after 10 consecutive failed login attempts.  The failed login counts are reset after a successful login.  Rate limiting is based on the user's email address and IP address. The second blocks the login route, for one day, after 100 failed login attempts. Rate limiting is based on the user's IP address. After this middleware is set up, we will set up the Redis database.&lt;/p&gt;

&lt;p&gt;You can simply rate limit based on IP address only, the problem with this is that IP addresses are not always unique &lt;sup&gt;&lt;a href="https://en.wikipedia.org/wiki/Network_address_translation" rel="noopener noreferrer"&gt;4&lt;/a&gt;&lt;/sup&gt;. A user in a network that shares a public IP address could block other users in that network. If you limit based on email address only, then a malicious user could block someone's access to the application by simply sending many requests to log in. Blocking by email address and IP address adds some flexibility. A user may be blocked using one IP address but could try login from another device. It is important to note that most devices use a dynamic IP address that changes over time and that IP addresses can be modified &lt;sup&gt;&lt;a href="https://support.google.com/fiber/answer/3547208?hl=en&amp;lt;/sup" rel="noopener noreferrer"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;, &lt;/sup&gt;&lt;sup&gt;&lt;a href="https://www.cloudflare.com/learning/ddos/glossary/ip-spoofing" rel="noopener noreferrer"&gt;6&lt;/a&gt;&lt;/sup&gt;.  Rate-limiting aims to minimize brute force attacks to guess a user's password. When rate limiting, user experience also needs to be considered. Being too strict by blocking users after only a few attempts is not good for the user experience. You need to make a trade-off between security and user experience.&lt;/p&gt;

&lt;h4&gt;
  
  
  npm packages required for Redis connection and rate-limiting
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.npmjs.com/package/redis" rel="noopener noreferrer"&gt;redis&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.npmjs.com/package/rate-limiter-flexible" rel="noopener noreferrer"&gt;node-rate-limiter-flexible&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h4&gt;
  
  
  Rate limit controller
&lt;/h4&gt;

&lt;p&gt;Create a file for the rate-limiting middleware. For example, &lt;code&gt;rateLimitController.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes" rel="noopener noreferrer"&gt;controller&lt;/a&gt; that will handle the login route POST request, a connection to Redis will be set up. Then a rate limiter instance that counts and limits the number of failed logins by key will be set up. The &lt;code&gt;storeClient&lt;/code&gt; property of the rate limiter instance will link the rate limiter instance to a Redis database (redisClient) that will be set up later. A points property on the rate limiter instance determines how many login attempts can be made. Keys are created on the instance by using the IP address of the login request or the IP address and email address. When a user fails to log in, points are consumed. This means the count for the key increases. When this count exceeds the points property value, which is the maximum number of failed login attempts allowed, then a message is sent to the user that states that too many login attempts have been made. The keys only exist for a defined amount of time, after this time the rate-limiting is reset. A variable, retrySecs, will be created to determine when a user can try to log in again. The time remaining until another login can be attempted is determined by using the &lt;code&gt;msBeforeNext()&lt;/code&gt; method on the rate limiter instance. &lt;/p&gt;

&lt;p&gt;If the login route is not being rate-limited, then we will authenticate the user. In this tutorial, &lt;a href="http://www.passportjs.org/" rel="noopener noreferrer"&gt;Passport&lt;/a&gt; is used. If the authentication fails and the user's email exists, then a point will be consumed from each rate limiter instance. If authentication is successful the key for the current user, based on IP address and email address, will be deleted and the user will be logged in. A login session is established using the Passport.js method &lt;code&gt;logIn()&lt;/code&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;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redis&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RateLimiterRedis&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rate-limiter-flexible&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;passport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;passport&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// create a Redis client - connect to Redis (will be done later in this tutorial)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;enable_offline_queue&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;// if no connection, an error will be emitted&lt;/span&gt;
&lt;span class="c1"&gt;// handle connection errors&lt;/span&gt;
&lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// this error is handled by an error handling function that will be explained later in this tutorial&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&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;maxWrongAttemptsByIPperDay&lt;/span&gt; &lt;span class="o"&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;maxConsecutiveFailsByEmailAndIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="c1"&gt;// the rate limiter instance counts and limits the number of failed logins by key&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limiterSlowBruteByIP&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;RateLimiterRedis&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;storeClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;keyPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login_fail_ip_per_day&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// maximum number of failed logins allowed. 1 fail = 1 point&lt;/span&gt;
  &lt;span class="c1"&gt;// each failed login consumes a point&lt;/span&gt;
  &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;maxWrongAttemptsByIPperDay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// delete key after 24 hours&lt;/span&gt;
  &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// number of seconds to block route if consumed points &amp;gt; points&lt;/span&gt;
  &lt;span class="na"&gt;blockDuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="c1"&gt;// Block for 1 day, if 100 wrong attempts per day&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;limiterConsecutiveFailsByEmailAndIP&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;RateLimiterRedis&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;storeClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;keyPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login_fail_consecutive_email_and_ip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;maxConsecutiveFailsByEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Delete key after 1 hour&lt;/span&gt;
  &lt;span class="na"&gt;blockDuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="c1"&gt;// Block for 1 hour&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// create key string&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getEmailIPkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;email&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;ip&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="c1"&gt;// rate-limiting middleware controller&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loginRouteRateLimit&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="nx"&gt;req&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;next&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ipAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ip&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;emailIPkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getEmailIPkey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ipAddr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// get keys for attempted login&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;resEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resSlowByIP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;limiterConsecutiveFailsByEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailIPkey&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;limiterSlowBruteByIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ipAddr&lt;/span&gt;&lt;span class="p"&gt;)&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;retrySecs&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="c1"&gt;// Check if IP or email + IP is already blocked&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;resSlowByIP&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;resSlowByIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consumedPoints&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;maxWrongAttemptsByIPperDay&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;retrySecs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resSlowByIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msBeforeNext&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;resEmailAndIP&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;resEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consumedPoints&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;maxConsecutiveFailsByEmailAndIP&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;retrySecs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msBeforeNext&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// the IP and email + ip are not rate limited  &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;retrySecs&lt;/span&gt; &lt;span class="o"&gt;&amp;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="c1"&gt;// sets the response’s HTTP header field&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Retry-After&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;retrySecs&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="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Too many requests. Retry after &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;retrySecs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; seconds.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&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;err&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="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Consume 1 point from limiters on wrong attempt and block if limits reached&lt;/span&gt;
        &lt;span class="k"&gt;try&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;promises&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;limiterSlowBruteByIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ipAddr&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
          &lt;span class="c1"&gt;// check if user exists by checking if authentication failed because of an incorrect password&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;info&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;IncorrectPasswordError&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="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;failed login: not authorized&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="c1"&gt;// Count failed attempts by Email + IP only for registered users&lt;/span&gt;
            &lt;span class="nx"&gt;promises&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nx"&gt;limiterConsecutiveFailsByEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailIPkey&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;// if user does not exist (not registered)&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;info&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;IncorrectUsernameError&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="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;failed login: user does not exist&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="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;promises&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email or password is wrong.&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rlRejected&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;rlRejected&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;rlRejected&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;timeOut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
              &lt;span class="nc"&gt;String&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="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rlRejected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msBeforeNext&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;1&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="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Retry-After&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;res&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Too many login attempts. Retry after &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="s2"&gt; seconds`&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="c1"&gt;// If passport authentication successful&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;user&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;successful login&lt;/span&gt;&lt;span class="dl"&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;resEmailAndIP&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;resEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consumedPoints&lt;/span&gt; &lt;span class="o"&gt;&amp;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="c1"&gt;// Reset limiter based on IP + email on successful authorisation&lt;/span&gt;
          &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;limiterConsecutiveFailsByEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailIPkey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// login (Passport.js method)&lt;/span&gt;
        &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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="nx"&gt;err&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;err&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="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="p"&gt;})(&lt;/span&gt;&lt;span class="nx"&gt;req&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;next&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; &lt;/p&gt;

&lt;h5&gt;
  
  
  Extra notes
&lt;/h5&gt;

&lt;p&gt;Within the RedisClient, the property &lt;code&gt;enable_offline_queue&lt;/code&gt; is set to false. This is done to prevent issues such as slowing down servers if many requests are queued due to a Redis connection failure. The author of node-rate-limiter-flexible recommends this setting unless you have reasons to change it &lt;sup&gt;&lt;a href="https://github.com/animir/node-rate-limiter-flexible/issues/37" rel="noopener noreferrer"&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;req.ip&lt;/code&gt; contains the remote IP address of the request &lt;sup&gt;&lt;a href="https://expressjs.com/en/api.html#req.ip" rel="noopener noreferrer"&gt;8&lt;/a&gt;&lt;/sup&gt;.  If you are using the Express app behind a &lt;a href="https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/" rel="noopener noreferrer"&gt;reverse proxy&lt;/a&gt;, such as Cloudflare CDN, then you should set the Express apps trust proxy setting to true and provide the IP address, subnet, or an array of these that can be trusted as a reverse proxy. If you do not do this, the value of &lt;code&gt;req.ip&lt;/code&gt;  will be the IP address of the reverse proxy &lt;sup&gt;&lt;a href="http://expressjs.com/en/guide/behind-proxies.html" rel="noopener noreferrer"&gt;9&lt;/a&gt;&lt;/sup&gt;.  Also note that running your application locally during development, &lt;code&gt;req.ip&lt;/code&gt; will return 127.0.0.1 if you are using IPv4 or ::1, ::fff:127.0.0.1 if you are using IPv6 &lt;sup&gt;&lt;a href="https://www.npmjs.com/package/request-ip" rel="noopener noreferrer"&gt;10&lt;/a&gt;&lt;/sup&gt;.  These describe the local computer address.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;index.js&lt;/code&gt;, the file with all of your routes. The following route is defined:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;catchErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rateLimitController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loginRouteRateLimit&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;catchErrors&lt;/code&gt; is an error handling function that is used to catch any async-await errors in the controller. This error handling method is from the Wes Bos course &lt;a href="https://learnnode.com/" rel="noopener noreferrer"&gt;Learn Node&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The errors for a Redis connection failure are handled as follows: Node Redis returns a &lt;code&gt;NR_CLOSED&lt;/code&gt; error code if the client's connection dropped. &lt;code&gt;ECONNRESET&lt;/code&gt; is a connection error. You can also set up a retry strategy for Node Redis to try and reconnect if the connection fails &lt;sup&gt;&lt;a href="https://github.com/NodeRedis/node-redis#options-object-properties" rel="noopener noreferrer"&gt;11&lt;/a&gt;&lt;/sup&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NR_CLOSED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ECONNRESET&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;There was a connection error&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;back&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; &lt;/p&gt;

&lt;h2&gt;
  
  
  Set up Redis
&lt;/h2&gt;

&lt;p&gt;The code above will not work yet as there is no Redis database set up. We will create a Redis database in the cloud using &lt;a href="https://redislabs.com/" rel="noopener noreferrer"&gt;Redis Labs&lt;/a&gt;. We will use the free plan. Then we will connect to this database through our Express app. To view the database, we will download Redis locally so that we can use the built-in client redis-cli (command-line interface). We will download and use Redis using Windows Subsystem for Linux (WSL), which allows you to use a Linux terminal in Windows. Other methods are described on the &lt;a href="https://redis.io/download" rel="noopener noreferrer"&gt;Redis website download page&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an account with Redis Labs
&lt;/h3&gt;

&lt;p&gt;Create an account on the &lt;a href="https://redislabs.com/try-free/" rel="noopener noreferrer"&gt;Redis Labs website&lt;/a&gt;. Follow the instructions in the documentation to learn how to &lt;a href="https://docs.redislabs.com/latest/rc/rc-quickstart/" rel="noopener noreferrer"&gt;create a database&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect the Redis instance on Redis Labs with your Express application
&lt;/h3&gt;

&lt;p&gt;In your express application &lt;code&gt;variables.env&lt;/code&gt; add the REDIS_URL:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;REDIS_URL=redis://&amp;lt;password&amp;gt;@&amp;lt;Endpoint&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Your Endpoint and password can be found in the database in the &lt;strong&gt;Configuration&lt;/strong&gt; details of the &lt;strong&gt;View Database&lt;/strong&gt; screen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Endpoint&lt;/strong&gt; setting shows the URL for your database and the port number.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Access Control &amp;amp; Security&lt;/strong&gt; setting shows the password. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the rate limit controller from the previous section, the following code connects the cloud Redis instance, hosted on Redis Labs, to the Express application:&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;redisClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// if no connection, an error will be emitted&lt;/span&gt;
  &lt;span class="na"&gt;enable_offline_queue&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The rate limiter instances connect to the  cloud Redis instance as follows (also from the rate limit controller): &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;limiterSlowBruteByIP&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;RateLimiterRedis&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;storeClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redisClient&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;limiterConsecutiveFailsByUsernameAndIP&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;RateLimiterRedis&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;storeClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redisClient&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; &lt;/p&gt;

&lt;h3&gt;
  
  
  Set up WSL and download Redis
&lt;/h3&gt;

&lt;p&gt;You will be able to rate limit your login route now, the next step is to set up Redis locally so that we can view the Redis database using the Redis command-line interface (redis-cli). Redis works best with Linux. Linux and OS X are the two operating systems where Redis is developed and tested the most. Linux is recommended for deployment &lt;sup&gt;&lt;a href="https://redis.io/topics/introduction" rel="noopener noreferrer"&gt;12&lt;/a&gt;, &lt;a href="https://medium.com/@RedisLabs/windows-subsystem-for-linux-wsl-10e3ca4d434e" rel="noopener noreferrer"&gt;13&lt;/a&gt;&lt;/sup&gt;. &lt;/p&gt;

&lt;p&gt;You can follow &lt;a href="https://medium.com/@RedisLabs/windows-subsystem-for-linux-wsl-10e3ca4d434e" rel="noopener noreferrer"&gt;this article&lt;/a&gt; on how to set up WSL, download and install a supported Linux distro and install Redis locally. Install Redis somewhere outside of your application. The Linux distro used in this tutorial is Ubuntu 18.04.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect the redis-cli to the Redis instance on Redis Labs
&lt;/h3&gt;

&lt;p&gt;We will use the redis-cli locally to see the key-value pairs created. Run your Express application and in a WSL terminal run the redis-cli:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cd into the Redis folder that you downloaded&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;cd redis-6.2.3&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;make sure the server is running&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;sudo service redis-server start&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;to stop the server: &lt;code&gt;sudo service redis-server stop&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you run &lt;code&gt;redis-cli&lt;/code&gt;, you will connect to the local instance of Redis and will run locally on the Localhost (127.0.0.1:6379). To exit, run &lt;code&gt;quit&lt;/code&gt;. To connect the redis-cli to the cloud instance of the Redis Labs database that we created, we'll use the URL-based connection method from the &lt;a href="https://docs.redislabs.com/latest/rs/administering/creating-databases/" rel="noopener noreferrer"&gt;Redis Labs docs&lt;/a&gt;. This connects to the Redis database using an endpoint URL and port number. Check the database &lt;strong&gt;Configuration&lt;/strong&gt; details in the &lt;strong&gt;View Database&lt;/strong&gt; screen to find the endpoint url and password.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ redis-cli -h redis-19836.c9.us-east-1-2.ec2.cloud.redislabs.com
-p 19836 -a astrongpassword


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;h is the host: add your endpoint, without the port number&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;p is the port, which is shown at the end of the endpoint url&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a is access control. Add your password&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can test if the connection worked by typing &lt;code&gt;PING&lt;/code&gt;. If the connection worked redis-cli will return &lt;code&gt;PONG&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;if the response is &lt;code&gt;NOAUTH Authentication required&lt;/code&gt; - check that you typed the password correctly. You can run &lt;code&gt;quit&lt;/code&gt; to exit the redis-cli so that you can try again.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Basic Redis commands
&lt;/h3&gt;

&lt;p&gt;There are many &lt;a href="https://redis.io/commands" rel="noopener noreferrer"&gt;commands&lt;/a&gt; available as shown in the docs. For our use case, we only need to know a few simple commands. You can try them in the redis-cli that is connected to your Redis Labs Redis instance. Note that the commands are all uppercase in the Redis docs, but the commands are not case-sensitive. However, key names are case-sensitive.&lt;/p&gt;

&lt;h4&gt;
  
  
  PING
&lt;/h4&gt;

&lt;p&gt;Checks the connection to the Redis database. If there is a connection, &lt;code&gt;PONG&lt;/code&gt; will be returned.&lt;/p&gt;

&lt;h4&gt;
  
  
  SET
&lt;/h4&gt;

&lt;p&gt;Set the string value of a key. It is used to create a key-value pair or change the value of an existing key.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;gt; SET job teacher
OK


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This sets the key "job" to the value "teacher". The response &lt;code&gt;OK&lt;/code&gt; means that the command was successful.&lt;/p&gt;

&lt;h4&gt;
  
  
  MSET
&lt;/h4&gt;

&lt;p&gt;Like SET, but its sets the values of multiple keys.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;gt; MSET job "teacher" AGE "50" TITLE "Mr."
OK


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  GET
&lt;/h4&gt;

&lt;p&gt;Get the value for a key.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;gt; GET job
"teacher"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  MGET
&lt;/h4&gt;

&lt;p&gt;Get the value of multiple keys.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;gt; MGET job age title
1) "teacher"
2) "50"
3) "Mr."


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  DEL
&lt;/h4&gt;

&lt;p&gt;Deletes a specific key.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;gt; DEL job
(integer) 1 -&amp;gt; this means that it found a key with the name "job" and deleted it. 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you try :&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;gt; GET job
(nil) -&amp;gt; this means that no key with the name "job" exists.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  SCAN
&lt;/h4&gt;

&lt;p&gt;View all keys. It iterates over a collection of keys. It is a cursor-based iterator. If you want to view all entries then run &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;gt; SCAN 0
1) "0"
2) "age"
3) "title"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The first value returned is "0", which indicates that a full iteration occurred. This means that all of the keys in the database were scanned. For more details, you can read up the description of the &lt;a href="https://redis.io/commands/scan" rel="noopener noreferrer"&gt;SCAN command&lt;/a&gt; in the docs. &lt;/p&gt;

&lt;p&gt;If you want to view all keys, excluding the first key then run &lt;code&gt;SCAN 1&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  FLUSHALL
&lt;/h4&gt;

&lt;p&gt;This deletes all of the keys in the database.&lt;/p&gt;

&lt;h4&gt;
  
  
  CLEAR
&lt;/h4&gt;

&lt;p&gt;Clears the terminal.&lt;/p&gt;




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

&lt;h2&gt;
  
  
  Test the rate-limiting
&lt;/h2&gt;

&lt;p&gt;We are going to test one of the rate limiters. Run your application locally and connect to Redis labs via the redis-cli in a WSL terminal. Before starting, make sure all of the keys in your database are deleted by running the command  &lt;code&gt;FLUSHALL&lt;/code&gt;. In your rate limit controller middleware (&lt;code&gt;rateLimitController.js&lt;/code&gt;.), set &lt;code&gt;maxConsecutiveFailsByEmailAndIP&lt;/code&gt; to 3. Set the options &lt;code&gt;duration&lt;/code&gt; and &lt;code&gt;blockDuration&lt;/code&gt;  of &lt;code&gt;limiterConsecutiveFailsByEmailAndIP&lt;/code&gt; to 60. This will allow us to test the rate-limiting quickly. &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxConsecutiveFailsByEmailAndIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&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;limiterConsecutiveFailsByEmailAndIP&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;RateLimiterRedis&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;storeClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;keyPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login_fail_consecutive_email_and_ip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;maxConsecutiveFailsByEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; 
  &lt;span class="na"&gt;blockDuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&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;
  
  
  Failed login with an account that does not exist
&lt;/h3&gt;

&lt;p&gt;Try login using an email (or another user identifier, such as user name, used in your app) that does not exist (not registered).&lt;/p&gt;

&lt;p&gt;After this, in the redis-cli, that is connected to your cloud Redis instance hosted on Redis Labs, view all of the keys. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yourRedisLabsEndpoint&amp;gt; SCAN 0
1)"0"
2) "login_fail_ip_per_day:::1"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;On localhost, &lt;code&gt;req.ip&lt;/code&gt; will return 127.0.0.1 if you are using IPv4 or ::1,  ::fff:127.0.0.1 if you are using IPv6.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can now check the number of consumed points (number of failed logins) of the &lt;code&gt;limiterSlowBruteByIP&lt;/code&gt; rate limiter for the IP that tried to log in.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yourRedisLabsEndpoint&amp;gt; GET login_fail_ip_per_day:::1
"1"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Failed login with an account that does exist
&lt;/h3&gt;

&lt;p&gt;Now try log in with an existing account and use the wrong password. Then view all of the keys in your Redis database.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yourRedisLabsEndpoint&amp;gt; SCAN 0
1)"0"
2) "login_fail_ip_per_day:::1"
3) "login_fail_consecutive_username_and_ip:realuser@example.com_::1"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can now check the number of points consumed for the IP that tried to log in for the &lt;code&gt;limiterSlowBruteByIP&lt;/code&gt; rate limiter key.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yourRedisLabsEndpoint&amp;gt; GET login_fail_ip_per_day:::1
"2"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Check the number of consumed points for the &lt;code&gt;limiterConsecutiveFailsByEmailAndIP&lt;/code&gt; rate limiter key.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yourRedisLabsEndpoint&amp;gt; GET login_fail_consecutive_username_and_ip:realuser@example.com_::1
"1"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Try logging in more than 3 times within 1 minute. After this, you will get this message displayed in your browser:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Too many requests. Retry after 60 seconds.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The login route for the given IP and username pair will be blocked for 60 seconds. This is because the &lt;code&gt;blockDuration&lt;/code&gt; that we set  for the &lt;code&gt;limiterConsecutiveFailsByEmailAndIP&lt;/code&gt; rate limiter is 60 seconds. After 60 seconds, check the number of consumed points for the key again: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yourRedisLabsEndpoint&amp;gt; GET login_fail_ip_per_day:::1
(nil)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It does not exist anymore as we set the &lt;code&gt;duration&lt;/code&gt; property to 60. The key is deleted after 60 seconds. &lt;/p&gt;

&lt;p&gt;Now try login using an existing account with the wrong password. After this, log in with the correct password. This will delete the &lt;code&gt;limiterConsecutiveFailsByEmailAndIP&lt;/code&gt; rate limiter key for the given user and IP pair. This occurs once the login is successful, as can be seen in the rate limit controller:&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resEmailAndIP&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;resEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consumedPoints&lt;/span&gt; &lt;span class="o"&gt;&amp;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="c1"&gt;// Reset on successful authorisation&lt;/span&gt;
          &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;limiterConsecutiveFailsByEmailAndIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailIPkey&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;blockquote&gt;
&lt;p&gt;You can do more thorough testing of POST requests using services such as &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt;, which is a tool used to build and test APIs.&lt;/p&gt;
&lt;/blockquote&gt;




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

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

&lt;p&gt;This is a basic example of how to rate limit a login route in an Express app using node-rate-limiter-flexible and Redis. node-rate-limiter-flexible was used to count and limit the number of login attempts by key. Redis was used to store the keys. We created a rate limiter middleware in an existing application with a login route and authentication. Two rate limiters were created. The first rate limiter rate-limited based on IP. The second rate-limited based on IP and the user's email address. Redis Labs was set up to create an online instance of Redis. The Redis Labs instance was connected to the Express app using an endpoint URL. Redis was installed locally and was connected to the online instance of Redis. Rate-limiting was tested by viewing the database keys, using the redis-cli, after attempted logins. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here are some useful links for further study:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1) &lt;a href="https://www.youtube.com/watch?v=Hbt56gFj998" rel="noopener noreferrer"&gt;Redis Crash Course Tutorial&lt;/a&gt; - Learn the basics of Redis&lt;/p&gt;

&lt;p&gt;2) &lt;a href="https://www.youtube.com/watch?v=oaJq1mQ3dFI" rel="noopener noreferrer"&gt;Redis Caching in Node.js&lt;/a&gt; - Learn how to cache API calls using Redis.&lt;/p&gt;

&lt;p&gt;3) &lt;a href="https://codeburst.io/api-rate-limiting-with-node-and-redis-95354259c768" rel="noopener noreferrer"&gt;API Rate Limiting with Node and Redis&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4) &lt;a href="https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example" rel="noopener noreferrer"&gt;node-rate-limiter-flexible: rate-limiting examples&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5) &lt;a href="https://redis.io/documentation" rel="noopener noreferrer"&gt;Redis documentation&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;6) &lt;a href="https://docs.redislabs.com/latest/" rel="noopener noreferrer"&gt;Redis Labs documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;7) &lt;a href="https://www.youtube.com/c/Redislabs" rel="noopener noreferrer"&gt;Redis Labs YouTube channel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>redis</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
