<?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: Rituraj Borpujari</title>
    <description>The latest articles on DEV Community by Rituraj Borpujari (@riturajborpujari).</description>
    <link>https://dev.to/riturajborpujari</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%2F359290%2Fb12c9f55-09b1-447d-a7f3-784e49c958c3.jpg</url>
      <title>DEV Community: Rituraj Borpujari</title>
      <link>https://dev.to/riturajborpujari</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/riturajborpujari"/>
    <language>en</language>
    <item>
      <title>Building Adda: A high performance group chat application in C</title>
      <dc:creator>Rituraj Borpujari</dc:creator>
      <pubDate>Fri, 14 Mar 2025 16:41:35 +0000</pubDate>
      <link>https://dev.to/riturajborpujari/building-adda-a-high-performance-group-chat-application-in-c-1kam</link>
      <guid>https://dev.to/riturajborpujari/building-adda-a-high-performance-group-chat-application-in-c-1kam</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I don't use C at my work but I do occasionally get back to this fantastic language. Some time back I developed a Terminal alias to &lt;a href="//https:/./riturajborpujari.com/posts/terminal-tools-shell-aliases-directory-bookmarks/"&gt;manage my directory bookmarks and allow faster navigation&lt;/a&gt; using &lt;code&gt;fzf&lt;/code&gt;. I was intrigued by the Unix Philosophy and its overall design.So I began looking at different syscalls Linux provides and understanding some of them. I even tried out building C programs to replicate behaviours of everyday programs like &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt; etc.&lt;/p&gt;

&lt;p&gt;Then I came to a domain which I have never touched in C before: Network Programming. I was kind of scared of that to be honest. But nevertheless I loved Network programming. I am, after all, a Web Developer who builds and maintains Web APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building it out
&lt;/h2&gt;

&lt;p&gt;But I wanted to try it out now. I have a copy of &lt;a href="https://en.wikipedia.org/wiki/UNIX_Network_Programming" rel="noopener noreferrer"&gt;Unix Network Programming&lt;/a&gt; and I referenced that for most parts. But I frequently used Man pages as it helped me look up things faster once I know the name of the function &lt;/p&gt;

&lt;p&gt;Working my way forward with the book and man pages, I was able to create a socket, &lt;code&gt;bind&lt;/code&gt; it to address &lt;code&gt;0.0.0.0&lt;/code&gt; (any IP on my local machine) with a specified port and &lt;code&gt;listen&lt;/code&gt; to it. The &lt;strong&gt;network ordering&lt;/strong&gt; of addresses and ports required some read up and I implemented the order conversion functionality myself before I actually stumbled upon &lt;code&gt;htonl&lt;/code&gt;, and &lt;code&gt;htons&lt;/code&gt; macros.&lt;/p&gt;

&lt;p&gt;With that out of the way, I was able to create a server which listens on a port for TCP connections, &lt;code&gt;accept&lt;/code&gt;s the first one and echoes whatever data the client sends to it. For client program, I still relied on NodeJs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Concurrency and IO Multiplexing
&lt;/h3&gt;

&lt;p&gt;One thing I really like about the man pages is that every page had a little &lt;code&gt;SEE ALSO&lt;/code&gt; section at the end. Without that I wouldn't have found &lt;code&gt;select&lt;/code&gt; function.  &lt;code&gt;select&lt;/code&gt; led me to &lt;code&gt;poll&lt;/code&gt; and soon I enhanced my echo server to use IO Multiplexing to support multiple clients concurrently, all with a single thread.  I later saw this in the book which explained concepts in detail.&lt;/p&gt;

&lt;p&gt;Now I started forwarding messages from one client to all others and I've got a bare-bones chat server instead of a concurrent echo server. Whenever one client is ready with some data to be read, (as &lt;code&gt;poll&lt;/code&gt; tells me this) I can then loop over all the clients again and forward the message (&lt;code&gt;write&lt;/code&gt;) it to all&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;poll&lt;/code&gt; method only polls on the valid file descriptors of the client sockets provided. Any invalid descriptor (&lt;em&gt;negative value&lt;/em&gt;) would be ignored. This helped me immensely. Since I could have a list of fds stored on the stack itself and when a client disconnects, I just simply set the relevant fd in the list as &lt;code&gt;-2&lt;/code&gt;. The message writing logic then can simply skip over all the client fds in the list which have value as &lt;code&gt;-2&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance and Threading
&lt;/h3&gt;

&lt;p&gt;Now all of this is great, but the performance is a bit slower. Handling 2000 concurrent connections takes a bit more time than expected. Time to employ threading.&lt;/p&gt;

&lt;p&gt;I referred back to the book and found &lt;a href="https://en.wikipedia.org/wiki/Pthreads" rel="noopener noreferrer"&gt;Posix Threads&lt;/a&gt;. After trying it out, I laid out my design like this&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;main thread to poll for new connections&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;message_reader&lt;/em&gt; thread to poll for messages from clients&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;message_writer&lt;/em&gt; thread to write available messages to all clients (except
the author)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I reused the same list of fds I used to poll in both &lt;em&gt;message_reader&lt;/em&gt; as well &lt;em&gt;message_writer&lt;/em&gt; to let both the threads know the list of clients. main thread would accept new connections and add it in this list itself.&lt;/p&gt;

&lt;p&gt;The remaining part was to find a way to transfer messages from reader to writer.  I used another file to act as a channel for the messages. That way I don't need to handle locks and can also poll on the channel file in &lt;em&gt;message_writer&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So the &lt;em&gt;message_reader&lt;/em&gt; thread would poll on the clients for data to be read, and once available it would read and write it just to the channel file. A single write operation per read message while iterating over messages to be read from all clients meant that the server could now read faster.&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;em&gt;message_writer&lt;/em&gt; would poll only on the channel file, and once data is available it would read it and write it to all clients in the list.  The ordering of messages is also preserved this way. The message read first is the message that is forwarded first to all clients&lt;/p&gt;

&lt;p&gt;This is great. The message throughput increased significantly and I was happy.  But I soon saw a peculiar thing. Even for zero clients, the cpu usage was pretty high. I had not enabled Non-Blocking IO on any file descriptor so &lt;code&gt;poll&lt;/code&gt; should block until data is available on the provided fds. And since reader has a list of zero fds, it is out of the question. It is configured to use poll with a timeout of 500 ms so as it uses the latest list of fds everytime, but that should not bring the CPU usage to much higher numbers.&lt;/p&gt;

