<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Zack's Learning Journal]]></title><description><![CDATA[A digital garden where I document interesting knowledge discoveries and tricky technical challenges encountered in my daily work.]]></description><link>https://blog.zackhu.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 18:02:37 GMT</lastBuildDate><atom:link href="https://blog.zackhu.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Kafka vs RabitMQ]]></title><description><![CDATA[Kafka: distributed streaming platform
RabbitMQ: message broker
Different Architecture Model: push & pull
Storage: rabbitmq delete after ack, kafka stored on disk, and durable
ordering: rabbitmq harder]]></description><link>https://blog.zackhu.com/kafka-vs-rabitmq</link><guid isPermaLink="true">https://blog.zackhu.com/kafka-vs-rabitmq</guid><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Tue, 24 Mar 2026 17:41:30 GMT</pubDate><content:encoded><![CDATA[<p>Kafka: distributed streaming platform</p>
<p>RabbitMQ: message broker</p>
<p>Different Architecture Model: push &amp; pull</p>
<p>Storage: rabbitmq delete after ack, kafka stored on disk, and durable</p>
<p>ordering: rabbitmq harder to guarentee, kafka: guarenteed per partition</p>
]]></content:encoded></item><item><title><![CDATA[D-L]]></title><description><![CDATA[缩写
全称
中文
操作对象
常见命令



DDL
Data Definition Language
数据定义语言
结构（表、索引等）
CREATE, ALTER, DROP, TRUNCATE


DML
Data Manipulation Language
数据操作语言
数据（行记录）
INSERT, UPDATE, DELETE


DQL
Data Query Language
数据查询语]]></description><link>https://blog.zackhu.com/d-l</link><guid isPermaLink="true">https://blog.zackhu.com/d-l</guid><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Tue, 24 Mar 2026 13:05:16 GMT</pubDate><content:encoded><![CDATA[<table>
<thead>
<tr>
<th><strong>缩写</strong></th>
<th><strong>全称</strong></th>
<th><strong>中文</strong></th>
<th><strong>操作对象</strong></th>
<th><strong>常见命令</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>DDL</strong></td>
<td>Data Definition Language</td>
<td>数据定义语言</td>
<td>结构（表、索引等）</td>
<td><code>CREATE</code>, <code>ALTER</code>, <code>DROP</code>, <code>TRUNCATE</code></td>
</tr>
<tr>
<td><strong>DML</strong></td>
<td>Data Manipulation Language</td>
<td>数据操作语言</td>
<td>数据（行记录）</td>
<td><code>INSERT</code>, <code>UPDATE</code>, <code>DELETE</code></td>
</tr>
<tr>
<td><strong>DQL</strong></td>
<td>Data Query Language</td>
<td>数据查询语言</td>
<td>数据（查询）</td>
<td><code>SELECT</code></td>
</tr>
<tr>
<td><strong>DCL</strong></td>
<td>Data Control Language</td>
<td>数据控制语言</td>
<td>权限</td>
<td><code>GRANT</code>, <code>REVOKE</code></td>
</tr>
<tr>
<td><strong>TCL</strong></td>
<td>Transaction Control Language</td>
<td>事务控制语言</td>
<td>事务</td>
<td><code>COMMIT</code>, <code>ROLLBACK</code>, <code>SAVEPOINT</code></td>
</tr>
</tbody></table>
]]></content:encoded></item><item><title><![CDATA[TCP vs UDP]]></title><description><![CDATA[Transmission control protocol vs User datagram protocol
TCP: use three handshake to establish connection between sender and receiver, more reliable, has flow control, has ordering, and guarantee data ]]></description><link>https://blog.zackhu.com/tcp-vs-udp</link><guid isPermaLink="true">https://blog.zackhu.com/tcp-vs-udp</guid><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Sun, 15 Mar 2026 02:19:03 GMT</pubDate><content:encoded><![CDATA[<p>Transmission control protocol vs User datagram protocol</p>
<p>TCP: use three handshake to establish connection between sender and receiver, more reliable, has flow control, has ordering, and guarantee data arrived exactly as sent. used on browsing, email</p>
<p>UDP: connectionless, no guarantee on the data sent will be received, order. also no overhead on set up connection error checking, faster and lower latency, best for live streaming, online gaming</p>
<p>Connection:</p>
<p>tcp sets up connection, for any data sent there is a three way handshake, to make sure both the sender and receiver are ready.</p>
]]></content:encoded></item><item><title><![CDATA[grep]]></title><description><![CDATA[-w: match whole word
-i: ignore case
-v: match doesn't contain
-n: show line number
-o: only show part that exactly matches
-A n: n lines after the occurrence
-B n: n lines before the occurrence
-C n:]]></description><link>https://blog.zackhu.com/grep</link><guid isPermaLink="true">https://blog.zackhu.com/grep</guid><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Thu, 12 Mar 2026 21:54:14 GMT</pubDate><content:encoded><![CDATA[<p>-w: match whole word</p>
<p>-i: ignore case</p>
<p>-v: match doesn't contain</p>
<p>-n: show line number</p>
<p>-o: only show part that exactly matches</p>
<p>-A n: n lines after the occurrence</p>
<p>-B n: n lines before the occurrence</p>
<p>-C n: both n lines before and after</p>
<p>-E: use regular expression</p>
<p>-c: show matched line count</p>
<p>-r: recursive search, usually for folder</p>
]]></content:encoded></item><item><title><![CDATA[cat - less - more]]></title><description><![CDATA[cat loads the whole file, fit well with reading small config file
less is suggested for reading log, large file, less is more
g - go to top
G - go to bottom
/keyword - search for keyword
b - go backwa]]></description><link>https://blog.zackhu.com/cat-less-more</link><guid isPermaLink="true">https://blog.zackhu.com/cat-less-more</guid><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Thu, 12 Mar 2026 20:19:28 GMT</pubDate><content:encoded><![CDATA[<p>cat loads the whole file, fit well with reading small config file</p>
<p>less is suggested for reading log, large file, less is more</p>
<p>g - go to top</p>
<p>G - go to bottom</p>
<p>/keyword - search for keyword</p>
<p>b - go backward 1 page</p>
<p>f - go forward 1 page</p>
<p>q - quit</p>
<p>common usage of cat:</p>
<p>cat a b &gt; c: concatenate content of a and b and redirect the output to file c</p>
<p>cat &gt; foo.txt: read from stdin and redirect to foo.txt</p>
]]></content:encoded></item><item><title><![CDATA[Snowflake vs UUID vs UUIDv7(2023)]]></title><description><![CDATA[PropertySnowflakeUUID v4UUIDv7Size64-bit int128-bit128-bitFormatInteger (e.g. 1541815603606036480)Hex string (e.g. 550e8400-e29b-...)Hex string (e.g. 018e-...)Time-sortable✅ Yes (ms precision)❌ No✅ Ye]]></description><link>https://blog.zackhu.com/snowflake-vs-uuid-vs-uuidv7-2023</link><guid isPermaLink="true">https://blog.zackhu.com/snowflake-vs-uuid-vs-uuidv7-2023</guid><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Sun, 22 Feb 2026 23:06:14 GMT</pubDate><content:encoded><![CDATA[<table style="min-width:100px"><colgroup><col style="min-width:25px"></col><col style="min-width:25px"></col><col style="min-width:25px"></col><col style="min-width:25px"></col></colgroup><tbody><tr><th><p>Property</p></th><th><p>Snowflake</p></th><th><p>UUID v4</p></th><th><p>UUIDv7</p></th></tr><tr><td><p><strong>Size</strong></p></td><td><p>64-bit int</p></td><td><p>128-bit</p></td><td><p>128-bit</p></td></tr><tr><td><p><strong>Format</strong></p></td><td><p>Integer (e.g. <code>1541815603606036480</code>)</p></td><td><p>Hex string (e.g. <code>550e8400-e29b-...</code>)</p></td><td><p>Hex string (e.g. <code>018e-...</code>)</p></td></tr><tr><td><p><strong>Time-sortable</strong></p></td><td><p>✅ Yes (ms precision)</p></td><td><p>❌ No</p></td><td><p>✅ Yes (ms precision)</p></td></tr><tr><td><p><strong>Globally unique</strong></p></td><td><p>⚠️ Within a coordinated cluster</p></td><td><p>✅ Yes (~2¹²² entropy)</p></td><td><p>✅ Yes (~74 bits entropy)</p></td></tr><tr><td><p><strong>Requires coordination</strong></p></td><td><p>✅ Yes (machine ID assignment)</p></td><td><p>❌ No</p></td><td><p>❌ No</p></td></tr><tr><td><p><strong>DB index performance</strong></p></td><td><p>✅ Excellent (sequential)</p></td><td><p>❌ Poor (random, index fragmentation)</p></td><td><p>✅ Excellent (sequential)</p></td></tr><tr><td><p><strong>Embeds timestamp</strong></p></td><td><p>✅ Yes</p></td><td><p>❌ No</p></td><td><p>✅ Yes</p></td></tr><tr><td><p><strong>Human extractable time</strong></p></td><td><p>✅ Yes</p></td><td><p>❌ No</p></td><td><p>✅ Yes</p></td></tr><tr><td><p><strong>Collision risk</strong></p></td><td><p>Very low (coordinated)</p></td><td><p>Negligible (random)</p></td><td><p>Very low</p></td></tr><tr><td><p><strong>Standard</strong></p></td><td><p>Proprietary</p></td><td><p>RFC 4122</p></td><td><p>RFC 9562 (2023)</p></td></tr><tr><td><p><strong>Cross-system portability</strong></p></td><td><p>⚠️ Epoch is custom</p></td><td><p>✅ Universal</p></td><td><p>✅ Universal</p></td></tr></tbody></table>]]></content:encoded></item><item><title><![CDATA[Diff between @Bean & @Component]]></title><description><![CDATA[Both @Bean and @Component are ways to tell spring ioc container “Hey, i want u to manage these object for me”.
@Component is a class-level annotation. Its basically telling ioc container “during your startup scan, when u meet this class, please initi...]]></description><link>https://blog.zackhu.com/diff-between-bean-and-component</link><guid isPermaLink="true">https://blog.zackhu.com/diff-between-bean-and-component</guid><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Wed, 04 Feb 2026 02:44:05 GMT</pubDate><content:encoded><![CDATA[<p>Both @Bean and @Component are ways to tell spring ioc container “Hey, i want u to manage these object for me”.</p>
<p>@Component is a class-level annotation. Its basically telling ioc container “during your startup scan, when u meet this class, please initiate it and keep it in your pocket”</p>
<ul>
<li><p>Sterotypes:</p>
<ul>
<li><p>@Controller: for web request handler</p>
</li>
<li><p>@Service: for business logic</p>
</li>
<li><p>@Repository: for data access</p>
</li>
</ul>
</li>
<li><p>Best for: you own the source code and have full control over the code</p>
</li>
</ul>
<p>@Bean is a method-level annotation. Usually found in a class marked with @Configuration. Instead of spring find the class and do the job, you write code to initialize it and return it.</p>
<ul>
<li>Best for: third party libaries where we have no access to the source code so that we can not annotate with @Component'</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[navigator.sendBeacon VS fetch + keepalive]]></title><description><![CDATA[When try to send some requests to the backend whenever frontend user ‘leave’ the page, there are two approaches navigator.sendBeacon or fetch with keepalive set to true.
So what is the tradeoff?
Advantages of navigator.sendBeacon:

Specifically desig...]]></description><link>https://blog.zackhu.com/navigatorsendbeacon-vs-fetch-keepalive</link><guid isPermaLink="true">https://blog.zackhu.com/navigatorsendbeacon-vs-fetch-keepalive</guid><category><![CDATA[fetch]]></category><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Mon, 10 Feb 2025 02:40:14 GMT</pubDate><content:encoded><![CDATA[<p>When try to send some requests to the backend whenever frontend user ‘leave’ the page, there are two approaches <strong>navigator.sendBeacon</strong> or <strong>fetch with keepalive set to true.</strong></p>
<h2 id="heading-so-what-is-the-tradeoff">So what is the tradeoff?</h2>
<h3 id="heading-advantages-of-navigatorsendbeacon">Advantages of navigator.sendBeacon:</h3>
<ul>
<li><p>Specifically designed for sending data when a page is being unloaded</p>
</li>
<li><p>Asynchronous with low priority, won't block page unload process</p>
</li>
<li><p>Browser ensures data transmission completion even after page closure</p>
</li>
<li><p>Simple to use with a clean API interface</p>
</li>
<li><p>Automatically uses POST method</p>
</li>
<li><p>No need to handle responses, ideal for one-way data reporting</p>
</li>
</ul>
<h3 id="heading-limitations-of-navigatorsendbeacon">Limitations of navigator.sendBeacon:</h3>
<ul>
<li><p>Only supports POST requests</p>
</li>
<li><p>Cannot receive response content</p>
</li>
<li><p>Size limitations (Chrome limits to approximately 64KB)</p>
</li>
<li><p>No custom headers support (except Content-Type)</p>
</li>
</ul>
<h3 id="heading-advantages-of-fetch-keepalive">Advantages of fetch + keepalive:</h3>
<ul>
<li><p>Supports all HTTP methods (GET, POST, PUT, etc.)</p>
</li>
<li><p>Allows custom request headers</p>
</li>
<li><p>Can handle response content</p>
</li>
<li><p>No data size limitations</p>
</li>
<li><p>More flexible error handling</p>
</li>
</ul>
<h3 id="heading-limitations-of-fetch-keepalive">Limitations of fetch + keepalive:</h3>
<ul>
<li><p>More complex implementation</p>
</li>
<li><p>Requires manual keepalive option setting</p>
</li>
<li><p>Slightly lower browser compatibility compared to sendBeacon</p>
</li>
</ul>
<h3 id="heading-usage-examples">Usage examples:</h3>
<ol>
<li>Using navigator.sendBeacon (for simple data reporting):</li>
</ol>
<pre><code class="lang-javascript">javascriptCopywindow.addEventListener(<span class="hljs-string">'unload'</span>, <span class="hljs-function">() =&gt;</span> {
  navigator.sendBeacon(<span class="hljs-string">'/api/log'</span>, <span class="hljs-built_in">JSON</span>.stringify({
    <span class="hljs-attr">event</span>: <span class="hljs-string">'page_exit'</span>,
    <span class="hljs-attr">duration</span>: performance.now()
  }));
});
</code></pre>
<ol start="2">
<li>Using fetch + keepalive (for more control):</li>
</ol>
<pre><code class="lang-javascript">javascriptCopywindow.addEventListener(<span class="hljs-string">'unload'</span>, <span class="hljs-function">() =&gt;</span> {
  fetch(<span class="hljs-string">'/api/sync'</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
    <span class="hljs-attr">keepalive</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
      <span class="hljs-string">'Authorization'</span>: <span class="hljs-string">'Bearer token'</span>
    },
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
      <span class="hljs-attr">data</span>: <span class="hljs-string">'important_data'</span>
    })
  });
});
</code></pre>
<p><strong>Recommendation:</strong> Choose navigator.sendBeacon for simple analytics and logging scenarios, and fetch + keepalive when you need more control over the request or need to handle responses. For critical data, consider synchronizing during user interactions rather than waiting for page unload.</p>
]]></content:encoded></item><item><title><![CDATA[--save VS --save-dev]]></title><description><![CDATA[When installing npm packages, there are two options provided:

—save (-S)

—save-dev (-D)


So what is the diff?
npm install <package> —save

Is equivalent to npm install <package>, which is the default behavior.

It install the package under node_mo...]]></description><link>https://blog.zackhu.com/save-vs-save-dev</link><guid isPermaLink="true">https://blog.zackhu.com/save-vs-save-dev</guid><category><![CDATA[npm]]></category><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Tue, 21 Jan 2025 18:41:13 GMT</pubDate><content:encoded><![CDATA[<p>When installing npm packages, there are two options provided:</p>
<ul>
<li><p><strong>—save (-S)</strong></p>
</li>
<li><p><strong>—save-dev (-D)</strong></p>
</li>
</ul>
<p>So what is the diff?</p>
<h2 id="heading-npm-install-ltpackagegt-save"><strong>npm install &lt;package&gt; —save</strong></h2>
<ul>
<li><p>Is equivalent to <strong>npm install &lt;package&gt;</strong>, which is the default behavior.</p>
</li>
<li><p>It install the package under <strong>node_modules</strong>, and add the package’s version information into the <strong>package.json’s dependencies.</strong></p>
</li>
</ul>
<h2 id="heading-npm-install-ltpackagegt-save-dev"><strong>npm install &lt;package&gt; —save-dev</strong></h2>
<ul>
<li><p>Not the default behavior, === <strong>npm install &lt;package&gt; -D</strong>.</p>
</li>
<li><p>It install the package under <strong>node_modules</strong>, and add the package’s version information into the package.json’s <strong><em>devDependencies</em>.</strong></p>
</li>
<li><p>These packages would not be install in <strong>prod env.</strong></p>
</li>
<li><p>Suitable for packages that would only be used in <strong>dev env</strong>, like eslint, webpack, @types/react (type definition packages, provided by TS community)</p>
</li>
</ul>
<h3 id="heading-note-the-reason-typesreact-exist-only-in-the-dev-env-is">Note: the reason @types/react exist only in the dev env is</h3>
<ul>
<li><p>Type definitions are only used during development to provide code hints and type checking</p>
</li>
<li><p>These type definitions are not needed in the production environment</p>
</li>
<li><p>All type information is removed in the compiled JavaScript code</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Top level Objects in browser]]></title><description><![CDATA[window

window.innerHeight

window.innerWidth

window.navigator

window.location

url info


window.history

window.localStorage

window.sessionStorage


methods:

window.alert()

window.setTimeout()

window.open()

open a new tab by default

window....]]></description><link>https://blog.zackhu.com/top-level-objects-in-browser</link><guid isPermaLink="true">https://blog.zackhu.com/top-level-objects-in-browser</guid><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Fri, 10 Jan 2025 23:15:55 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-window">window</h2>
<ul>
<li><p>window.innerHeight</p>
</li>
<li><p>window.innerWidth</p>
</li>
<li><p>window.navigator</p>
</li>
<li><p>window.location</p>
<ul>
<li>url info</li>
</ul>
</li>
<li><p>window.history</p>
</li>
<li><p>window.localStorage</p>
</li>
<li><p>window.sessionStorage</p>
</li>
</ul>
<p>methods:</p>
<ul>
<li><p>window.alert()</p>
</li>
<li><p>window.setTimeout()</p>
</li>
<li><p>window.open()</p>
<ul>
<li><p>open a new tab by default</p>
</li>
<li><p>window.open("https://example.com", "_blank");</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-navigator">navigator</h2>
<ul>
<li><p>navigator.userAgent</p>
</li>
<li><p>navigator.language</p>
</li>
<li><p>navigator.platform</p>
</li>
<li><p>navigator.onLine</p>
</li>
<li><p>navigator.geoLocation</p>
</li>
</ul>
<h2 id="heading-document">document</h2>
<ul>
<li><p>document.title</p>
</li>
<li><p>document.cookie <em>// cookie</em></p>
</li>
<li><p>document.location <em>// URL</em> related</p>
</li>
<li><p>document.getElementById()</p>
</li>
<li><p>document.querySelector()</p>
</li>
<li><p>document.createElement()</p>
</li>
</ul>
<h2 id="heading-location">location</h2>
<ul>
<li><p>location.href <em>// full URL</em></p>
</li>
<li><p>location.protocol</p>
</li>
<li><p>location.host</p>
</li>
<li><p>location.hostname</p>
</li>
<li><p>location.port</p>
</li>
<li><p>location.pathname</p>
</li>
<li><p>location.search</p>
</li>
<li><p>location.hash</p>
</li>
</ul>
<h2 id="heading-history">history</h2>
<ul>
<li><p>history.back()</p>
</li>
<li><p>history.forward()</p>
</li>
<li><p>history.pushState()</p>
</li>
<li><p>history.replaceState()</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[./public or ./src/assets ?]]></title><description><![CDATA[There are two place to put resources that would be later imported into a react project, src/assets/ folder and public/ folder. So what is the diff?

Build Processing


src/assets: Files will be processed by build tools (like webpack, Vite)

Images ma...]]></description><link>https://blog.zackhu.com/public-or-srcassets</link><guid isPermaLink="true">https://blog.zackhu.com/public-or-srcassets</guid><category><![CDATA[React]]></category><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Fri, 10 Jan 2025 18:46:04 GMT</pubDate><content:encoded><![CDATA[<p>There are two place to put resources that would be later imported into a react project, <strong>src/assets/</strong> folder and <strong>public/</strong> folder. <strong>So what is the diff?</strong></p>
<ol>
<li>Build Processing</li>
</ol>
<ul>
<li><p><code>src/assets</code>: Files will be processed by build tools (like webpack, Vite)</p>
<ul>
<li><p>Images may be compressed and optimized</p>
</li>
<li><p>CSS/SCSS will be compiled and prefixed</p>
</li>
<li><p>Filenames will be hashed, e.g., <code>logo.png</code> → <code>logo.a5d4f.png</code>, for cache control</p>
</li>
<li><p><strong>Filename caching is critical for updates, since the browser would cache the resource. If the browser find no changes on the name, it would not fetch the updated version, through giving them a hash name it is easier to do cache control and version control.</strong></p>
</li>
</ul>
</li>
<li><p><code>public</code>: Files will be copied to their build directory as-is</p>
<ul>
<li>No compression or optimization</li>
</ul>
</li>
</ul>
<ul>
<li><p>Filenames remain unchanged</p>
</li>
<li><p>Suitable for files that need fixed paths</p>
</li>
</ul>
<ol start="2">
<li>Usage Method</li>
</ol>
<ul>
<li><code>src/assets</code>: Need to be imported</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> logo <span class="hljs-keyword">from</span> <span class="hljs-string">'@/assets/images/logo.png'</span>
</code></pre>
<ul>
<li><code>public</code>: Referenced directly via absolute path</li>
</ul>
<pre><code class="lang-javascript">&lt;img src=<span class="hljs-string">"/images/logo.png"</span> /&gt;
</code></pre>
<ol start="3">
<li>Use Case Examples: Files to put in <code>public</code>:</li>
</ol>
<ul>
<li><p>favicon.ico</p>
</li>
<li><p>robots.txt</p>
</li>
<li><p>sitemap.xml</p>
</li>
<li><p>Resources that need to be referenced directly in index.html</p>
</li>
<li><p>Files that require fixed access paths</p>
</li>
<li><p>Large media files (like videos) that don't need build processing</p>
</li>
</ul>
<p>Files to put in <code>src/assets</code>:</p>
<ul>
<li><p>Images used by components</p>
</li>
<li><p>Style files</p>
</li>
<li><p>Other resources that need build tool processing</p>
</li>
<li><p>Files that need frequent modifications</p>
</li>
</ul>
<p>In simple terms, if a resource needs to be processed by build tools or changes frequently, put it in <code>src/assets</code>; if it needs to remain unchanged with a fixed path, put it in <code>public</code>.</p>
<p>Here is a sample of using Vite’s plugin to optimize &amp; compress the image.</p>
<pre><code class="lang-javascript">
<span class="hljs-comment">// vite.config.js</span>
<span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vite'</span>
<span class="hljs-keyword">import</span> imagemin <span class="hljs-keyword">from</span> <span class="hljs-string">'vite-plugin-imagemin'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  <span class="hljs-attr">plugins</span>: [
    imagemin({
      <span class="hljs-comment">// WebP conversion</span>
      <span class="hljs-attr">webp</span>: {
        <span class="hljs-attr">quality</span>: <span class="hljs-number">75</span>
      },
      <span class="hljs-comment">// PNG compression</span>
      <span class="hljs-attr">pngquant</span>: {
        <span class="hljs-attr">quality</span>: [<span class="hljs-number">0.8</span>, <span class="hljs-number">0.9</span>],
        <span class="hljs-attr">speed</span>: <span class="hljs-number">4</span>
      },
      <span class="hljs-comment">// JPEG compression</span>
      <span class="hljs-attr">mozjpeg</span>: {
        <span class="hljs-attr">quality</span>: <span class="hljs-number">75</span>
      }
    })
  ]
})
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Interview question: React performance optimization]]></title><description><![CDATA[I get an interview question, which is: what if there are 10k tasks waiting for process in the front end, how to ensure the tasks does not freeze the page.
My first thought was web worker, we could create web worker and run the tasks on another thread...]]></description><link>https://blog.zackhu.com/interview-question-react-performance-optimization</link><guid isPermaLink="true">https://blog.zackhu.com/interview-question-react-performance-optimization</guid><category><![CDATA[React]]></category><category><![CDATA[interview questions]]></category><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Wed, 08 Jan 2025 04:09:02 GMT</pubDate><content:encoded><![CDATA[<p>I get an interview question, which is: <mark>what if there are 10k tasks waiting for process in the front end, how to ensure the tasks does not freeze the page.</mark></p>
<p>My first thought was web worker, we could create <strong>web worker</strong> and run the tasks on <strong>another thread</strong>, without blocking the main thread that is responsible for <strong>rendering</strong>. (Obviously the task is not related to ui rendering, since web worker have no access to the <strong>DOM</strong>)</p>
<p>While they told me that another solution could be <strong>batch processing</strong>, like using setTimeout(), and there is one more api could be used in this scenario: <strong>requestIdleCallback.</strong> This api would register a callback function and would get it executed when the main thread is idle.</p>
<p>Here is a sample:</p>
<pre><code class="lang-javascript">requestIdleCallback(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">deadline</span>) </span>{
  <span class="hljs-comment">// check if there is enough idle time in the browser</span>
  <span class="hljs-keyword">while</span> (deadline.timeRemaining() &gt; <span class="hljs-number">0</span>) {
    <span class="hljs-comment">// execute the task, untill there is no more idle time left</span>
    doSomeTask();
  }
}, {<span class="hljs-attr">timeout</span>: <span class="hljs-number">2000</span>});  <span class="hljs-comment">// force execution if the browser is not idle within 2 seconds</span>
</code></pre>
<p>The final take away from this interview question is that: to ensure the browser remain smooth and doesn’t freeze, the key is to <strong>avoid long-running synchronous tasks</strong> that block the main thread.</p>
]]></content:encoded></item><item><title><![CDATA[SSE vs webSocket vs Long Polling]]></title><description><![CDATA[I was learning SSE today, and kinda confused about the SSE with other server-client communication methods, so here is short summary of the learning outcome.
This post is a shallow comparison between the normal http requests, short polling, long polli...]]></description><link>https://blog.zackhu.com/sse-vs-websocket-vs-long-polling</link><guid isPermaLink="true">https://blog.zackhu.com/sse-vs-websocket-vs-long-polling</guid><category><![CDATA[websockets]]></category><category><![CDATA[longpolling]]></category><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Wed, 08 Jan 2025 02:53:13 GMT</pubDate><content:encoded><![CDATA[<p>I was learning SSE today, and kinda confused about the SSE with other server-client communication methods, so here is short summary of the learning outcome.</p>
<p>This post is a <strong>shallow comparison</strong> between the normal <strong>http requests</strong>, <strong>short polling</strong>, <strong>long polling</strong>, <strong>webSocket</strong>, and <strong>SSE.</strong></p>
<ul>
<li><p><strong>Communication Method</strong></p>
<ul>
<li><p><strong>HTTP Requests:</strong> One-way request/response.</p>
</li>
<li><p><strong>Short Polling:</strong> One-way request/response.</p>
</li>
<li><p><strong>Long Polling:</strong> One-way request/response.</p>
</li>
<li><p><strong>WebSocket:</strong> Full-duplex, bidirectional communication.</p>
</li>
<li><p><strong>SSE:</strong> One-way communication (server to client).</p>
</li>
</ul>
</li>
<li><p><strong>Connection Persistence</strong></p>
<ul>
<li><p><strong>HTTP Requests:</strong> A new connection is established for every request.</p>
</li>
<li><p><strong>Short Polling:</strong> Each request closes after completion.</p>
</li>
<li><p><strong>Long Polling:</strong> Each request closes after completion.</p>
</li>
<li><p><strong>WebSocket:</strong> Persistent connection until explicitly closed.</p>
</li>
<li><p><strong>SSE:</strong> Persistent connection until explicitly closed.</p>
</li>
</ul>
</li>
<li><p><strong>Real-Time Capability</strong></p>
<ul>
<li><p><strong>HTTP Requests:</strong> Low (requires new requests after each response).</p>
</li>
<li><p><strong>Short Polling:</strong> Medium (depends on polling frequency).</p>
</li>
<li><p><strong>Long Polling:</strong> Medium-High (server can push data proactively).</p>
</li>
<li><p><strong>WebSocket:</strong> Very high (minimal latency).</p>
</li>
<li><p><strong>SSE:</strong> Medium-High (server can push data proactively).</p>
</li>
</ul>
</li>
<li><p><strong>Performance</strong></p>
<ul>
<li><p><strong>HTTP Requests:</strong> High overhead (frequent connection setup).</p>
</li>
<li><p><strong>Short Polling:</strong> Medium (frequent requests).</p>
</li>
<li><p><strong>Long Polling:</strong> Lower (reduces unnecessary requests).</p>
</li>
<li><p><strong>WebSocket:</strong> Optimal (single connection, low overhead).</p>
</li>
<li><p><strong>SSE:</strong> Efficient (single connection, low overhead).</p>
</li>
</ul>
</li>
<li><p><strong>Use Cases</strong></p>
<ul>
<li><p><strong>HTTP Requests:</strong> Static data fetching or short-lived interactions.</p>
</li>
<li><p><strong>Short Polling:</strong> Scenarios with infrequent data updates (e.g., weather updates).</p>
</li>
<li><p><strong>Long Polling:</strong> Applications needing real-time updates (e.g., chat systems).</p>
</li>
<li><p><strong>WebSocket:</strong> High-frequency, real-time bidirectional data exchange.</p>
</li>
<li><p><strong>SSE:</strong> One-way real-time data streams (e.g., notifications, live feeds).</p>
</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Arrow Function vs Normal Method]]></title><description><![CDATA[this binding:

Arrow function:

Does not has its own this keyword, it inherits this from the surrounding lexical scope where it was defined.

This feature is particularly useful when working with callbacks, as the context in which the function is cre...]]></description><link>https://blog.zackhu.com/arrow-function-vs-normal-method</link><guid isPermaLink="true">https://blog.zackhu.com/arrow-function-vs-normal-method</guid><category><![CDATA[#arrowfunction]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Mon, 06 Jan 2025 03:32:12 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-this-binding"><code>this</code> binding:</h3>
<ul>
<li><p><strong>Arrow function:</strong></p>
<ul>
<li><p>Does not has its own <code>this</code> keyword, it <strong>inherits</strong> <code>this</code> from the surrounding lexical scope where it was defined.</p>
</li>
<li><p>This feature is particularly useful when working with <strong>callbacks</strong>, as the <strong>context</strong> in which the function is <strong>created</strong> may differ from the <strong>context</strong> in which it is <strong>called</strong></p>
</li>
<li><p><strong>(a) Declared in the Global Context</strong></p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> arrowFunction = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>);
  };

  <span class="hljs-comment">// Arrow functions do not have their own `this`</span>
  arrowFunction(); <span class="hljs-comment">// `this` refers to the surrounding lexical scope (global in this case)</span>