&lt;p&gt;Its obvious that &lt;em&gt;message_writer&lt;/em&gt; is to blame. And I found out the &lt;code&gt;poll&lt;/code&gt; function is returning immediately for the channel file saying it has data to be read (&lt;code&gt;POLLIN&lt;/code&gt; event is being raised). But the subsequent &lt;code&gt;read&lt;/code&gt; returned zero bytes. So it looped over the poll-read logic continuously. This is causing the high CPU usage. I looked into man page of &lt;code&gt;poll&lt;/code&gt; for info and I found out the thing I skipped earlier. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Being "ready" means that the requested operation will not  block;  thus, poll()ing regular  files,  block devices, and other files with no reasonable polling semantic always returns instantly as ready to read and write&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay so using a channel file is not possible. After reading about Unix Sockets (sockets for Interprocess communication) I came to this amazing function &lt;code&gt;socketpair&lt;/code&gt;. It creates a pair of sockets which are connected to each other.  So, data written to any of them is available on the other. Perfect!&lt;/p&gt;

&lt;p&gt;I updated my channel file logic to use channel socket pairs and soon everything came back to normal. CPU Usage is &lt;code&gt;Zero&lt;/code&gt; for zero clients and it also increased predictively now as the number of clients increased&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks
&lt;/h2&gt;

&lt;p&gt;The program acheives the following benchmark result on my local machine&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU: Ryzen 3700x (8 cores 8 threads)&lt;/li&gt;
&lt;li&gt;RAM: 16GB&lt;/li&gt;
&lt;li&gt;Message length: 211 bytes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: CPU usage is divided by the number of cores (&lt;code&gt;top&lt;/code&gt; - Iris Mode off)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Number of Clients&lt;/th&gt;
&lt;th&gt;CPU Usage&lt;/th&gt;
&lt;th&gt;RAM Usage&lt;/th&gt;
&lt;th&gt;1M messages write&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1.6m&lt;/td&gt;
&lt;td&gt;NA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;1.3%&lt;/td&gt;
&lt;td&gt;1.6m&lt;/td&gt;
&lt;td&gt;~4 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;4.9%&lt;/td&gt;
&lt;td&gt;1.6m&lt;/td&gt;
&lt;td&gt;~1.3 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2000&lt;/td&gt;
&lt;td&gt;5.6%&lt;/td&gt;
&lt;td&gt;1.6m&lt;/td&gt;
&lt;td&gt;~0.9 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000&lt;/td&gt;
&lt;td&gt;5.3%&lt;/td&gt;
&lt;td&gt;1.7m&lt;/td&gt;
&lt;td&gt;~1.5 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;The server is working fine now. Obviously this is not ready for production usage as it would have to be inspected for error scenarios, edge cases and security considerations. And its feature list is still at the beginning.&lt;/p&gt;

&lt;p&gt;I named it &lt;strong&gt;Adda&lt;/strong&gt; a word popular in Assamese and many other languages in India, which roughly translates &lt;em&gt;to hang out / chat with a group of friends&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;This was built as a fun project and I enjoyed building this and learned a lot about Network Programming and also C in general.&lt;/p&gt;

&lt;p&gt;In future I would try to enhance this to allow command parsing and User authentication to help better suit the use case. For now, I am happy with what it is!&lt;/p&gt;

&lt;h2&gt;
  
  
  Project repository
&lt;/h2&gt;

&lt;p&gt;The project repository is available on Github here at &lt;a href="https://github.com/riturajborpujari/adda" rel="noopener noreferrer"&gt;Adda&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/UNIX_Network_Programming" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/UNIX_Network_Programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Pthreads" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Pthreads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.man7.org/linux/man-pages/man1/top.1.html" rel="noopener noreferrer"&gt;https://www.man7.org/linux/man-pages/man1/top.1.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>c</category>
      <category>network</category>
      <category>development</category>
    </item>
    <item>
      <title>Building a Downloader in Go</title>
      <dc:creator>Rituraj Borpujari</dc:creator>
      <pubDate>Wed, 12 Mar 2025 06:16:03 +0000</pubDate>
      <link>https://dev.to/riturajborpujari/building-a-downloader-in-go-1d8h</link>
      <guid>https://dev.to/riturajborpujari/building-a-downloader-in-go-1d8h</guid>
      <description>&lt;p&gt;People say Go is well suited for Network applications. With its light&lt;br&gt;
Goroutines and huge standard library it can get most of the job done&lt;br&gt;
without even needing a third-party library.&lt;/p&gt;

&lt;p&gt;Great, let me build a terminal program to download files&lt;/p&gt;
&lt;h2&gt;
  
  
  Accio
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyz01dj6o2gnrzkko2nx0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyz01dj6o2gnrzkko2nx0.gif" alt="harry-potter-casting-spell-accio-dittany" width="400" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://harrypotter.fandom.com/wiki/Summoning_Charm" rel="noopener noreferrer"&gt;summoning charm from Harry Potter&lt;/a&gt;&lt;br&gt;
seems like a fit name for my downloader. Like when Harry Potter says&lt;br&gt;
"Accio Dittany" and out pops the bottle of Dittany potion from &lt;br&gt;
Hermione's bag with an "Undectable Extension Charm", our version of &lt;br&gt;
Accio would do something similar, albeit with URLs.&lt;/p&gt;

&lt;p&gt;So running &lt;code&gt;accio url&lt;/code&gt; would get you the file from the &lt;code&gt;url&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Simple enough! Let's start then.&lt;/p&gt;
&lt;h2&gt;
  
  
  The process
&lt;/h2&gt;

&lt;p&gt;The module &lt;code&gt;net/http&lt;/code&gt; gives us this amazing method for making a GET request -&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http.Get(url string) (resp *httpResponse, err error)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With this, we can run a &lt;code&gt;GET&lt;/code&gt; request to &lt;code&gt;url&lt;/code&gt; and we get a response object&lt;br&gt;
(of type &lt;code&gt;httpResponse&lt;/code&gt;) and a possible error (of type &lt;code&gt;error&lt;/code&gt;). We check for any error that might have occured while making the request and then&lt;br&gt;
move on to reading the data bytes from &lt;code&gt;httpResponse.Body&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But before reading the body, we would need to create and open a file for&lt;br&gt;
writing with the following method. And &lt;code&gt;os&lt;/code&gt; module has the capability we need&lt;/p&gt;

&lt;p&gt;&lt;code&gt;os.OpenFile(name string, flag int, perm fs.FileMode) (*os.File, error)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;we also need &lt;code&gt;os&lt;/code&gt; to get the CLI argument for URL being passed into our program&lt;br&gt;
by the user while running command &lt;code&gt;accio URL&lt;/code&gt;. We need &lt;code&gt;io&lt;/code&gt; module because it has defined the &lt;code&gt;io.EOF&lt;/code&gt; error value that&lt;br&gt;
we need to test to know when we've reached the end of reading the response&lt;br&gt;
body. With the file opened and the response body ready for reading, we would simply&lt;br&gt;
need to loop this following&lt;/p&gt;
&lt;h3&gt;
  
  
  Copy Data process
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Initialize a buffer&lt;/li&gt;
&lt;li&gt;Read &lt;code&gt;n&lt;/code&gt; bytes from response body into a buffer&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;n&lt;/code&gt; is non-zero we write &lt;code&gt;n&lt;/code&gt; bytes to the file&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If error occured is &lt;code&gt;EOF&lt;/code&gt; (End of file - indicates response data end)&lt;/p&gt;