</code></pre>
<h4 id="heading-b-inside-an-object"><strong>(b) Inside an Object</strong></h4>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> obj = {
    <span class="hljs-attr">value</span>: <span class="hljs-number">42</span>,
    <span class="hljs-attr">arrowFunction</span>: <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>);
    },
  };

  obj.arrowFunction(); <span class="hljs-comment">// `this` still refers to the surrounding scope, not `obj` (global or outer context)</span>
</code></pre>
<h4 id="heading-c-nested-inside-a-normal-function"><strong>(c) Nested Inside a Normal Function</strong></h4>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> obj = {
    <span class="hljs-attr">value</span>: <span class="hljs-number">42</span>,
    <span class="hljs-attr">normalFunction</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> arrowFunction = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>);
      };
      arrowFunction(); <span class="hljs-comment">// `this` refers to `obj` because it inherits from the surrounding `normalFunction`</span>
    },
  };

  obj.normalFunction(); <span class="hljs-comment">// `this` is `obj`</span>
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Normal function:</strong></p>
<ul>
<li><p>The value of <code>this</code> is <strong>dynamic</strong> and depends on how the function is called.</p>
</li>
<li><p>It can change when the function is invoked using <code>.call</code>, <code>.apply</code>, or <code>.bind</code>.</p>
</li>
<li><p><strong>(a) Function Declaration</strong></p>
<pre><code class="lang-javascript">  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">normalFunction</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>);
  }

  <span class="hljs-comment">// Calling it in the global context</span>
  normalFunction(); <span class="hljs-comment">// In browsers: `window`, in Node.js: `global`</span>
</code></pre>
<h4 id="heading-b-function-expression"><strong>(b) Function Expression</strong></h4>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> normalFunction = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>);
  };

  <span class="hljs-comment">// Calling it in the global context</span>
  normalFunction(); <span class="hljs-comment">// In browsers: `window`, in Node.js: `global`</span>
</code></pre>
<h4 id="heading-c-as-a-method-of-an-object"><strong>(c) As a Method of an Object</strong></h4>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> obj = {
    <span class="hljs-attr">value</span>: <span class="hljs-number">42</span>,
    <span class="hljs-attr">normalFunction</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>);
    },
  };

  obj.normalFunction(); <span class="hljs-comment">// `this` refers to `obj`</span>
</code></pre>
<h4 id="heading-d-extracted-from-an-object"><strong>(d) Extracted from an Object</strong></h4>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> extractedFunction = obj.normalFunction;
  extractedFunction(); <span class="hljs-comment">// `this` is `undefined` in strict mode or `window/global` in non-strict mode</span>
</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="heading-arguments-object"><strong>Arguments Object</strong></h3>
<ul>
<li><p><strong>Normal Method</strong>:</p>
<ul>
<li>Has access to the <code>arguments</code> <strong>object</strong>, which is an array-like object containing all the arguments passed to the function. (How come I just got to know about this?!!)</li>
</ul>
</li>
</ul>
<pre><code class="lang-javascript">    javascriptCopy codefunction normalFunction() {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">arguments</span>);
    }
    normalFunction(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>); <span class="hljs-comment">// [1, 2, 3]</span>