&lt;p&gt;We break the loop (go to step 6)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to step 2 (repeat)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We close the file and the response body&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the actual code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;downloadUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// handle error&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"download"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_WRONLY&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_CREATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModePerm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// handle error&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;512&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;512&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;n&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="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"download error: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&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;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We open the file with &lt;code&gt;flags&lt;/code&gt; as &lt;code&gt;os.O_WRONLY | os.O_CREATE&lt;/code&gt; which causes it to&lt;br&gt;
open a file for writing and the &lt;code&gt;perm&lt;/code&gt; as &lt;code&gt;os.ModePerm&lt;/code&gt; so that the opened file&lt;br&gt;
gets the same permissions as our executable program &lt;code&gt;accio&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We reset the &lt;code&gt;buffer&lt;/code&gt; slice's capacity to &lt;code&gt;512&lt;/code&gt; each time in the loop to&lt;br&gt;
utilize the full capacity and let the &lt;code&gt;Read&lt;/code&gt; method of &lt;code&gt;response.Body&lt;/code&gt; to fill&lt;br&gt;
it up with &lt;code&gt;n&lt;/code&gt; bytes.&lt;/p&gt;

&lt;p&gt;We then proceed to write only &lt;code&gt;n&lt;/code&gt; bytes to the file because that's how much we &lt;br&gt;
read in this iteration from &lt;code&gt;response.Body&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If error has occured, we need to stop everything. If the error is not &lt;code&gt;EOF&lt;/code&gt; &lt;br&gt;
we also log this onto the terminal. Otherwise, we silently break the loop&lt;/p&gt;
&lt;h2&gt;
  
  
  Showing progress
&lt;/h2&gt;

&lt;p&gt;The next part is to show progress of the download. For this I'm going to use the&lt;br&gt;
channel feature of golang. &lt;/p&gt;

&lt;p&gt;Basically the download (more specifically the copy of bytes from response body&lt;br&gt;
to file) would be happening on another go routine and it will send progress&lt;br&gt;
stats over a channel. The main routine can then read messages from this channel&lt;br&gt;
to display progress.&lt;/p&gt;

&lt;p&gt;Here's the structure I used for the download progress status message&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;DownloadStatus&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Error&lt;/span&gt;           &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="n"&gt;IsComplete&lt;/span&gt;      &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;BytesDownloaded&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will suffice. The copying logic will post a message of type&lt;br&gt;
&lt;code&gt;DownloadStatus&lt;/code&gt; on the &lt;code&gt;statusChannel&lt;/code&gt; channel so that the main routine can&lt;br&gt;
display the progress&lt;/p&gt;

&lt;p&gt;here's the updated function to copy data from &lt;code&gt;src&lt;/code&gt; to &lt;code&gt;dest&lt;/code&gt; while posting&lt;br&gt;
updates of the progress&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;copyVerbose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;statusChannel&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;DownloadStatus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COPY_BUFFER_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;DownloadStatus&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;nread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nread&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;nwritten&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;nread&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BytesDownloaded&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nwritten&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="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsComplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&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="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;statusChannel&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;status&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;
  
  
  Showing progress in
&lt;/h3&gt;

&lt;p&gt;Now to show progress on the &lt;code&gt;main&lt;/code&gt; routine, we need to do this&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;create a ticker (which ticks periodically at say 500 ms)&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;select&lt;/code&gt; to read from ticker and the &lt;code&gt;statusChannel&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;if read from statusChannel, store it in a local variable&lt;/li&gt;
&lt;li&gt;if read from ticker channel, show the progress&lt;/li&gt;
&lt;li&gt;go to step 2 and repeat&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;of course, we would close this repeat loop once we find the status message&lt;br&gt;
contains &lt;code&gt;IsComplete&lt;/code&gt; as &lt;code&gt;true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;here's the code for that (partial &lt;code&gt;main&lt;/code&gt; function)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;lastStatus&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;DownloadStatus&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTicker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;downloadUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;DownloadOptions&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Filepath&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;statusChannel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getFormattedSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BytesDownloaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lastStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsComplete&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\x1B&lt;/span&gt;&lt;span class="s"&gt;[1K&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt;completed: %.2f %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lastStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"download failed: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;lastStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\x1B&lt;/span&gt;&lt;span class="s"&gt;[1K&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt;%.2f %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;statusChannel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lastStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The escape sequence in printf (&lt;code&gt;\x1B[1K&lt;/code&gt;) deletes the current line and &lt;code&gt;\r&lt;/code&gt;&lt;br&gt;
moves the cursor to the beginning of the line. &lt;a href="https://www2.ccs.neu.edu/research/gpc/VonaUtils/vona/terminal/vtansi.htm" rel="noopener noreferrer"&gt;See more&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This effectively shows us the updated progress by deleting the old progress&lt;br&gt;
every 500 ms&lt;/p&gt;

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

&lt;p&gt;We've got ourselves a http(s) downloader using Golang's standard libraries only.&lt;br&gt;
The downloader shows progress as it downloads and saves the file with name as&lt;br&gt;
found looking at the url (or &lt;code&gt;download&lt;/code&gt; if the url doesn't contain a&lt;br&gt;
&lt;code&gt;/resource_name.extension&lt;/code&gt; part at the end&lt;/p&gt;

&lt;p&gt;There are many more things that can be done here. Some of the basic ones are&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add multi connections to speed up downloads&lt;/li&gt;
&lt;li&gt;Add pause / resume capability&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both of them requires the usage of response header &lt;code&gt;Accept-Range&lt;/code&gt; which denotes&lt;br&gt;
whether the server supports requesting file data by a specific range. The&lt;br&gt;
corresponding request header is &lt;code&gt;Range&lt;/code&gt; which can be added in the request to let&lt;br&gt;
the server know which range of data we need&lt;/p&gt;

&lt;p&gt;I'll pick this up in the next iteration of &lt;code&gt;Accio&lt;/code&gt; our very own http downloader.&lt;/p&gt;

&lt;h2&gt;
  
  
  Full code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/riturajborpujari/accio" rel="noopener noreferrer"&gt;https://github.com/riturajborpujari/accio&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://pkg.go.dev/std" rel="noopener noreferrer"&gt;https://pkg.go.dev/std&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www2.ccs.neu.edu/research/gpc/VonaUtils/vona/terminal/vtansi.htm" rel="noopener noreferrer"&gt;https://www2.ccs.neu.edu/research/gpc/VonaUtils/vona/terminal/vtansi.htm&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>go</category>
      <category>terminal</category>
      <category>http</category>
      <category>development</category>
    </item>
    <item>
      <title>Competing with JSON.stringify - by building a custom one</title>
      <dc:creator>Rituraj Borpujari</dc:creator>
      <pubDate>Wed, 14 Aug 2024 05:38:03 +0000</pubDate>
      <link>https://dev.to/riturajborpujari/competing-with-jsonstringify-by-building-a-custom-one-53l5</link>
      <guid>https://dev.to/riturajborpujari/competing-with-jsonstringify-by-building-a-custom-one-53l5</guid>
      <description>&lt;p&gt;This came up during a discussion with my friend about Recursion. Why not build &lt;br&gt;
a Javascript &lt;code&gt;JSON.stringify&lt;/code&gt; method as a recursive programming exercise? Seems like a great&lt;br&gt;
idea. &lt;/p&gt;

&lt;p&gt;I quickly drafted out the first version. And it performed horribly! The &lt;br&gt;
&lt;strong&gt;time required was about 4 times that of the standard&lt;/strong&gt; &lt;code&gt;JSON.stringify&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The first draft
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;json_stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;boolean&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;return&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;obj&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&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;return&lt;/span&gt; &lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;obj&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json_stringify&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;properties_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;val&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="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;":&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;json_stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;properties_str&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;By running the following, we can see that our &lt;code&gt;json_stringify&lt;/code&gt; works as&lt;br&gt;
expected.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;assert&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="s2"&gt;console&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;test_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;hobbies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;football&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="s2"&gt;comet study&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="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;json_stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;test_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;test_obj&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test more scenarios, and multiple runs to get an average idea of how our &lt;br&gt;
script runs, we made a simple testing script!&lt;/p&gt;
&lt;h2&gt;
  
  
  A simple testing script
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validity_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;test_values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;test_value&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;test_values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;test_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;fn2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;test_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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;num_runs&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;num_runs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fn&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;end_time&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start_time&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;performance_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counts&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="s2"&gt;Starting performance test with&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;test_obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;counts&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="s2"&gt;Testing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;times&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;duration_std_json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;time&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="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;test_obj&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="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;Std lib JSON.stringify() took&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;duration_std_json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ms&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;duration_custom_json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json_stringify&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;test_obj&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="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;Custom json_stringify() took&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;duration_custom_json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ms&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;test_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;// a deeply nested JS object, ommitted here for brevity &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;test_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string test&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="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;34&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="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&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="nx"&gt;test_obj&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nf"&gt;validity_test&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="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;json_stringify&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;test_values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;performance_test&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Running this we get the timings like the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Testing 1000 &lt;span class="nb"&gt;times
    &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 5 ms
    Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 20 ms
Testing 10000 &lt;span class="nb"&gt;times
    &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 40 ms
    Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 129 ms
Testing 100000 &lt;span class="nb"&gt;times
    &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 388 ms
    Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 1241 ms
Testing 1000000 &lt;span class="nb"&gt;times
    &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 3823 ms
    Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 12275 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It might run differently on different systems but the ratio of the time taken &lt;br&gt;
by std &lt;code&gt;JSON.strngify&lt;/code&gt; to that of our custom &lt;code&gt;json_stringify&lt;/code&gt; should be about &lt;br&gt;
&lt;strong&gt;1:3&lt;/strong&gt; - &lt;strong&gt;1:4&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It could be different too in an interesting case. Read on to know more about &lt;br&gt;
that!&lt;/p&gt;
&lt;h2&gt;
  
  
  Improving performance
&lt;/h2&gt;

&lt;p&gt;The first thing that could be fixed is the use of &lt;code&gt;map&lt;/code&gt; function. It creates&lt;br&gt;
new array from the old one. In our case of objects, it is creating an array of&lt;br&gt;
JSON stringified object properties out of the array containing object entries.&lt;/p&gt;

&lt;p&gt;Similar thing is also happening with stringification of the array elements too.&lt;/p&gt;

&lt;p&gt;We have to loop over the elements in an array, or the entries of an object! But&lt;br&gt;
we can skip creating another array just to join the JSON stringified parts.&lt;/p&gt;

&lt;p&gt;Here's the updated version (only the changed parts shown for brevity)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;json_stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;boolean&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;return&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;val&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&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;return&lt;/span&gt; &lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&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;elements_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;elements_str&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;sep&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;json_stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;sep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;elements_str&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;elements_str&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;typeof&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;properties_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;properties_str&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;sep&lt;/span&gt; &lt;span class="o"&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;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;":&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;json_stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;])}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
      &lt;span class="nx"&gt;sep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;properties_str&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;properties_str&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;And here's the output of the test script now&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Testing 1000 &lt;span class="nb"&gt;times
        &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 5 ms
        Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 6 ms
Testing 10000 &lt;span class="nb"&gt;times
        &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 40 ms
        Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 43 ms
Testing 100000 &lt;span class="nb"&gt;times
        &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 393 ms
        Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 405 ms
Testing 1000000 &lt;span class="nb"&gt;times
        &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 3888 ms
        Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 3966 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks a lot better now. Our custom &lt;code&gt;json_stringify&lt;/code&gt; is taking only 3 ms&lt;br&gt;
more than &lt;code&gt;JSON.stringify&lt;/code&gt; to stringify a deep nested object 10,000 times.&lt;br&gt;
Although this is not perfect, it is an acceptable delay.&lt;/p&gt;
&lt;h2&gt;
  
  
  Squeezing out more??
&lt;/h2&gt;

&lt;p&gt;The current delay could be due to all the string creation and concatenation &lt;br&gt;
that's happening. Every time we run &lt;code&gt;elements_str += sep + json_stringify(element)&lt;/code&gt;&lt;br&gt;
we are concatenating 3 strings.&lt;/p&gt;

&lt;p&gt;Concatenating strings is costly because it requires&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;creating a new string buffer to fit the whole combined string&lt;/li&gt;
&lt;li&gt;copy individual strings to the newly created buffer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By using a &lt;code&gt;Buffer&lt;/code&gt; ourselves and writing the data directly there might give us&lt;br&gt;
a performance improvement. Since we can create a large buffer (say 80 characters)&lt;br&gt;
and then create new buffers to fit 80 characters more when it runs out.&lt;/p&gt;

&lt;p&gt;We won't be avoiding the reallocation / copying of data altogether, but we will&lt;br&gt;
reducing those operations.&lt;/p&gt;

&lt;p&gt;Another possible delay is the recursive process itself! Specifically the&lt;br&gt;
function call which takes up time. Consider our function call &lt;code&gt;json_stringify(val)&lt;/code&gt;&lt;br&gt;
which just has one parameter.&lt;/p&gt;
&lt;h3&gt;
  
  
  Understanding Function calls
&lt;/h3&gt;

&lt;p&gt;The steps would be&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push the return address to the stack&lt;/li&gt;
&lt;li&gt;push the argument reference to the stack&lt;/li&gt;
&lt;li&gt;In the called function

&lt;ol&gt;
&lt;li&gt;Pop the parameter reference from the stack&lt;/li&gt;
&lt;li&gt;Pop the return address from the stack&lt;/li&gt;
&lt;li&gt;push the return value (the stringified part) onto the stack&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;In the calling function

&lt;ol&gt;
&lt;li&gt;Pop off the value returned by the function from the stack&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All these operations happen to ensure function calls happen and this adds CPU&lt;br&gt;
costs.&lt;/p&gt;

&lt;p&gt;If we create a non-recursive algorithm of &lt;code&gt;json_stringify&lt;/code&gt; all these operations&lt;br&gt;
listed above for function call (times the number of such calls) would be&lt;br&gt;
reduced to none.&lt;/p&gt;

&lt;p&gt;This can be a future attempt. &lt;/p&gt;
&lt;h2&gt;
  
  
  NodeJs version differences
&lt;/h2&gt;

&lt;p&gt;One last thing to note here. Consider the following output of the test script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Testing 1000 &lt;span class="nb"&gt;times
        &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 8 ms
        Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 8 ms
Testing 10000 &lt;span class="nb"&gt;times
        &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 64 ms
        Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 51 ms
Testing 100000 &lt;span class="nb"&gt;times
        &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 636 ms
        Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 467 ms
Testing 1000000 &lt;span class="nb"&gt;times
        &lt;/span&gt;Std lib JSON.stringify&lt;span class="o"&gt;()&lt;/span&gt; took 6282 ms
        Custom json_stringify&lt;span class="o"&gt;()&lt;/span&gt; took 4526 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did our custom &lt;code&gt;json_stringify&lt;/code&gt; just perform better than the NodeJs standard&lt;br&gt;
&lt;code&gt;JSON.stringify&lt;/code&gt;???&lt;/p&gt;

&lt;p&gt;Well yes! But this is an older version of NodeJs (&lt;code&gt;v18.20.3&lt;/code&gt;). Turns out, for&lt;br&gt;
this version (and lower also perhaps) our custom made &lt;code&gt;json_stringify&lt;/code&gt; works&lt;br&gt;
faster than the standard library one!&lt;/p&gt;

&lt;p&gt;All the tests for this article (except this last one) has been done with &lt;br&gt;
&lt;strong&gt;Node v22.6.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The performance of JSON.stringify has increased from v18 to v22. This is so great&lt;/p&gt;

&lt;p&gt;It is also important to note that, our script performed better in NodeJs v22.&lt;br&gt;
So, it means, NodeJs has increased the overall performance of the runtime too.&lt;br&gt;
Possibly an update has happened to the underlying &lt;strong&gt;V8 engine&lt;/strong&gt; itself.&lt;/p&gt;

&lt;p&gt;Well, this has been an enjoyable experience for me. And I hope it will be for&lt;br&gt;
you too. And in the midst of all this enjoyment, we learnt a thing or two!&lt;/p&gt;

&lt;p&gt;Keep building, keep testing!&lt;/p&gt;

</description>
      <category>development</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Terminal Tools, Shell Aliases, and directory bookmarks</title>
      <dc:creator>Rituraj Borpujari</dc:creator>
      <pubDate>Fri, 03 May 2024 17:10:52 +0000</pubDate>
      <link>https://dev.to/riturajborpujari/terminal-tools-shell-aliases-and-directory-bookmarks-2jab</link>
      <guid>https://dev.to/riturajborpujari/terminal-tools-shell-aliases-and-directory-bookmarks-2jab</guid>
      <description>&lt;p&gt;I like using terminal tools and programs. They are so handy that you can't ignore once you get used to them. There are many of them at your disposal, each doing something which is unique in their own.&lt;/p&gt;

&lt;p&gt;They do their own thing best, and they work with each other. Take a look at &lt;a href="https://en.wikipedia.org/wiki/Unix_philosophy" rel="noopener noreferrer"&gt;Unix Philosophy&lt;/a&gt; to understand the guiding principles that these tools follow to make them so easy to work with!&lt;/p&gt;

&lt;p&gt;As I begin using these tools and the many ways in which they allow &lt;a href="https://en.wikipedia.org/wiki/Function_composition_(computer_science)" rel="noopener noreferrer"&gt;composability&lt;/a&gt;, I found myself using such composed commands and even scripts. Here's one that allows me to move to frequently used directories without typing the path everytime, from any directory I'm in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Directory bookmarks
&lt;/h2&gt;

&lt;p&gt;We use &lt;code&gt;cd&lt;/code&gt; a lot in terminal. It allows us to change to the directory we want to work on. As I started using &lt;a href="https://wiki.archlinux.org/title/fzf" rel="noopener noreferrer"&gt;fzf&lt;/a&gt;, finding a specific subdirectory became much more easier than before. I can type in &lt;code&gt;cd $(fzf)&lt;/code&gt; and it will open up a search window where I can &lt;a href="https://en.wikipedia.org/wiki/Approximate_string_matching" rel="noopener noreferrer"&gt;fuzzy-search&lt;/a&gt; for a specific directory. I can write a shell alias like &lt;code&gt;alias cdf="cd $(fzf)"&lt;/code&gt; and then I can just type in &lt;code&gt;cdf&lt;/code&gt; and press &lt;code&gt;return&lt;/code&gt; to activate the command. Its great!&lt;/p&gt;

&lt;p&gt;But still, when I'm deep in a particular directory and I wanted to move to another directory which is not a sub dir this gives me a problem. Because the required directory that I want to move into is not a subdirectory, I can't just &lt;code&gt;cdf&lt;/code&gt; any more (atleast not from the current dir). I have to move up the directory structure untill the required directory becomes a subdir to the present working directory. This is inadequate!&lt;/p&gt;

&lt;p&gt;What if I can store certain directories that I frequently &lt;code&gt;cd&lt;/code&gt; into, somewhere in a file, and then use &lt;code&gt;fzf&lt;/code&gt; to match and &lt;code&gt;cd&lt;/code&gt; into whichever one I want. That would be awesome!&lt;/p&gt;

&lt;p&gt;That's what I built with &lt;strong&gt;&lt;code&gt;dmk&lt;/code&gt; (directory bookmark)&lt;/strong&gt;. Its a set of two shell aliases to help me navigate to any directory with ease. From anywhere!!!&lt;/p&gt;

&lt;h3&gt;
  
  
  Marking directories as bookmarks
&lt;/h3&gt;

&lt;p&gt;First things first, I need a way to mark certain directories as important so that I can come back to them when needed. For this, I just need to save the directory path into a file.&lt;/p&gt;

&lt;p&gt;If I run the command &lt;code&gt;pwd &amp;gt;&amp;gt; ~/.dmks&lt;/code&gt;, the present working directory path gets appended to a file called &lt;code&gt;.dmks&lt;/code&gt; in my home directory &lt;code&gt;~&lt;/code&gt;. Here, &lt;code&gt;pwd&lt;/code&gt; command prints the present working directory to terminal, and &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; causes that output to get appended to the filename provided after.&lt;/p&gt;

&lt;p&gt;For simpler frequent usage, I created an alias &lt;code&gt;alias dmk="pwd &amp;gt;&amp;gt; ~/.dmks"&lt;/code&gt;. I added this command into my shell init rc file &lt;code&gt;~/.bashrc&lt;/code&gt; and the alias is available from any shell window I open next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Moving into a bookmarked directory
&lt;/h3&gt;

&lt;p&gt;Okay, now that we have a way of marking directories by saving their path into a file, its time to use &lt;code&gt;fzf&lt;/code&gt; to move into one.&lt;/p&gt;

&lt;p&gt;For this I run the command &lt;code&gt;cd $(cat ~/.dmks | fzf)&lt;/code&gt;. This moves into the directory which is given by the &lt;a href="https://en.wikiversity.org/wiki/Bash_programming/Subshells" rel="noopener noreferrer"&gt;sub-shell command&lt;/a&gt; &lt;code&gt;cat ~/.dmks | fzf&lt;/code&gt;. Whatever is the output of this sub-shell command gets used by &lt;code&gt;cd&lt;/code&gt; and it will cause the change in working directory. It's key to note that, &lt;code&gt;cat ~/.dmks&lt;/code&gt; prints the content of the file &lt;code&gt;~/.dmks&lt;/code&gt; into the shell and because of the pipe operator &lt;code&gt;|&lt;/code&gt; it gets passed on to &lt;code&gt;fzf&lt;/code&gt;. This file has all of our marked directories which we marked with &lt;code&gt;dmk&lt;/code&gt; and this list is passed on to FZF. FZF then shows an interactive search window, from which we can search the required directory from the list of marked directories and select the one we need.&lt;/p&gt;

&lt;p&gt;Again, to help simplify running this command regularly, I have created a shell alias for this too! &lt;code&gt;alias cdmk="cd \$(cat ~/.dmks | fzf)"&lt;/code&gt; creates an alias and I write this command in the shell rc file &lt;code&gt;~/.bashrc&lt;/code&gt; to make it available in any new shell window as well.&lt;/p&gt;

&lt;p&gt;Note the escape character &lt;code&gt;\&lt;/code&gt; is required before &lt;code&gt;$&lt;/code&gt; when writing into the shell rc file! Otherwise, the shell will execute the command itself when initializing the alias! We don't want that! We want us to be able to use the alias, and when we do that, we need the command to run!&lt;/p&gt;

&lt;p&gt;That is that, and I get directory bookmark system available in any of my shell window!!! &lt;code&gt;dmk&lt;/code&gt; and &lt;code&gt;cdmk&lt;/code&gt;!!!&lt;/p&gt;

&lt;p&gt;P.S. here is the &lt;a href="https://gist.github.com/riturajborpujari/096d8b704157a7ad3eb5f8237ba05b52" rel="noopener noreferrer"&gt;link to the gist containing the aliases&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>terminal</category>
    </item>
    <item>
      <title>Twitter API: Searching tweets, replies</title>
      <dc:creator>Rituraj Borpujari</dc:creator>
      <pubDate>Sat, 09 May 2020 14:49:01 +0000</pubDate>
      <link>https://dev.to/riturajborpujari/twitter-api-searching-tweets-replies-2bpj</link>
      <guid>https://dev.to/riturajborpujari/twitter-api-searching-tweets-replies-2bpj</guid>
      <description>&lt;p&gt;&lt;em&gt;Get started with Twitter's API, searching tweets, loading replies&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This project is on &lt;a href="https://github.com/riturajborpujari/twitter-app" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt; as an API server. Clone this to use twitter API immediately(after you've created your twitter developer app), to search for tweets, load replies to tweets.&lt;/p&gt;