</code></pre>
<ul>
<li><p><strong>Arrow Function</strong>:</p>
<ul>
<li><strong>Does not have its own</strong> <code>arguments</code> object. To access arguments, you must use <strong>rest parameters.</strong></li>
</ul>
</li>
</ul>
<pre><code class="lang-javascript">    javascriptCopy codeconst arrowFunction = <span class="hljs-function">(<span class="hljs-params">...args</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(args);
    };
    arrowFunction(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>); <span class="hljs-comment">// [1, 2, 3]</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[LocalStorage vs indexDB]]></title><description><![CDATA[Recently I’ve worked on projects that separately used localStorage & indexDB, so i am kinda curious what is the diff, after some search, here is my understanding.
Obviously, both localStorage and indexDB is client side storage solutions provided by m...]]></description><link>https://blog.zackhu.com/localstorage-vs-indexdb</link><guid isPermaLink="true">https://blog.zackhu.com/localstorage-vs-indexdb</guid><category><![CDATA[localstorage]]></category><category><![CDATA[indexdb]]></category><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Mon, 06 Jan 2025 03:07:28 GMT</pubDate><content:encoded><![CDATA[<p>Recently I’ve worked on projects that separately used localStorage &amp; indexDB, so i am kinda curious what is the diff, after some search, here is my understanding.</p>
<p>Obviously, both localStorage and indexDB is <strong>client side storage</strong> solutions provided by modern web browser.</p>
<p>But there’s lots of diff between them, could be analyzed from the following perspectives:</p>
<h3 id="heading-data-structure">Data structure:</h3>
<ul>
<li><p><strong>IndexedDB:</strong></p>
<ul>
<li><p>is a <strong>NoSQL DB</strong>, store in key-value pair format but allow <strong>structured data(obj, arr)</strong> with indexes</p>
</li>
<li><p>supports complex queries, transactions</p>
</li>
<li><p>suitable for storing large, <strong>structured data</strong> sets.</p>
</li>
</ul>
</li>
<li><p><strong>localStorage:</strong></p>
<ul>
<li><p>simple <strong>string-based</strong> <strong>key-value storage</strong></p>
</li>
<li><p>meant for simple storage and retrieval tasks</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-storage-limits">Storage limits:</h3>
<ul>
<li><p><strong>IndexedDB:</strong> larger storage limits: range from <strong>hundreds of MBs to GBs,</strong> ideal for data like images, videos, or entire datasets</p>
</li>
<li><p><strong>LocalStorage:</strong> limited to about <strong>5-10 MB per domain</strong></p>
</li>
</ul>
<h3 id="heading-performance">Performance:</h3>
<ul>
<li><p><strong>IndexedDB:</strong> asynchronous operation (<strong>none-blocking</strong>), high performance, handy for large DB</p>
</li>
<li><p><strong>LocalStorage:</strong> synchronous operation (<strong>blocking</strong>), slower with potential causing UI performance issues</p>
</li>
</ul>
<h3 id="heading-when-to-use">When to use:</h3>
<ul>
<li><p><strong>IndexedDB</strong>: Choose this for <strong>large-scale, structured, and performance-critical tasks</strong>.</p>
</li>
<li><p><strong>LocalStorage</strong>: Opt for this for <strong>small, quick, and simple tasks</strong> where blocking is acceptable.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[An Interesting React Bug]]></title><description><![CDATA[Sample Code:
Play around at https://codesandbox.io/p/devbox/an-intresting-react-error-d9gc2l, line 60.
Problem description:
When text area wrapped in a component, the text area would lose focus whenever user type in a character.
Some might ask what i...]]></description><link>https://blog.zackhu.com/an-interesting-react-bug</link><guid isPermaLink="true">https://blog.zackhu.com/an-interesting-react-bug</guid><category><![CDATA[React]]></category><dc:creator><![CDATA[Zack Hu]]></dc:creator><pubDate>Mon, 30 Dec 2024 02:41:58 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-sample-code">Sample Code:</h3>
<p>Play around at <a target="_blank" href="https://codesandbox.io/p/devbox/an-intresting-react-error-d9gc2l">https://codesandbox.io/p/devbox/an-intresting-react-error-d9gc2l</a>, line 60.</p>
<h3 id="heading-problem-description">Problem description:</h3>
<p>When text area wrapped in a component, the text area would <strong>lose focus</strong> whenever user type in a character.</p>
<p>Some might ask what is the purpose of this Wrapper: DefaultRender, since we might have different render logic and design, we would like it to be dynamically rendered based on our needs (this part is removed from the code snippet, since it is unrelated to the bug).</p>
<pre><code class="lang-javascript">
<span class="hljs-comment">// Here is a normal list rendering, the normal TextArea works perfectly fine, </span>
<span class="hljs-comment">// but once replaced with the DefaultItemRender would trigger the problem of losing focus.</span>
{editingItems.map(<span class="hljs-function">(<span class="hljs-params">item, index</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (!item) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
      {/* <span class="hljs-tag">&lt;<span class="hljs-name">TextArea</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{item.title</span> || ''}
      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(value)</span> =&gt;</span> handleInputChange(index, 'title', value)}
    /&gt; */}
      <span class="hljs-tag">&lt;<span class="hljs-name">DefaultItemRenderer</span>
        <span class="hljs-attr">item</span>=<span class="hljs-string">{item}</span>
        <span class="hljs-attr">index</span>=<span class="hljs-string">{index}</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
})}

<span class="hljs-comment">// Just a normal wrapper of TextArea, the reason for this wrapper is: initially </span>
<span class="hljs-keyword">const</span> DefaultItemRenderer = <span class="hljs-function">(<span class="hljs-params">{ item, index }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TextArea</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{item.title</span> || ''}
      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(value)</span> =&gt;</span> handleInputChange(index, 'title', value)}
    /&gt;</span>
  );
};


<span class="hljs-comment">// TextArea is just a custom component</span>
<span class="hljs-keyword">import</span> React, { useRef, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> TextArea = <span class="hljs-function">(<span class="hljs-params">{ value, onChange }</span>) =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"TextArea rendered"</span>);
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{value}</span>
      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> onChange(e.target.value)}
      rows={1}
    /&gt;</span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TextArea;
</code></pre>
<h3 id="heading-some-guess-around-it">Some guess around it:</h3>
<p>Still confused about the cause.</p>
]]></content:encoded></item></channel></rss>