&lt;h3&gt;
  
  
  What you need to get started?
&lt;/h3&gt;

&lt;p&gt;You will need a twitter developer app to access the Twitter API. The App will provide you with two keys: API key, and API secret which we will use for requesting data from the API endpoints. Follow the following steps to get yourself the necessary keys.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Apply for a &lt;a href="https://developer.twitter.com/en/apply" rel="noopener noreferrer"&gt;twitter developer account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create a &lt;a href="https://developer.twitter.com/en/apps" rel="noopener noreferrer"&gt;twitter developer app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Generate your app's keys on the app's details page under &lt;strong&gt;Keys and tokens&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Open terminal and run the following command to generate your app's Bearer token.
&lt;code&gt;curl -u '&amp;lt;API key&amp;gt;:&amp;lt;API secret key&amp;gt;' --data 'grant_type=client_credentials' 'https://api.twitter.com/oauth2/token'&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Replace &lt;code&gt;&amp;lt;API key&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;API  secret key&amp;gt;&lt;/code&gt; with your app's key and secret.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; With Bearer token, your app can only search for public data. It can not post tweet, read/write messages from your account. For such purposes, you'll need the Access token and secret too. You can generate them on the same page where you generated your keys. For our use case this will be sufficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project setup
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/riturajborpujari/typescript-boilerplate" rel="noopener noreferrer"&gt;Nodejs Typescript boilerplate here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You are now ready to use Twitter API. We are using a Node.js application and writing in Typescript, but you can use any language you prefer. But depending on your language of choice, you may find a twitter library or may have to build your own. For Node.js, we have a library called &lt;a href="https://www.npmjs.com/package/twitter" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, which we will use to make the requests&lt;/p&gt;

&lt;h4&gt;
  
  
  Add the dependencies
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Twitter library &lt;code&gt;npm install twitter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Types &lt;code&gt;npm install @types/twitter&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Modify environment variables
&lt;/h4&gt;

&lt;p&gt;Open up the &lt;code&gt;src/.env&lt;/code&gt; file and add your app's keys and token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TWITTER_APP_API_KEY=&amp;lt;your-api-key&amp;gt;
TWITTER_APP_API_SECRET=&amp;lt;your-api-secret&amp;gt;
TWITTER_APP_BEARER_TOKEN=&amp;lt;your-bearer-token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this to the config file &lt;code&gt;src/config.js&lt;/code&gt; to load these env variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const twitter = {
    consumer_key: process.env.TWITTER_APP_API_KEY,
    consumer_secret: process.env.TWITTER_APP_API_SECRET,
    bearer_token: process.env.TWITTER_APP_BEARER_TOKEN
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Let's search for some tweets. Shall we?
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;src/app.ts&lt;/code&gt; file write the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Twitter from 'twitter';
import {twitter} from './config';

let tw = new Twitter(twitter);

tw.get('search/tweets', {
    q: '#webdevelopment',
    count: 2
})
    .then(res =&amp;gt; {
        console.log('Response: ',res);
    })
    .catch(err =&amp;gt; {
        console.error(err);
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this code by &lt;code&gt;npm run start&lt;/code&gt; and you should see Twitter respond you with two tweets as an array, and some metadata about the search itself&lt;/p&gt;

&lt;h5&gt;
  
  
  Search parameters
&lt;/h5&gt;

&lt;p&gt;Here, we are only using two properties &lt;code&gt;q&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt;. we are searching for tweets that contain the hashtag &lt;code&gt;#webdevelopment&lt;/code&gt;, and we are retrieving only 2 tweets.&lt;br&gt;
See the full list of properties available &lt;a href="https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h5&gt;
  
  
  Search operators
&lt;/h5&gt;

&lt;p&gt;For &lt;em&gt;standard search&lt;/em&gt;(free with 7 days of data), your search query &lt;code&gt;q&lt;/code&gt; can use a list of &lt;a href="https://developer.twitter.com/en/docs/tweets/search/guides/standard-operators" rel="noopener noreferrer"&gt;standard search operators&lt;/a&gt;. In our example we are searching by hashtag &lt;code&gt;#webdevelopment&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Pagination
&lt;/h3&gt;

&lt;p&gt;For obvious reasons, Twitter allow only a maximum of 100 tweets to load at a time. You can load the next tweets(older), or refresh the search(newer tweets) using two parameters &lt;code&gt;max_id&lt;/code&gt; and &lt;code&gt;since_id&lt;/code&gt;. When you get response from twitter, you get one &lt;code&gt;search_metadata&lt;/code&gt; field which contains &lt;code&gt;next_results&lt;/code&gt; and &lt;code&gt;refresh_url&lt;/code&gt;. From these two query strings, you can filter out the &lt;em&gt;max_id&lt;/em&gt; and &lt;em&gt;since_id&lt;/em&gt; respectively. Then if you want to load the older tweets simply add the max_id to your parameters.(alongside &lt;code&gt;q&lt;/code&gt;).&lt;br&gt;
In my &lt;a href="https://github.com/riturajborpujari/twitter-app" rel="noopener noreferrer"&gt;repo&lt;/a&gt;, there is a &lt;code&gt;PaginationController&lt;/code&gt; class which automatically filters out the max_id and since_id if you just supply next_results and refresh_url respectively.&lt;/p&gt;
&lt;h3&gt;
  
  
  Schema for tweets
&lt;/h3&gt;

&lt;p&gt;While twitter gives a whole lot of detail with tweets, we do not need all that. For example tweets contain both &lt;code&gt;id_str&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt;, but we will only use &lt;code&gt;id_str&lt;/code&gt; as id as it contains the original value. Also what's good is typescript, if we don't use a type for tweet. So, I have created a schema for handling tweets, and also a filter function to filter out tweets in our schema from twitter responses. Check them out at my &lt;a href="https://github.com/riturajborpujari/twitter-app" rel="noopener noreferrer"&gt;repo&lt;/a&gt;. They are in file &lt;code&gt;src/api/twitter/schema.ts&lt;/code&gt; and &lt;code&gt;src/api/twitter/filter/tweetFilter.ts&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Loading replies
&lt;/h3&gt;

&lt;p&gt;Loading replies is a bit tricky. Because, twitter does not provide us API to load replies for a tweet directly. That's sad. But thankfully, twitter standard search operators can be used to fulfill our need. It provides us a &lt;code&gt;to:screen_name&lt;/code&gt; operator which allows us to load replies to a twitter user. The screen name is the twitter handle like &lt;code&gt;@thisisrituraj&lt;/code&gt;, without the &lt;code&gt;@&lt;/code&gt; sign. So to search for replies to my account, I would search using &lt;code&gt;q: "to:thisisrituraj"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This will load replies to my account. But I wanted replies for a particular tweet of mine. Not all. That's what we have to filter out by looking a field in the responded tweets. The &lt;code&gt;in_reply_to_status_id_str&lt;/code&gt; field which holds the id of the tweet for which this tweet is a reply.&lt;/p&gt;

&lt;p&gt;We have to load all the replies to my account, using pagination, and then filter out replies to a particular tweet using its id. But do we have to load all replies to filter out replies to just one tweet. Unfortunately, twitter does not provide us with a tweet's reply count to know how many replies are there for a tweet. BUT..., we it provides us with the timestamp when the tweet was created(&lt;code&gt;created_at&lt;/code&gt; field inside a tweet). And we know that, &lt;em&gt;replies to a tweet can not predate the tweet itself&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So, the steps to load replies are&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the id of the tweet(&lt;code&gt;id_str&lt;/code&gt;) for which we wan't to load replies to.&lt;/li&gt;
&lt;li&gt;Get the user's screen name who posted this tweet.&lt;/li&gt;
&lt;li&gt;Load replies to this user using &lt;code&gt;to&lt;/code&gt; operator&lt;/li&gt;
&lt;li&gt;Filter out replies by comparing &lt;code&gt;in_reply_to_status_id_str&lt;/code&gt; with &lt;code&gt;id_str&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use pagination to keep on loading replies until one of the following occurs

&lt;ul&gt;
&lt;li&gt;We have run out of replies. This means no more replies are there, &lt;em&gt;or&lt;/em&gt; we have loaded replies for past 7 days&lt;/li&gt;
&lt;li&gt;We find a reply whose timestamp predates the timestamp of the tweet&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the code for loading replies. (This is an excerpt from my &lt;a href="https://github.com/riturajborpujari/twitter-app" rel="noopener noreferrer"&gt;repo&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default class TwitterClient {
    // code omitted for brevity

    private async loadRepliesForTweet(tweet: ITweet): Promise&amp;lt;ITweetsResponse&amp;gt; {
        let { user, id_str } = tweet;

        // save tweet's post datestamp
        let tweet_at = new Date(tweet.created_at);

        // load all replies to this user
        let allRepliesToTweet: ITweet[] = [];
        let replies: ITweetsResponse;
        let max_id = null;

        do {
            // load all replies to user
            replies = await this.searchTweets({
                q: `to:${user.screen_name}`,
                max_id,
                include_entities: false,
                count: 100
            });

            // select only replies done to THIS tweet
            replies.tweets.forEach(tweet =&amp;gt; {
                if (tweet.in_reply_to.status_id_str === id_str) {
                    allRepliesToTweet.push(tweet);
                }
            })

            // Get max_id from next_results
            if (replies.search_metadata.next_results) {
                let next = &amp;lt;string&amp;gt;replies.search_metadata.next_results;

                // Use PaginationController to get max_id
                max_id = PaginationController.getParameterFromQueryString(next, 'max_id');
            }
            else {
                // BREAK loop if no more results exist
                break;
            }

            // get last reply tweet's post datestamp
            let last_reply_at = new Date(replies.tweets[replies.tweets.length - 1].created_at);

            // BREAK loop if last reply is earlier than tweet itself
            if (last_reply_at.valueOf() &amp;lt; tweet_at.valueOf()) {
                break;
            }

        } while (true);

        return { tweets: allRepliesToTweet, search_metadata: replies.search_metadata };
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  That's all folks!
&lt;/h3&gt;

&lt;p&gt;That was all about using the Twitter API for searching tweets and loading their replies. We saw, that although Twitter does not allow us to load replies to a tweet directly, we can use its Standard Search Operators and some coding to solve that.&lt;/p&gt;

&lt;p&gt;How do you like this post. Do you have any idea about building something with Twitter API. Let me know. I develop software applications and am very much into problem solving. Connect with &lt;a href="https://in.linkedin.com/in/riturajborpujari" rel="noopener noreferrer"&gt;me on linkedin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>twitter</category>
      <category>node</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Node.js, its awesome!</title>
      <dc:creator>Rituraj Borpujari</dc:creator>
      <pubDate>Fri, 01 May 2020 06:43:51 +0000</pubDate>
      <link>https://dev.to/riturajborpujari/node-js-its-awesome-2nc9</link>
      <guid>https://dev.to/riturajborpujari/node-js-its-awesome-2nc9</guid>
      <description>&lt;p&gt;&lt;em&gt;checkout what makes Nodejs so popular&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Node.js?
&lt;/h3&gt;

&lt;p&gt;Node.js is an open-source and cross-platform JavaScript runtime environment. It runs the V8 JavaScript engine, the core of Google Chrome, outside of the browser.&lt;br&gt;
Node.js uses event-driven non-blocking I/O design, which makes it very performant while reducing CPU and memory usage. A Node.js app runs on a single process, and it doesn't create new thread for every request like other server side languages. There is only one OS process running the event-loop, the core of Node.js application. This event-loop runs your code, and registers callbacks for asynchronous non-blocking I/O. This makes it a suitable candidate for highly scalable containerized applications and microservices.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is V8 Javascript Engine
&lt;/h3&gt;

&lt;p&gt;V8 Javascript engine is a javascript runtime developed in C++ for compiling and executing javascript code in Google Chrome. This is what runs the javascript code from the webpage you're viewing with Chrome. V8 is always evolving, just like the other JavaScript engines around, to speed up the Web and the Node.js ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is non-blocking I/O important?
&lt;/h3&gt;

&lt;p&gt;There is one key understanding here. &lt;em&gt;The speed of an application mostly depends on the speed of the I/O devices&lt;/em&gt;. Read and writes from the main memory(RAM) is the fastest(leave aside CPU registers and caches for simplicity), followed by Disk reads and writes(reading from a file or local database server), followed by Network level I/O(like a HTTP request, database server requests). This is why applications are loaded into main memory, rather than keeping it in disk before executing. Extensive graphical applications loads the data into the GPU memory for faster access by the GPU, as GPU memory(VRAM) provides more than 10X speed in sequential access than RAM.&lt;/p&gt;

&lt;p&gt;But a web application needs to access Network I/O even though its extremely slower than RAM I/O. So in a threaded model like PHP, Python the thread &lt;strong&gt;waits for the I/O method to complete&lt;/strong&gt;. That is why they need multiple threads to handle concurrent requests, where one thread is allocated for every request. But with increase in number of threads comes three main issues&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increase in memory usage(RAM)&lt;/li&gt;
&lt;li&gt;Possibility of deadlocks&lt;/li&gt;
&lt;li&gt;Possible issues in thread concurrency
The second and third one is prevented using careful designing and deadlock detection and breaking methodologies, while the first one needs machines with more RAM, and/ or clustering.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Specialties of Node.js
&lt;/h3&gt;

&lt;p&gt;Because of its event-driven non-blocking I/O nature, &lt;strong&gt;it doesn't wait for the I/O to finish but registers a callback&lt;/strong&gt; to happen when the I/O completes. The event-loop then continues performing other tasks. Node.js internally uses thread pool to manage callbacks and event notification. It will be notified by the callback with an event when I/O method finishes, and it can continue from there. Due to this single threaded nature it provides the ability to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle thousands of concurrent requests without increasing burden on the main memory&lt;/li&gt;
&lt;li&gt;No possibility of a deadlock&lt;/li&gt;
&lt;li&gt;No issues with thread concurrency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of its Javascript(one of the most popular language for the web) based nature, it provides the following advantages&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large collection of user libraries&lt;/li&gt;
&lt;li&gt;One language in both server and client side&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Threads with Node.js?
&lt;/h3&gt;

&lt;p&gt;Although Node.js is designed with single threading in mind, &lt;em&gt;you can also leverage the power of multiple cores when you want&lt;/em&gt;. You can create child processes, manage clusters with simple interfaces. For the extreme cases(like machine learning, complex computations), you can use multi-threaded libraries in C++(the fastest language) as an addon library. The C++ addon libraries provide interface for Node.js applications to use them like regular Node.js libraries. Much like how Tensorflow(written in C++) exposes interface for Python to use it like a python library.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use Node.js?
&lt;/h3&gt;

&lt;p&gt;Because of its simple asynchronous nature and its event-driven model it has preffered choice for applications of different types and scale.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Highly scalable network applications, microservices&lt;/li&gt;
&lt;li&gt;Reducing number of servers while maintaining network throughput&lt;/li&gt;
&lt;li&gt;Increasing the ability to handle large number of concurrent requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From this post you can see why Node.js is becoming the first choice for large scale network applications and services. Many companies have ported over their codebase to Node.js from other languages and have significantly reduced the number of servers, and increased ability to handle concurrent requests while doing so.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wondering if your application idea is suitable for Node.js?
&lt;/h3&gt;

&lt;p&gt;I am a software developer and a skilled problem solver wih good experience in web technologies. I build web applications, scalable APIs, business management systems. Let's discuss your project and we can understand specific needs of your system. Before crafting your idea into application code, I can also help you get a good overview of your system.&lt;/p&gt;

&lt;p&gt;Regards,&lt;br&gt;
Rituraj Borpujari&lt;br&gt;
&lt;a href="https://dev.toLinkedIn%20profile"&gt;https://in.linkedin.com/in/riturajborpujari&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>microservices</category>
    </item>
  </channel>
</rss>
