<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Jelon</title>
  
  <subtitle>个人博客小站</subtitle>
  <link href="https://jelon.link/atom.xml" rel="self"/>
  
  <link href="https://jelon.link/"/>
  <updated>2025-11-11T00:00:00.000Z</updated>
  <id>https://jelon.link/</id>
  
  <author>
    <name>Jelon</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>React 核心原理与实现机制详解</title>
    <link href="https://jelon.link/posts/basic-of-react/index/"/>
    <id>https://jelon.link/posts/basic-of-react/index/</id>
    <published>2025-11-11T00:00:00.000Z</published>
    <updated>2025-11-11T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#1-%E8%99%9A%E6%8B%9Fdom-virtual-dom">1. <strong>虚拟DOM (Virtual DOM)</strong></a></li><li><a href="#2-diffing%E7%AE%97%E6%B3%95%E5%8D%8F%E8%B0%83%E7%AE%97%E6%B3%95">2. <strong>Diffing算法（协调算法）</strong></a><ul><li><a href="#%E6%AF%94%E8%BE%83%E7%AD%96%E7%95%A5">比较策略：</a></li><li><a href="#diff%E8%A7%84%E5%88%99">Diff规则：</a></li></ul></li><li><a href="#3-fiber%E6%9E%B6%E6%9E%84react-16">3. <strong>Fiber架构（React 16+）</strong></a><ul><li><a href="#fiber%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5">Fiber核心概念：</a></li></ul></li><li><a href="#4-%E6%B8%B2%E6%9F%93%E6%B5%81%E7%A8%8B">4. <strong>渲染流程</strong></a><ul><li><a href="#%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B8%B2%E6%9F%93">初始化渲染：</a></li><li><a href="#%E6%9B%B4%E6%96%B0%E8%BF%87%E7%A8%8B">更新过程：</a></li></ul></li><li><a href="#5-hooks%E5%8E%9F%E7%90%86">5. <strong>Hooks原理</strong></a><ul><li><a href="#hooks%E8%A7%84%E5%88%99">Hooks规则：</a></li></ul></li><li><a href="#6-%E4%BA%8B%E4%BB%B6%E7%B3%BB%E7%BB%9F">6. <strong>事件系统</strong></a></li><li><a href="#7-%E7%BB%84%E4%BB%B6%E6%9B%B4%E6%96%B0%E6%9C%BA%E5%88%B6">7. <strong>组件更新机制</strong></a><ul><li><a href="#%E7%B1%BB%E7%BB%84%E4%BB%B6">类组件：</a></li><li><a href="#%E5%87%BD%E6%95%B0%E7%BB%84%E4%BB%B6">函数组件：</a></li></ul></li><li><a href="#8-%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%8E%9F%E7%90%86">8. <strong>性能优化原理</strong></a><ul><li><a href="#reactmemo">React.memo：</a></li><li><a href="#usememousecallback">useMemo&#x2F;useCallback：</a></li></ul></li><li><a href="#9-%E6%96%B0%E7%9A%84%E5%B9%B6%E5%8F%91%E7%89%B9%E6%80%A7react-18">9. <strong>新的并发特性（React 18+）</strong></a><ul><li><a href="#concurrent-mode">Concurrent Mode：</a></li></ul></li><li><a href="#10-%E6%A0%B8%E5%BF%83%E4%BC%98%E5%8A%BF">10. <strong>核心优势</strong></a></li><li><a href="#11-%E6%B5%81%E7%A8%8B%E6%80%BB%E7%BB%93">11. 流程总结</a></li></ul><!-- tocstop --></div><p>React 的核心原理主要围绕以下几个方面：</p><h2><span id="1-虚拟dom-virtual-dom">1. <strong>虚拟DOM (Virtual DOM)</strong></span></h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 虚拟DOM是一个JavaScript对象</span></span><br><span class="line"><span class="keyword">const</span> virtualDOM = &#123;</span><br><span class="line">  <span class="attr">type</span>: <span class="string">&#x27;div&#x27;</span>,</span><br><span class="line">  <span class="attr">props</span>: &#123;</span><br><span class="line">    <span class="attr">className</span>: <span class="string">&#x27;container&#x27;</span>,</span><br><span class="line">    <span class="attr">children</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">type</span>: <span class="string">&#x27;h1&#x27;</span>,</span><br><span class="line">        <span class="attr">props</span>: &#123; <span class="attr">children</span>: <span class="string">&#x27;Hello&#x27;</span> &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>工作原理：</strong></p><ul><li>React 创建虚拟DOM树（轻量级的JS对象）</li><li>状态变化时，生成新的虚拟DOM树</li><li>通过Diff算法比较新旧树的差异</li><li>批量更新实际DOM（最小化操作）</li></ul><h2><span id="2-diffing算法协调算法">2. <strong>Diffing算法（协调算法）</strong></span></h2><p>React 使用 <strong>O(n)</strong> 复杂度的启发式算法：</p><h3><span id="比较策略">比较策略：</span></h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 不同类型元素 → 完全重建</span></span><br><span class="line"><span class="keyword">if</span> (old.<span class="property">type</span> !== <span class="keyword">new</span>.<span class="property">type</span>) &#123;</span><br><span class="line">  <span class="comment">// 卸载旧组件，挂载新组件</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 相同类型元素 → 更新属性</span></span><br><span class="line"><span class="keyword">if</span> (old.<span class="property">type</span> === <span class="keyword">new</span>.<span class="property">type</span>) &#123;</span><br><span class="line">  <span class="comment">// 只更新变化的属性</span></span><br><span class="line">  <span class="title function_">updateProperties</span>(oldNode, newNode);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 列表元素使用key优化</span></span><br><span class="line">&lt;ul&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">&quot;a&quot;</span>&gt;</span>A<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span></span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">&quot;b&quot;</span>&gt;</span>B<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span></span><br><span class="line">&lt;/ul&gt;</span><br></pre></td></tr></table></figure><h3><span id="diff规则">Diff规则：</span></h3><ol><li><strong>同级比较</strong>：只比较同一层的节点</li><li><strong>Key的重要性</strong>：帮助React识别元素的移动、添加、删除</li><li><strong>类型不同则重建</strong>：元素类型改变，整个子树重建</li></ol><h2><span id="3-fiber架构react-16">3. <strong>Fiber架构（React 16+）</strong></span></h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Fiber节点结构</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">FiberNode</span> = &#123;</span><br><span class="line">  <span class="attr">type</span>: <span class="title class_">FunctionComponent</span> | <span class="title class_">ClassComponent</span> | <span class="title class_">HostComponent</span>,</span><br><span class="line">  <span class="attr">stateNode</span>: <span class="title class_">Component</span>实例 | <span class="variable constant_">DOM</span>节点,</span><br><span class="line">  <span class="attr">return</span>: 父<span class="title class_">Fiber</span>,</span><br><span class="line">  <span class="attr">child</span>: 第一个子<span class="title class_">Fiber</span>,</span><br><span class="line">  <span class="attr">sibling</span>: 兄弟<span class="title class_">Fiber</span>,</span><br><span class="line">  <span class="attr">alternate</span>: 上次渲染的<span class="title class_">Fiber</span>,</span><br><span class="line">  <span class="attr">effectTag</span>: 需要执行的副作用（<span class="variable constant_">PLACEMENT</span>, <span class="variable constant_">UPDATE</span>, <span class="variable constant_">DELETION</span>等）</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3><span id="fiber核心概念">Fiber核心概念：</span></h3><ul><li><strong>增量渲染</strong>：将渲染工作拆分成多个小任务</li><li><strong>可中断</strong>：React可以暂停、恢复渲染</li><li><strong>优先级调度</strong>：为不同类型的更新分配优先级</li></ul><h2><span id="4-渲染流程">4. <strong>渲染流程</strong></span></h2><h3><span id="初始化渲染">初始化渲染：</span></h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> <span class="variable constant_">JSX</span> → <span class="title class_">React</span>.<span class="title function_">createElement</span>() → 虚拟<span class="variable constant_">DOM</span>对象</span><br><span class="line"><span class="number">2.</span> 创建<span class="title class_">Fiber</span>树（协调阶段）</span><br><span class="line"><span class="number">3.</span> 计算<span class="variable constant_">DOM</span>更新（提交阶段）</span><br><span class="line"><span class="number">4.</span> 实际<span class="variable constant_">DOM</span>操作</span><br></pre></td></tr></table></figure><h3><span id="更新过程">更新过程：</span></h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1. 触发更新</span></span><br><span class="line"><span class="title function_">setState</span>(newState);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2. 调度更新（Scheduler）</span></span><br><span class="line"><span class="title function_">requestIdleCallback</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 在空闲时间执行</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3. 协调阶段（可中断）</span></span><br><span class="line"><span class="title function_">workLoop</span>(<span class="params">deadline</span>) &#123;</span><br><span class="line">  <span class="keyword">while</span> (有工作 &amp;&amp; 有空闲时间) &#123;</span><br><span class="line">    <span class="title function_">performUnitOfWork</span>(currentFiber);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 4. 提交阶段（不可中断）</span></span><br><span class="line"><span class="title function_">commitRoot</span>();</span><br></pre></td></tr></table></figure><h2><span id="5-hooks原理">5. <strong>Hooks原理</strong></span></h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> hookIndex = <span class="number">0</span>;  <span class="comment">// 当前hook索引</span></span><br><span class="line"><span class="keyword">let</span> workInProgressHook = <span class="literal">null</span>;  <span class="comment">// 当前处理的hook</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">useState</span>(<span class="params">initialState</span>) &#123;</span><br><span class="line">  <span class="comment">// 获取当前hook</span></span><br><span class="line">  <span class="keyword">const</span> hook = &#123;</span><br><span class="line">    <span class="attr">memoizedState</span>: initialState,</span><br><span class="line">    <span class="attr">queue</span>: [],  <span class="comment">// 更新队列</span></span><br><span class="line">    <span class="attr">next</span>: <span class="literal">null</span>  <span class="comment">// 下一个hook</span></span><br><span class="line">  &#125;;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 返回[状态, 更新函数]</span></span><br><span class="line">  <span class="keyword">return</span> [hook.<span class="property">memoizedState</span>, dispatchAction];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">dispatchAction</span>(<span class="params">queue, action</span>) &#123;</span><br><span class="line">  <span class="comment">// 创建更新对象</span></span><br><span class="line">  <span class="keyword">const</span> update = &#123; action, <span class="attr">next</span>: <span class="literal">null</span> &#125;;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 将更新加入队列</span></span><br><span class="line">  <span class="comment">// 调度重新渲染</span></span><br><span class="line">  <span class="title function_">scheduleUpdate</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3><span id="hooks规则">Hooks规则：</span></h3><ul><li>只能在函数组件顶层调用</li><li>Hook调用顺序必须稳定（基于链表实现）</li><li>每个Hook有独立的内存单元</li></ul><h2><span id="6-事件系统">6. <strong>事件系统</strong></span></h2><p>React使用<strong>合成事件</strong>（SyntheticEvent）：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 事件委托</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>, dispatchEvent);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 合成事件池</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">SyntheticEvent</span>(<span class="params">nativeEvent</span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">nativeEvent</span> = nativeEvent;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">currentTarget</span> = <span class="literal">null</span>;</span><br><span class="line">  <span class="comment">// ... 其他属性</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 自动回收（React 17前）</span></span><br><span class="line">  <span class="variable language_">this</span>.<span class="title function_">persist</span>(); <span class="comment">// 阻止自动回收</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2><span id="7-组件更新机制">7. <strong>组件更新机制</strong></span></h2><h3><span id="类组件">类组件：</span></h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Component</span> &#123;</span><br><span class="line">  <span class="title function_">setState</span>(<span class="params">partialState, callback</span>) &#123;</span><br><span class="line">    <span class="comment">// 1. 将更新加入队列</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">updater</span>.<span class="title function_">enqueueSetState</span>(<span class="variable language_">this</span>, partialState, callback);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 2. 调度更新</span></span><br><span class="line">    <span class="title function_">scheduleUpdate</span>();</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 生命周期</span></span><br><span class="line">  <span class="title function_">shouldComponentUpdate</span>(<span class="params">nextProps, nextState</span>) &#123;</span><br><span class="line">    <span class="comment">// 决定是否更新</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3><span id="函数组件">函数组件：</span></h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">MyComponent</span>(<span class="params">props</span>) &#123;</span><br><span class="line">  <span class="comment">// 每次渲染都会调用整个函数</span></span><br><span class="line">  <span class="keyword">const</span> [state, setState] = <span class="title function_">useState</span>();</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// useEffect处理副作用</span></span><br><span class="line">  <span class="title function_">useEffect</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 副作用代码</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">// 清理函数</span></span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;, [dependencies]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2><span id="8-性能优化原理">8. <strong>性能优化原理</strong></span></h2><h3><span id="reactmemo">React.memo：</span></h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title class_">MemoComponent</span> = <span class="title class_">React</span>.<span class="title function_">memo</span>(</span><br><span class="line">  <span class="title class_">MyComponent</span>,</span><br><span class="line">  <span class="function">(<span class="params">prevProps, nextProps</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 自定义比较逻辑</span></span><br><span class="line">    <span class="keyword">return</span> prevProps.<span class="property">id</span> === nextProps.<span class="property">id</span>;</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h3><span id="usememox2fusecallback">useMemo&#x2F;useCallback：</span></h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> memoizedValue = <span class="title function_">useMemo</span>(</span><br><span class="line">  <span class="function">() =&gt;</span> <span class="title function_">computeExpensiveValue</span>(a, b),</span><br><span class="line">  [a, b]  <span class="comment">// 依赖数组</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> memoizedCallback = <span class="title function_">useCallback</span>(</span><br><span class="line">  <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="title function_">doSomething</span>(a, b);</span><br><span class="line">  &#125;,</span><br><span class="line">  [a, b]</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h2><span id="9-新的并发特性react-18">9. <strong>新的并发特性（React 18+）</strong></span></h2><h3><span id="concurrent-mode">Concurrent Mode：</span></h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 可中断的渲染</span></span><br><span class="line"><span class="keyword">const</span> root = <span class="title class_">ReactDOM</span>.<span class="title function_">createRoot</span>(container);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 过渡更新（低优先级）</span></span><br><span class="line"><span class="title function_">startTransition</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="title function_">setState</span>(newState);  <span class="comment">// 不紧急的更新</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 延迟值</span></span><br><span class="line"><span class="keyword">const</span> deferredValue = <span class="title function_">useDeferredValue</span>(value);</span><br></pre></td></tr></table></figure><h2><span id="10-核心优势">10. <strong>核心优势</strong></span></h2><ol><li><strong>声明式编程</strong>：描述UI应该是什么样子</li><li><strong>组件化</strong>：高内聚、低耦合</li><li><strong>一次学习，随处编写</strong>：React Native、React VR</li><li><strong>强大的生态系统</strong></li></ol><p>理解这些原理有助于：</p><ul><li>编写更高效的代码</li><li>更好的性能优化</li><li>避免常见错误</li><li>理解React生态系统中的其他库</li></ul><h2><span id="11-流程总结">11. 流程总结</span></h2><p><img src="https://jangdelong.github.io/blog_img/images/basic-of-react/1.svg" alt="react 渲染流程"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;div class=&quot;toc&quot;&gt;

&lt;!-- toc --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#1-%E8%99%9A%E6%8B%9Fdom-virtual-dom&quot;&gt;1. &lt;strong&gt;虚拟DOM (Virtual DOM)&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;l</summary>
      
    
    
    
    <category term="Web技术" scheme="https://jelon.link/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="js" scheme="https://jelon.link/tags/js/"/>
    
    <category term="React" scheme="https://jelon.link/tags/React/"/>
    
  </entry>
  
  <entry>
    <title>为什么使用 pnpm + workspace + changesets 替代 yarn + lerna 构建我们组件库</title>
    <link href="https://jelon.link/posts/pnpm-workspace-changesets/"/>
    <id>https://jelon.link/posts/pnpm-workspace-changesets/</id>
    <published>2025-03-15T00:22:48.000Z</published>
    <updated>2025-03-15T00:22:48.000Z</updated>
    
    <content type="html"><![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#%E4%B8%80-%E8%83%8C%E6%99%AF">一、背景</a></li><li><a href="#%E4%BA%8C-%E4%BB%80%E4%B9%88%E6%98%AF-pnpm">二、什么是 pnpm ？</a></li><li><a href="#%E4%B8%89-pnpm-%E5%AF%B9%E6%AF%94-npmyarn-%E6%9C%89%E4%BB%80%E4%B9%88%E4%BC%98%E5%8A%BF">三、pnpm 对比 npm&#x2F;yarn 有什么优势？</a></li><li><a href="#%E5%9B%9B-%E4%BB%80%E4%B9%88%E6%98%AF-changesets">四、什么是 changesets ？</a></li><li><a href="#%E4%BA%94-%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%BD%BF%E7%94%A8-changesets">五、为什么要使用 changesets ？</a></li><li><a href="#%E6%80%BB%E7%BB%93">总结</a></li></ul><!-- tocstop --></div><h2><span id="一-背景">一、背景</span></h2><p>最近公司私服开启鉴权，对于前端来说，带来一些非常重要的影响和变化：</p><ol><li>不管拉取 npm 包还是发布 npm 包，均需要鉴权，具体就是 .npmrc 配置信息需要增加 auth token 信息；</li><li>使用 yarn 出现偶然下载包失败问题以及必现的无法发包问题，而 npm 和 pnpm 可以；</li><li>现有组件库工程（所使用的工具链为 yarn + lerna）发包时会出现 401 鉴权问题，甚至有时连安装依赖包也有问题。</li></ol><p>基于以上三个问题，我们做了一些尝试：</p><ol><li>将 yarn 从 1.x 升级到 2.x，也就是说 yarn 2.x + lerna，不行；❌</li><li>将 yarn 改成 pnpm，使用 pnpm + lerna 组合，也出现了一些问题；❌</li><li>将 yarn + lerna 组合改成 pnpm + workspace + [pnpm publish]，成功。✅</li></ol><p>最后，我们决定彻底地将 yarn + lerna 组合切换成 pnpm + workspace + changesets 。</p><h2><span id="二-什么是-pnpm">二、什么是 pnpm ？</span></h2><p>pnpm 是新一代的包管理工具，是目前较为先进的包管理器。按照官网说法，可以实现节约磁盘空间并提升安装速度和创建非扁平化的 node_modules 文件夹两大目标，具体原理可以参考 pnpm 官网。</p><p>以下是官方给的一张关于 pnpm 的原理图：</p><p><img src="https://jangdelong.github.io/blog_img/images/pnpm-workspace-changesets/1.png" alt="pnpm 原理图"></p><p>所以，综合上图，我就现在知道 pnpm 为什么说是先进的包管理器了吧。</p><p>首先，最大的优点是节省磁盘空间，一个包全局只保存一份，剩下的都是软硬连接，这必然节省不少磁盘空间，并且使用软链接的方式创建非扁平的 node_modules 嵌套关系。</p><p>其次就是快，因为通过链接的方式而不是复制，自然会快。</p><h2><span id="三-pnpm-对比-npmx2fyarn-有什么优势">三、pnpm 对比 npm&#x2F;yarn 有什么优势？</span></h2><ol><li>速度快</li></ol><p>pnpm 安装包的速度究竟有多快？先以 React 包为例来对比一下:</p><p><img src="https://jangdelong.github.io/blog_img/images/pnpm-workspace-changesets/2.webp" alt="pnpm 原理图"></p><p>可以看到，作为黄色部分的 pnpm，在绝多大数场景下，包安装的速度都是明显优于 npm&#x2F;yarn，速度会比 npm&#x2F;yarn 快 2-3 倍。</p><p>对 yarn 比较熟悉的同学可能会说，yarn 不是有 PnP 安装模式吗？直接去掉 node_modules，将依赖包内容写在磁盘，节省了 node 文件 I&#x2F;O 的开销，这样也能提升安装速度。</p><p>接下来，我们以这样一个仓库为例，我们来看一看 benchmark 数据，主要对比一下 pnpm 和 yarn PnP:</p><p><img src="https://jangdelong.github.io/blog_img/images/pnpm-workspace-changesets/3.webp" alt="pnpm 原理图"></p><p>从中可以看到，总体而言，pnpm 的包安装速度还是明显优于 yarn PnP 的。</p><ol start="2"><li>高效利用磁盘空间</li></ol><p>pnpm 内部使用基于内容寻址的文件系统来存储磁盘上所有的文件，这个文件系统出色的地方在于:</p><ul><li>不会重复安装同一个包。用 npm&#x2F;yarn 的时候，如果 100 个项目都依赖 lodash，那么 lodash 很可能就被安装了 100 次，磁盘中就有 100 个地方写入了这部分代码。但在使用 pnpm 只会安装一次，磁盘中只有一个地方写入，后面再次使用都会直接使用 hardlink（硬链接）。</li><li>即使一个包的不同版本，pnpm 也会极大程度地复用之前版本的代码。举个例子，比如 lodash 有 100 个文件，更新版本之后多了一个文件，那么磁盘当中并不会重新写入 101 个文件，而是保留原来的 100 个文件的 hardlink，仅仅写入那一个新增的文件。</li></ul><ol start="3"><li>支持 monorepo</li></ol><p>随着前端工程的日益复杂，越来越多的项目开始使用 monorepo。之前对于多个项目的管理，我们一般都是使用多个 git 仓库，但 monorepo 的宗旨就是用一个 git 仓库来管理多个子项目，所有的子项目都存放在根目录的 packages 目录下，那么一个子项目就代表一个 package。</p><p>pnpm 与 npm&#x2F;yarn 另外一个很大的不同就是支持了 monorepo，体现在各个子命令的功能上，比如在根目录下 <code>pnpm add A -r</code>, 那么所有的 package 中都会被添加 A 这个依赖，当然也支持 <code>--filter</code> 字段来对 package 进行过滤。</p><p>pnpm 通过 pnpm-workspace.yaml 配置定义工作空间目录，并能够使您从工作空间中包含 &#x2F; 排除目录。</p><ol start="4"><li>安全性高</li></ol><p>之前在使用 npm&#x2F;yarn 的时候，由于 node_modules 的扁平结构，如果 A 依赖 B， B 依赖 C，那么 A 当中是可以直接使用 C 的，但问题是 A 当中并没有声明 C 这个依赖。因此会出现这种非法访问的情况。但 pnpm 脑洞特别大，自创了一套依赖管理方式，很好地解决了这个问题，保证了安全性，具体怎么体现安全、规避非法访问依赖的风险的，主要表现为幽灵依赖。</p><p>小结</p><p>总而言之，pnpm 与 npm&#x2F;yarn 比较，可以通过以下表格总结出来。</p><p><img src="https://jangdelong.github.io/blog_img/images/pnpm-workspace-changesets/4.png" alt="pnpm 原理图"></p><h2><span id="四-什么是-changesets">四、什么是 changesets ？</span></h2><p>在 workspace 中对包版本管理是一个非常复杂的工作，原来 yarn 还可以使用 lerna，遗憾的是 pnpm 没有提供内置的解决方案，一部分开源项目在自己的项目中自己实现了一套包版本的管理机制，比如 Vue3、Vite等。</p><p>pnpm 推荐了两个开源的版本控制工具：</p><ul><li>changesets</li><li>rush</li></ul><p>这里我们采用了 changesets 来做依赖包的管理。选用 changesets 的主要原因还是文档更加清晰一些，感觉上手比较容易。</p><p>按照 changesets 文档介绍的，changesets 主要是做了两件事：</p><blockquote><p>Changesets hold two key bits of information: a version type (following semver), and change information to be added to a changelog.</p></blockquote><p>简而言之就是管理包的 version 和生成 changelog。</p><h2><span id="五-为什么要使用-changesets">五、为什么要使用 changesets ？</span></h2><p>1. lerna 发包方案缺陷</p><p>早期我们的组件库版本中采用了 lerna 这一套的发包方案，但随着频繁的使用和深入的研究发现，这套方案随之带来了不少问题：</p><ul><li>ignoreChanges 不能做到文件的完全忽略，存在优先级问题；</li><li>lerna version 根据 commit 以及 tag 更新出来的包版本不符合预期；</li><li>生成的 CHANGELOG 文件信息不完整；</li><li>lifecycle scripts 经常命中一些用户自定义的 script（例如 publish 等）；</li><li>CI 中自动化发包场景需要很高的定制成本；</li><li>lerna 本身不支持 workspace 协议，导致基于 pnpm 开发的一些仓库无法使用。</li></ul><p>2. changesets 的基本工作流程及优势</p><p>Changesets 提供了简单、轻量的版本控制和发布方案，其工作流原理如下。</p><p><img src="https://jangdelong.github.io/blog_img/images/pnpm-workspace-changesets/5.webp" alt="pnpm 原理图"></p><p>整个流程可以理解为四部曲：</p><p>第一步，<code>changeset init</code>。通过执行执行该命令，可以在项目根目录下生成一个 <code>.changeset</code> 目录，里面会生成一个 changesets 的 config 文件，一般项目初始化时，执行一遍即可，后续不用再执行该操作。</p><p>第二步，<code>changeset add</code> 或者 <code>changeset</code>。<code>add</code> 在 changesets 中算得上比较关键的命令之一了，它会根据 monorepo下的项目来生成一个 changeset 文件，里面会包含前面提到的 changeset 文件信息(更新包名称、版本层级、CHANGELOG 信息。</p><p>第三步，<code>changeset version</code>。 这个命令这里可以当作 <code>Bump Version</code>（版本号升级或更新操作）来理解，这里本质上做的工作是消耗 changesets 文件并且修改对应包版本以及依赖该包的包版本，同时会根据之前 changeset 文件里面的信息来生成对应的 CHANGELOG 信息。</p><p>第四步，<code>changeset publish</code>。本质上就是对 <code>npm publish</code> 做了一次封装，同时会检查对应的 registry 上有没有对应包的版本，如果已经存在了，就不会再发包了，如果不存在会对对应的包版本执行一次 <code>npm publish</code>。</p><p>另外，changesets 支持 <code>pre 版本</code> 和 <code>非 pre 版本</code> 的操作切换，需要在第二步之前执行 <code>changeset pre enter</code>、<code>changeset pre exit</code> 等操作。</p><p>小结</p><p>总而言之，主要优点在于提供了很大的自主权在使用者手中，在复杂的业务场景下能够做出一些合适的调整，例如用户可以自行修改 changesets 文件、changelog 文件、甚至是 Bump Version 后不满意的版本。</p><p>相比较于 lerna 提供的比较理想化的方案而言，changeset 本身是一套泛用性很强的方案，而且比较适合当下 monorepo 工作流场景下的一些运作方式，虽然本身还存在着不少的缺点 。</p><h2><span id="总结">总结</span></h2><p>综上所述，为什么使用 pnpm + workspace + changesets 替代 yarn + lerna 构建我们组件库，可以总结为以下几个点。</p><ol><li>使用 pnpm 解决私服开启鉴权带来的一些非常重要的影响和变化；</li><li>充分利用 pnpm 不可替代的速度快、高效利用磁盘空间、天然支持 monorepo（支持 workspace 配置）、 安全性高（比如解决幽灵依赖问题、node_modules 嵌套过深问题）等优势；</li><li>changesets 带来更加简单、更加轻量的版本控制和发布方案，使得版本管理及发布流程更多的自主权掌握在使用者手中。</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;div class=&quot;toc&quot;&gt;

&lt;!-- toc --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#%E4%B8%80-%E8%83%8C%E6%99%AF&quot;&gt;一、背景&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E4%BA%8C-%E4%BB%80%E4%B9%88%E</summary>
      
    
    
    
    <category term="Web技术" scheme="https://jelon.link/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="pnpm" scheme="https://jelon.link/tags/pnpm/"/>
    
    <category term="monorepo" scheme="https://jelon.link/tags/monorepo/"/>
    
    <category term="changesets" scheme="https://jelon.link/tags/changesets/"/>
    
  </entry>
  
  <entry>
    <title>Node.js多线程</title>
    <link href="https://jelon.link/posts/node-multi-process/"/>
    <id>https://jelon.link/posts/node-multi-process/</id>
    <published>2023-04-15T00:22:48.000Z</published>
    <updated>2023-04-15T00:22:48.000Z</updated>
    
    <content type="html"><![CDATA[<div class="toc"><!-- toc --><!-- tocstop --></div><p>在 Node.js 中，可以使用多种方式实现多线程编程，其中最常用的方式包括：</p><ol><li>使用 Worker Threads 模块：这是 Node.js 内置的一个模块，它提供了创建和管理多线程的 API。通过该模块，可以在 Node.js 中启动多个线程来执行不同的任务，以提高应用程序的性能和响应速度。该模块使用了共享内存和线程间消息传递来实现多线程编程。</li><li>使用 Child Processes 模块：该模块也是 Node.js 内置的一个模块，它允许创建子进程来执行一些独立的任务。这些子进程可以通过 IPC（进程间通信）与主进程进行通信，从而实现多线程编程。</li><li>使用 Cluster 模块：该模块允许将 Node.js 应用程序分为多个进程，每个进程都可以处理来自客户端的请求。通过将请求分配给不同的进程，可以有效地利用多核 CPU，从而提高应用程序的性能。</li></ol><p>需要注意的是，虽然 Node.js 可以使用多线程来提高应用程序的性能，但多线程编程也可能会带来一些问题，如竞争条件和死锁等。因此，在使用多线程编程时，需要仔细考虑和处理这些问题，以确保应用程序的正确性和稳定性。</p><p>详细展开说如下。</p><ol><li>使用 Worker Threads 模块</li></ol><p>Worker Threads 是 Node.js 内置的一个模块，它提供了一种在 Node.js 中创建和管理多线程的方式。通过该模块，可以在 Node.js 中启动多个线程来执行不同的任务，以提高应用程序的性能和响应速度。</p><p>Worker Threads 模块使用了共享内存和线程间消息传递来实现多线程编程。具体来说，可以通过 Worker 类来创建和管理多个线程，每个线程都可以独立地执行一个任务。在任务执行过程中，可以使用 postMessage() 方法向其他线程发送消息，也可以使用 on() 方法监听其他线程发送的消息。</p><p>需要注意的是，由于多个线程共享同一个内存空间，因此需要特别小心，避免出现竞争条件和内存泄漏等问题。</p><p>以下是使用 Worker Threads 模块示例：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> &#123; <span class="title class_">Worker</span> &#125; = <span class="built_in">require</span>(<span class="string">&#x27;worker_threads&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">runService</span>(<span class="params">workerData</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> worker = <span class="keyword">new</span> <span class="title class_">Worker</span>(<span class="string">&#x27;./worker.js&#x27;</span>, &#123; workerData &#125;);</span><br><span class="line">    worker.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, resolve);</span><br><span class="line">    worker.<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, reject);</span><br><span class="line">    worker.<span class="title function_">on</span>(<span class="string">&#x27;exit&#x27;</span>, <span class="function">(<span class="params">code</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (code !== <span class="number">0</span>)</span><br><span class="line">        <span class="title function_">reject</span>(<span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`Worker stopped with exit code <span class="subst">$&#123;code&#125;</span>`</span>));</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">run</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> result = <span class="keyword">await</span> <span class="title function_">runService</span>(<span class="string">&#x27;hello&#x27;</span>);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title function_">run</span>();</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在上面的示例中，我们使用 Worker Threads 模块创建了一个新的 Worker 对象，并指定了需要执行的 worker.js 文件和传递给它的 workerData 参数。在 worker.js 文件中，我们可以使用 parentPort.postMessage() 方法向主线程发送消息，也可以使用 workerData 属性获取从主线程传递过来的参数。</p><ol start="2"><li>使用 Child Processes 模块</li></ol><p>Child Processes 模块也是 Node.js 内置的一个模块，它允许创建子进程来执行一些独立的任务。这些子进程可以通过 IPC（进程间通信）与主进程进行通信，从而实现多线程编程。</p><p>使用 Child Processes 模块时，可以通过 spawn() 方法创建一个子进程，并指定该子进程执行的命令和参数。子进程创建后，可以使用 stdin、stdout 和 stderr 等标准 I&#x2F;O 流与其进行通信。此外，还可以使用 IPC 机制来实现主进程和子进程之间的通信。</p><p>需要注意的是，子进程与主进程之间的通信会涉及到进程间的上下文切换，因此在大规模并发的情况下，可能会导致性能问题。</p><p>以下是使用 Child Processes 模块示例：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> &#123; spawn &#125; = <span class="built_in">require</span>(<span class="string">&#x27;child_process&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> child = <span class="title function_">spawn</span>(<span class="string">&#x27;ls&#x27;</span>, [<span class="string">&#x27;-lh&#x27;</span>, <span class="string">&#x27;/usr&#x27;</span>]);</span><br><span class="line"></span><br><span class="line">child.<span class="property">stdout</span>.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function">(<span class="params">data</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`stdout: <span class="subst">$&#123;data&#125;</span>`</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">child.<span class="property">stderr</span>.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function">(<span class="params">data</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">`stderr: <span class="subst">$&#123;data&#125;</span>`</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">child.<span class="title function_">on</span>(<span class="string">&#x27;close&#x27;</span>, <span class="function">(<span class="params">code</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`child process exited with code <span class="subst">$&#123;code&#125;</span>`</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在上面的示例中，我们使用 Child Processes 模块创建了一个新的子进程，并指定需要执行的 ls 命令和参数。在子进程中，我们可以使用 process.stdout 和 process.stderr 对象输出日志信息，也可以使用 process.send() 方法向主进程发送消息。</p><ol start="3"><li>使用 Cluster 模块</li></ol><p>Cluster 模块允许将 Node.js 应用程序分为多个进程，每个进程都可以处理来自客户端的请求。通过将请求分配给不同的进程，可以有效地利用多核 CPU，从而提高应用程序的性能。</p><p>在使用 Cluster 模块时，可以通过调用 cluster.fork() 方法来创建一个新的工作进程，并将其注册到主进程的事件循环中。主进程和工作进程之间可以使用 IPC 机制进行通信，并共享一些数据和资源。此外，工作进程也可以独立地处理客户端的请求，从而提高应用程序的性能和可扩展性。</p><p>需要注意的是，Cluster 模块虽然可以提高应用程序的性能，但也会带来一些复杂性和挑战。例如，需要考虑进程间通信的问题、负载均衡的问题以及进程的崩溃等问题。</p><p>以下是使用 Cluster 模块示例：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> cluster = <span class="built_in">require</span>(<span class="string">&#x27;cluster&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> numCPUs = <span class="built_in">require</span>(<span class="string">&#x27;os&#x27;</span>).<span class="title function_">cpus</span>().<span class="property">length</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (cluster.<span class="property">isMaster</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Master <span class="subst">$&#123;process.pid&#125;</span> is running`</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; numCPUs; i++) &#123;</span><br><span class="line">    cluster.<span class="title function_">fork</span>();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  cluster.<span class="title function_">on</span>(<span class="string">&#x27;exit&#x27;</span>, <span class="function">(<span class="params">worker, code, signal</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`worker <span class="subst">$&#123;worker.process.pid&#125;</span> died`</span>);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Worker <span class="subst">$&#123;process.pid&#125;</span> started`</span>);</span><br><span class="line"></span><br><span class="line">  http.<span class="title function_">createServer</span>(<span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    res.<span class="title function_">writeHead</span>(<span class="number">200</span>);</span><br><span class="line">    res.<span class="title function_">end</span>(<span class="string">&#x27;Hello World\n&#x27;</span>);</span><br><span class="line">  &#125;).<span class="title function_">listen</span>(<span class="number">8000</span>);</span><br><span class="line"></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Worker <span class="subst">$&#123;process.pid&#125;</span> listening on port 8000`</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在上面的示例中，我们使用 Cluster 模块创建了多个工作进程，并使用 HTTP 模块创建了一个 Web 服务器。每个工作进程都可以独立地处理客户端的请求，并使用 console.log() 方法输出日志信息。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;div class=&quot;toc&quot;&gt;

&lt;!-- toc --&gt;



&lt;!-- tocstop --&gt;

&lt;/div&gt;

&lt;p&gt;在 Node.js 中，可以使用多种方式实现多线程编程，其中最常用的方式包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 Worker Threads 模块：这是</summary>
      
    
    
    
    <category term="Web技术" scheme="https://jelon.link/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Node.js" scheme="https://jelon.link/tags/Node-js/"/>
    
  </entry>
  
  <entry>
    <title>给项目 npm 依赖包升级</title>
    <link href="https://jelon.link/posts/npm-check-updates/"/>
    <id>https://jelon.link/posts/npm-check-updates/</id>
    <published>2021-01-12T19:55:33.000Z</published>
    <updated>2021-01-12T19:55:33.000Z</updated>
    
    <content type="html"><![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#%E6%96%B9%E6%B3%95%E4%B8%80">方法一</a></li><li><a href="#%E6%96%B9%E6%B3%95%E4%BA%8C">方法二</a></li></ul><!-- tocstop --></div><p>升级之前要先检查更新</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm outdated</span><br></pre></td></tr></table></figure><p>执行以上命令，可以看到所有可以更新的模块。<br>我们需要先更新 package.json 文件。</p><h3><span id="方法一">方法一</span></h3><p>我们需要安装 <code>npm-check-updates</code> 模块</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g npm-check-updates</span><br></pre></td></tr></table></figure><p>检查可更新的模块</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ncu</span><br></pre></td></tr></table></figure><p>或者</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm-check-updates</span><br></pre></td></tr></table></figure><p>以上两条命令都可以检查可更新模块。接下来更新 package.json 的依赖包到最新版本：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ncu -u</span><br></pre></td></tr></table></figure><p>以上命令执行时更新全部模块。</p><h3><span id="方法二">方法二</span></h3><p>实际场景不建议一次性全部更新，有一定的风险，可以根据实际需要，更新指定的模块，并且可以根据作用范围在后面加上 -D、-S 或者 -g。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm update xxxx <span class="comment"># -D 、-S 或者 -g</span></span><br></pre></td></tr></table></figure><p>如果，是需要指定更新到某个版本可提前修改 package.json 中的版本号。</p><p>保险起见，更新完之后，可先删除 node_modules 目录，然后重新安装 npm 包。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;div class=&quot;toc&quot;&gt;

&lt;!-- toc --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#%E6%96%B9%E6%B3%95%E4%B8%80&quot;&gt;方法一&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E6%96%B9%E6%B3%95%E4%BA%8C&quot;&gt;方法二</summary>
      
    
    
    
    <category term="Web技术" scheme="https://jelon.link/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="npm" scheme="https://jelon.link/tags/npm/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】93. 复原IP地址</title>
    <link href="https://jelon.link/posts/leetcode-93/"/>
    <id>https://jelon.link/posts/leetcode-93/</id>
    <published>2020-08-13T00:00:00.000Z</published>
    <updated>2020-08-13T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>给定一个只包含数字的字符串，复原它并返回所有可能的 IP 地址格式。</p><p>有效的 IP 地址正好由四个整数（每个整数位于 0 到 255 之间组成），整数之间用 ‘.’ 分隔。</p><p><strong>示例:</strong></p><figure class="highlight prolog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: <span class="string">&quot;25525511135&quot;</span></span><br><span class="line">输出: [<span class="string">&quot;255.255.11.135&quot;</span>, <span class="string">&quot;255.255.111.35&quot;</span>]</span><br></pre></td></tr></table></figure><h5><span id="参考解答">参考解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">string</span>&#125; <span class="variable">s</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">string[]</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> restoreIpAddresses = <span class="keyword">function</span>(<span class="params">s</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> res = []</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * cur 当前</span></span><br><span class="line"><span class="comment">   * sub 剩余字符串</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">search</span> = (<span class="params">cur, sub</span>) =&gt; &#123;</span><br><span class="line">    <span class="comment">// 超出范围</span></span><br><span class="line">    <span class="keyword">if</span> (sub.<span class="property">length</span> &gt; <span class="number">12</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> res</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (cur.<span class="property">length</span> === <span class="number">4</span> &amp;&amp; cur.<span class="title function_">join</span>(<span class="string">&#x27;&#x27;</span>) === s) &#123;</span><br><span class="line">      res.<span class="title function_">push</span>(cur.<span class="title function_">join</span>(<span class="string">&#x27;.&#x27;</span>))</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="comment">// ip位最长只有三位</span></span><br><span class="line">      <span class="keyword">const</span> len = <span class="title class_">Math</span>.<span class="title function_">min</span>(<span class="number">3</span>, sub.<span class="property">length</span>)</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">        <span class="keyword">const</span> tmp = sub.<span class="title function_">substr</span>(<span class="number">0</span>, i + <span class="number">1</span>)</span><br><span class="line">        <span class="keyword">if</span> (tmp &lt; <span class="number">256</span> &amp;&amp; <span class="title class_">Number</span>(tmp).<span class="title function_">toString</span>() === tmp) &#123;</span><br><span class="line">          <span class="title function_">search</span>([ ...cur, tmp ], sub.<span class="title function_">substr</span>(i + <span class="number">1</span>))</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="title function_">search</span>([], s)</span><br><span class="line">  <span class="keyword">return</span> res</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5><span id="解决思路">解决思路</span></h5><blockquote><p>递归</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;给定一个只包含数字的字符串，复原它并返回所有可能的 IP 地址格式。&lt;/p&gt;
&lt;p&gt;有效的 IP 地址正好由四个整数（每个整数位于 0 到 255 之间组成），整数之间用 ‘.’ 分隔。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例:&lt;/strong&gt;&lt;/p&gt;
&lt;figure cla</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】209. 长度最小的子数组</title>
    <link href="https://jelon.link/posts/leetcode-209/"/>
    <id>https://jelon.link/posts/leetcode-209/</id>
    <published>2020-08-10T00:00:00.000Z</published>
    <updated>2020-08-10T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>给定一个含有 n 个正整数的数组和一个正整数 s ，找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组，并返回其长度。如果不存在符合条件的子数组，返回 0。</p><p> </p><p><strong>示例：</strong></p><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入：s = 7, nums = <span class="comment">[2,3,1,2,4,3]</span></span><br><span class="line">输出：2</span><br><span class="line">解释：子数组 <span class="comment">[4,3]</span> 是该条件下的长度最小的子数组。</span><br></pre></td></tr></table></figure><p> </p><p><strong>进阶：</strong></p><ul><li>如果你已经完成了 O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。</li></ul><h5><span id="参考解答">参考解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">number</span>&#125; <span class="variable">s</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">number[]</span>&#125; <span class="variable">nums</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">number</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> minSubArrayLen = <span class="keyword">function</span>(<span class="params">s, nums</span>) &#123;</span><br><span class="line">  <span class="comment">// 双指针</span></span><br><span class="line">  <span class="keyword">let</span> minLen = nums.<span class="property">length</span> + <span class="number">1</span></span><br><span class="line">  <span class="keyword">let</span> i = <span class="number">0</span></span><br><span class="line">  <span class="keyword">let</span> j = <span class="number">0</span></span><br><span class="line">  <span class="keyword">let</span> sum = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (j &lt; nums.<span class="property">length</span>) &#123; <span class="comment">// 放大</span></span><br><span class="line">    sum += nums[j]</span><br><span class="line">    <span class="keyword">while</span> (sum &gt;= s) &#123; <span class="comment">// 缩小</span></span><br><span class="line">      sum -= nums[i]</span><br><span class="line">      minLen = <span class="title class_">Math</span>.<span class="title function_">min</span>(minLen, j - i + <span class="number">1</span>)</span><br><span class="line">      i++</span><br><span class="line">    &#125;</span><br><span class="line">    j++</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> minLen === nums.<span class="property">length</span> + <span class="number">1</span> ? <span class="number">0</span> : minLen</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5><span id="参考思路">参考思路</span></h5><ul><li>扩张窗口：为了找到一个可行解，找到了就不再扩张</li><li>收缩窗口：在长度上优化该可行解，直到条件被破坏</li><li>寻找下一个可行解，然后再优化。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;给定一个含有 n 个正整数的数组和一个正整数 s ，找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组，并返回其长度。如果不存在符合条件的子数组，返回 0。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例：&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】56. 合并区间</title>
    <link href="https://jelon.link/posts/leetcode-56/"/>
    <id>https://jelon.link/posts/leetcode-56/</id>
    <published>2020-08-09T00:00:00.000Z</published>
    <updated>2020-08-09T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>给出一个区间的集合，请合并所有重叠的区间。</p><p><strong>示例 1:</strong></p><figure class="highlight prolog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: [[<span class="number">1</span>,<span class="number">3</span>],[<span class="number">2</span>,<span class="number">6</span>],[<span class="number">8</span>,<span class="number">10</span>],[<span class="number">15</span>,<span class="number">18</span>]]</span><br><span class="line">输出: [[<span class="number">1</span>,<span class="number">6</span>],[<span class="number">8</span>,<span class="number">10</span>],[<span class="number">15</span>,<span class="number">18</span>]]</span><br><span class="line">解释: 区间 [<span class="number">1</span>,<span class="number">3</span>] 和 [<span class="number">2</span>,<span class="number">6</span>] 重叠, 将它们合并为 [<span class="number">1</span>,<span class="number">6</span>].</span><br></pre></td></tr></table></figure><p><strong>示例 2:</strong></p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: <span class="string">[[1,4],[4,5]]</span></span><br><span class="line">输出: <span class="string">[[1,5]]</span></span><br><span class="line">解释: 区间 [<span class="number">1</span>,<span class="number">4</span>] 和 [<span class="number">4</span>,<span class="number">5</span>] 可被视为重叠区间。</span><br></pre></td></tr></table></figure><h5><span id="个人解答">个人解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">number[][]</span>&#125; <span class="variable">intervals</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">number[][]</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> merge = <span class="keyword">function</span>(<span class="params">intervals</span>) &#123;</span><br><span class="line">  <span class="comment">// 先根据左顶点进行升序排序</span></span><br><span class="line">  intervals = intervals.<span class="title function_">sort</span>(<span class="function">(<span class="params">a, b</span>) =&gt;</span> a[<span class="number">0</span>] - b[<span class="number">0</span>])</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; intervals.<span class="property">length</span> - <span class="number">1</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">const</span> a2 = intervals[i][<span class="number">1</span>] <span class="comment">// 当前元素的右顶点</span></span><br><span class="line">    <span class="keyword">const</span> b1 = intervals[i+<span class="number">1</span>][<span class="number">0</span>] <span class="comment">// 下个元素的左顶点</span></span><br><span class="line">    <span class="keyword">const</span> b2 = intervals[i+<span class="number">1</span>][<span class="number">1</span>] <span class="comment">// 下个元素的右顶点</span></span><br><span class="line">    <span class="keyword">if</span> (a2 &gt;= b1) &#123; <span class="comment">// 当前元素的右顶点与下个元素左顶点比较</span></span><br><span class="line">      intervals[i][<span class="number">1</span>] = <span class="title class_">Math</span>.<span class="title function_">max</span>(a2, b2)</span><br><span class="line">      intervals.<span class="title function_">splice</span>(i + <span class="number">1</span>, <span class="number">1</span>) <span class="comment">// 删掉下标 i + 1</span></span><br><span class="line">      i--</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> intervals</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5><span id="解题思路">解题思路</span></h5><ol><li>先按左顶点进行升序排序；</li><li>循环判断 intervals[i][1] &gt;&#x3D; intervals[i+1][0]，即当前元素右顶点与下个元素左顶点比较；</li><li>当前元素右顶点取值，符合条件删除下一个元素 intervals[i+1]。</li></ol><blockquote><p>注：</p><p>边界i&lt;intervals.length-1</p><p>因为删除元素，数组变短了。此时： i–</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;给出一个区间的集合，请合并所有重叠的区间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight prolog&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】102. 二叉树的层序遍历</title>
    <link href="https://jelon.link/posts/leetcode-102/"/>
    <id>https://jelon.link/posts/leetcode-102/</id>
    <published>2020-07-24T00:00:00.000Z</published>
    <updated>2020-07-24T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>给你一个二叉树，请你返回其按 层序遍历 得到的节点值。 （即逐层地，从左到右访问所有节点）。</p><p><strong>示例：</strong><br>二叉树：[3,9,20,null,null,15,7],</p><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">  <span class="number">3</span></span><br><span class="line"> / <span class="string">\</span></span><br><span class="line"><span class="number">9</span>  <span class="number">20</span></span><br><span class="line">  /  <span class="string">\</span></span><br><span class="line"> <span class="number">15</span>   <span class="number">7</span></span><br></pre></td></tr></table></figure><p>返回其层次遍历结果：</p><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">[</span></span><br><span class="line"><span class="comment">  <span class="comment">[3]</span>,</span></span><br><span class="line"><span class="comment">  <span class="comment">[9,20]</span>,</span></span><br><span class="line"><span class="comment">  <span class="comment">[15,7]</span></span></span><br><span class="line"><span class="comment">]</span></span><br></pre></td></tr></table></figure><h5><span id="个人解答">个人解答</span></h5><p>广度遍历</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * function TreeNode(val) &#123;</span></span><br><span class="line"><span class="comment"> *     this.val = val;</span></span><br><span class="line"><span class="comment"> *     this.left = this.right = null;</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">TreeNode</span>&#125; <span class="variable">root</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">number[][]</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> levelOrder = <span class="keyword">function</span>(<span class="params">root</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (!root) <span class="keyword">return</span> []</span><br><span class="line">  <span class="keyword">var</span> res = []</span><br><span class="line">  <span class="keyword">var</span> queue = [ root ]</span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (queue.<span class="property">length</span>) &#123; <span class="comment">// 纵向遍历</span></span><br><span class="line">    <span class="keyword">var</span> curr = [] <span class="comment">// 当前行</span></span><br><span class="line">    <span class="keyword">var</span> next = [] <span class="comment">// 下一行</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (queue.<span class="property">length</span>) &#123; <span class="comment">// 横向遍历</span></span><br><span class="line">      <span class="keyword">var</span> node = queue.<span class="title function_">shift</span>()</span><br><span class="line">      curr.<span class="title function_">push</span>(node.<span class="property">val</span>)</span><br><span class="line">      <span class="keyword">if</span> (node.<span class="property">left</span>) &#123;</span><br><span class="line">        next.<span class="title function_">push</span>(node.<span class="property">left</span>)</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (node.<span class="property">right</span>) &#123;</span><br><span class="line">        next.<span class="title function_">push</span>(node.<span class="property">right</span>)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    res.<span class="title function_">push</span>(curr)</span><br><span class="line">    queue = next</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> res</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>深度遍历</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * function TreeNode(val) &#123;</span></span><br><span class="line"><span class="comment"> *     this.val = val;</span></span><br><span class="line"><span class="comment"> *     this.left = this.right = null;</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">TreeNode</span>&#125; <span class="variable">root</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">number[][]</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> levelOrder = <span class="keyword">function</span>(<span class="params">root</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> res = []</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> levelTransal = <span class="keyword">function</span> (<span class="params">node, order</span>) &#123;</span><br><span class="line">    res[order] = res[order] || []</span><br><span class="line">    res[order].<span class="title function_">push</span>(node.<span class="property">val</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (node.<span class="property">left</span>) &#123;</span><br><span class="line">      <span class="title function_">levelTransal</span>(node.<span class="property">left</span>, order + <span class="number">1</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (node.<span class="property">right</span>) &#123;</span><br><span class="line">      <span class="title function_">levelTransal</span>(node.<span class="property">right</span>, order + <span class="number">1</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (!root) <span class="keyword">return</span> [] </span><br><span class="line">  <span class="title function_">levelTransal</span>(root, <span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> res</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5><span id="解题思路">解题思路</span></h5><ol><li>广度遍历（双重循环）；</li><li>深度遍历（递归）。</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;给你一个二叉树，请你返回其按 层序遍历 得到的节点值。 （即逐层地，从左到右访问所有节点）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例：&lt;/strong&gt;&lt;br&gt;二叉树：[3,9,20,null,null,15,7],&lt;/p&gt;
&lt;figure class=&quot;highlight l</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】61. 旋转链表</title>
    <link href="https://jelon.link/posts/leetcode-61/"/>
    <id>https://jelon.link/posts/leetcode-61/</id>
    <published>2020-07-23T00:00:00.000Z</published>
    <updated>2020-07-23T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>给定一个链表，旋转链表，将链表每个节点向右移动 k 个位置，其中 k 是非负数。</p><p><strong>示例 1:</strong></p><figure class="highlight clean"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">输入: <span class="number">1</span>-&gt;<span class="number">2</span>-&gt;<span class="number">3</span>-&gt;<span class="number">4</span>-&gt;<span class="number">5</span>-&gt;NULL, k = <span class="number">2</span></span><br><span class="line">输出: <span class="number">4</span>-&gt;<span class="number">5</span>-&gt;<span class="number">1</span>-&gt;<span class="number">2</span>-&gt;<span class="number">3</span>-&gt;NULL</span><br><span class="line">解释:</span><br><span class="line">向右旋转 <span class="number">1</span> 步: <span class="number">5</span>-&gt;<span class="number">1</span>-&gt;<span class="number">2</span>-&gt;<span class="number">3</span>-&gt;<span class="number">4</span>-&gt;NULL</span><br><span class="line">向右旋转 <span class="number">2</span> 步: <span class="number">4</span>-&gt;<span class="number">5</span>-&gt;<span class="number">1</span>-&gt;<span class="number">2</span>-&gt;<span class="number">3</span>-&gt;NULL</span><br></pre></td></tr></table></figure><p><strong>示例 2:</strong></p><figure class="highlight clean"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">输入: <span class="number">0</span>-&gt;<span class="number">1</span>-&gt;<span class="number">2</span>-&gt;NULL, k = <span class="number">4</span></span><br><span class="line">输出: <span class="number">2</span>-&gt;<span class="number">0</span>-&gt;<span class="number">1</span>-&gt;NULL</span><br><span class="line">解释:</span><br><span class="line">向右旋转 <span class="number">1</span> 步: <span class="number">2</span>-&gt;<span class="number">0</span>-&gt;<span class="number">1</span>-&gt;NULL</span><br><span class="line">向右旋转 <span class="number">2</span> 步: <span class="number">1</span>-&gt;<span class="number">2</span>-&gt;<span class="number">0</span>-&gt;NULL</span><br><span class="line">向右旋转 <span class="number">3</span> 步: <span class="number">0</span>-&gt;<span class="number">1</span>-&gt;<span class="number">2</span>-&gt;NULL</span><br><span class="line">向右旋转 <span class="number">4</span> 步: <span class="number">2</span>-&gt;<span class="number">0</span>-&gt;<span class="number">1</span>-&gt;NULL</span><br></pre></td></tr></table></figure><h5><span id="个人解答">个人解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) &#123;</span></span><br><span class="line"><span class="comment"> *     this.val = val;</span></span><br><span class="line"><span class="comment"> *     this.next = null;</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">ListNode</span>&#125; <span class="variable">head</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">number</span>&#125; <span class="variable">k</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">ListNode</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> rotateRight = <span class="keyword">function</span>(<span class="params">head, k</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (!head || !head.<span class="property">next</span>) <span class="keyword">return</span> head</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 先闭合环</span></span><br><span class="line">  <span class="keyword">var</span> old_tail = head</span><br><span class="line">  <span class="keyword">var</span> n = <span class="number">1</span></span><br><span class="line">  <span class="keyword">while</span> (old_tail.<span class="property">next</span>) &#123;</span><br><span class="line">    old_tail = old_tail.<span class="property">next</span></span><br><span class="line">    n++</span><br><span class="line">  &#125;</span><br><span class="line">  old_tail.<span class="property">next</span> = head</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 断开</span></span><br><span class="line">  <span class="keyword">var</span> new_tail = head</span><br><span class="line">  <span class="keyword">var</span> new_head = head</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; n - k % n - <span class="number">1</span>; i++) &#123;</span><br><span class="line">    new_tail = new_tail.<span class="property">next</span></span><br><span class="line">  &#125;</span><br><span class="line">  new_head = new_tail.<span class="property">next</span> <span class="comment">// 重新计算新的头结点</span></span><br><span class="line">  new_tail.<span class="property">next</span> = <span class="literal">null</span> <span class="comment">// 断开</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> new_head</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5><span id="解题思路">解题思路</span></h5><ol><li>先将链表进行闭环</li><li>从 n - k % n （因为考虑到k &gt; n情况）处断开。</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;给定一个链表，旋转链表，将链表每个节点向右移动 k 个位置，其中 k 是非负数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight clean&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】11. 盛最多水的容器</title>
    <link href="https://jelon.link/posts/leetcode-11/"/>
    <id>https://jelon.link/posts/leetcode-11/</id>
    <published>2020-07-21T00:00:00.000Z</published>
    <updated>2020-07-21T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>给你 n 个非负整数 a1，a2，…，an，每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线，垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线，使得它们与 x 轴共同构成的容器可以容纳最多的水。</p><p>**说明：**你不能倾斜容器，且 n 的值至少为 2。</p><p><img src="https://jangdelong.github.io/blog_img/images/leetcode-11/question_11.jpg" alt="https:&#x2F;&#x2F;jangdelong.github.io&#x2F;blog_img&#x2F;images&#x2F;leetcode-11&#x2F;question_11.png"></p><p><sup>图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下，容器能够容纳水（表示为蓝色部分）的最大值为 49。</sup></p><p><strong>示例：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入：[<span class="number">1</span>,<span class="number">8</span>,<span class="number">6</span>,<span class="number">2</span>,<span class="number">5</span>,<span class="number">4</span>,<span class="number">8</span>,<span class="number">3</span>,<span class="number">7</span>]</span><br><span class="line">输出：<span class="number">49</span></span><br></pre></td></tr></table></figure><h5><span id="个人解答">个人解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">number[]</span>&#125; <span class="variable">height</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">number</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> maxArea = <span class="keyword">function</span>(<span class="params">height</span>) &#123;</span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * 双指针</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="keyword">var</span> res = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">var</span> i = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">var</span> j = height.<span class="property">length</span> - <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">var</span> cur = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">while</span> (i &lt; j) &#123;</span><br><span class="line">    <span class="keyword">var</span> h = <span class="title class_">Math</span>.<span class="title function_">min</span>(height[i], height[j]);</span><br><span class="line">    cur = (j - i) * h;</span><br><span class="line">    res = <span class="title class_">Math</span>.<span class="title function_">max</span>(res, cur);</span><br><span class="line">    <span class="keyword">if</span> (height[i] &lt; height[j]) &#123;</span><br><span class="line">      i++;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      j--;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> res;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5><span id="解题思路">解题思路</span></h5><p>双指针。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;给你 n 个非负整数 a1，a2，…，an，每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线，垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线，使得它们与 x 轴共同构成的容器可以容纳最多的水。&lt;/p&gt;
&lt;p&gt;**说明：*</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>前端散记 3</title>
    <link href="https://jelon.link/posts/front-end-notes-3/"/>
    <id>https://jelon.link/posts/front-end-notes-3/</id>
    <published>2020-06-17T00:00:00.000Z</published>
    <updated>2020-06-17T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#async-await-%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86">async await 实现原理</a></li><li><a href="#async-await-%E6%B3%A8%E6%84%8F%E7%82%B9">async await 注意点</a></li><li><a href="#es5-%E5%AE%9E%E7%8E%B0%E7%BB%A7%E6%89%BF">ES5 实现继承</a></li><li><a href="#%E8%99%9A%E6%8B%9Fdom%E5%92%8Cdiff%E7%AE%97%E6%B3%95">虚拟DOM和Diff算法</a></li><li><a href="#%E5%B7%A5%E4%BD%9C%E4%B8%AD%E9%A1%B9%E7%9B%AE%E4%BC%98%E5%8C%96%E5%AE%9E%E8%B7%B5">工作中项目优化实践</a></li><li><a href="#defineproperty-vs-proxy">defineProperty vs proxy</a></li><li><a href="#%E6%89%8B%E5%86%99-call">手写 call</a></li><li><a href="#%E6%89%8B%E5%86%99-apply">手写 apply</a></li><li><a href="#%E6%89%8B%E5%86%99bind">手写bind</a></li><li><a href="#preload%E5%92%8Cprefetch">preload和prefetch</a><ul><li><a href="#%E5%AF%B9%E6%AF%94">对比</a></li></ul></li><li><a href="#%E5%A6%82%E4%BD%95%E6%AF%94%E8%BE%83%E4%B8%A4%E4%B8%AA-dom-%E6%A0%91%E7%9A%84%E5%B7%AE%E5%BC%82">如何比较两个 DOM 树的差异？</a></li></ul><!-- tocstop --></div><blockquote><p>在写这篇前端散记之前有写过另外两篇散记，可点击 <a href="https://jelon.link/posts/front-end-notes/">前端散记</a> 和 <a href="https://jelon.link/posts/front-end-notes-2/">前端散记 2</a> 访问。所谓散记，东西都比较零散，更谈不上什么深入，但是至少可以让读者知道一些概念理论，如果深入可以自行去查询相关知识。</p></blockquote><h1><span id="async-await-实现原理">async await 实现原理</span></h1><p><strong>async 函数的实现，就是将 Generator 函数和自动执行器，包装在一个函数里。</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">args</span>)&#123;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 等同于</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">args</span>)&#123; </span><br><span class="line">  <span class="keyword">return</span> <span class="title function_">spawn</span>(<span class="keyword">function</span>*() &#123;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">  &#125;); </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>所有的 async 函数都可以写成上面的第二种形式，其中的 spawn 函数就是自动执行器。</p><p>下面给出 spawn 函数的实现，基本就是前文自动执行器的翻版。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">spawn</span>(<span class="params">genF</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="keyword">function</span>(<span class="params">resolve, reject</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> gen = <span class="title function_">genF</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">step</span>(<span class="params">nextF</span>) &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">var</span> next = <span class="title function_">nextF</span>();</span><br><span class="line">      &#125; <span class="keyword">catch</span>(e) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">reject</span>(e); </span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span>(next.<span class="property">done</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">resolve</span>(next.<span class="property">value</span>);</span><br><span class="line">      &#125; </span><br><span class="line">      <span class="title class_">Promise</span>.<span class="title function_">resolve</span>(next.<span class="property">value</span>).<span class="title function_">then</span>(<span class="keyword">function</span>(<span class="params">v</span>) &#123;</span><br><span class="line">        <span class="title function_">step</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123; <span class="keyword">return</span> gen.<span class="title function_">next</span>(v); &#125;);      </span><br><span class="line">      &#125;, <span class="keyword">function</span>(<span class="params">e</span>) &#123;</span><br><span class="line">        <span class="title function_">step</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123; <span class="keyword">return</span> gen.<span class="keyword">throw</span>(e); &#125;);</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">step</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123; <span class="keyword">return</span> gen.<span class="title function_">next</span>(<span class="literal">undefined</span>); &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>async 函数是非常新的语法功能，新到都不属于 ES6，而是属于 ES7。目前，它仍处于提案阶段，但是转码器 Babel 和 regenerator 都已经支持，转码后就能使用。</p><h1><span id="async-await-注意点">async await 注意点</span></h1><p>await 命令后面的 Promise 对象，运行结果可能是 rejected，所以最好把 await 命令放在 try…catch 代码块中。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">sync <span class="keyword">function</span> <span class="title function_">myFunction</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">await</span> <span class="title function_">somethingThatReturnsAPromise</span>();</span><br><span class="line">  &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(err);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 另一种写法</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">myFunction</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">await</span> <span class="title function_">somethingThatReturnsAPromise</span>().<span class="title function_">catch</span>(<span class="keyword">function</span> (<span class="params">err</span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(err);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>await 命令只能用在 async 函数之中，如果用在普通函数，就会报错。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">dbFuc</span>(<span class="params">db</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> docs = [&#123;&#125;, &#123;&#125;, &#123;&#125;];</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 报错</span></span><br><span class="line">  docs.<span class="title function_">forEach</span>(<span class="keyword">function</span> (<span class="params">doc</span>) &#123;</span><br><span class="line">    <span class="keyword">await</span> db.<span class="title function_">post</span>(doc);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面代码会报错，因为 await 用在普通函数之中了。但是，如果将 forEach 方法的参数改成 async 函数，也有问题。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">dbFuc</span>(<span class="params">db</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> docs = [&#123;&#125;, &#123;&#125;, &#123;&#125;];</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 可能得到错误结果</span></span><br><span class="line">  docs.<span class="title function_">forEach</span>(<span class="keyword">async</span> <span class="keyword">function</span> (<span class="params">doc</span>) &#123;</span><br><span class="line">    <span class="keyword">await</span> db.<span class="title function_">post</span>(doc);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面代码可能不会正常工作，原因是这时三个 db.post 操作将是并发执行，也就是同时执行，而不是继发执行。正确的写法是采用 for 循环。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">dbFuc</span>(<span class="params">db</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> docs = [&#123;&#125;, &#123;&#125;, &#123;&#125;];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> doc <span class="keyword">of</span> docs) &#123;</span><br><span class="line">    <span class="keyword">await</span> db.<span class="title function_">post</span>(doc);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>如果确实希望多个请求并发执行，可以使用 Promise.all 方法。</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">dbFuc</span>(<span class="params">db</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> docs = [&#123;&#125;, &#123;&#125;, &#123;&#125;];</span><br><span class="line">  <span class="keyword">let</span> promises = docs.<span class="title function_">map</span>(<span class="function">(<span class="params">doc</span>) =&gt;</span> db.<span class="title function_">post</span>(doc));</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> results = <span class="keyword">await</span> <span class="title class_">Promise</span>.<span class="title function_">all</span>(promises);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(results);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 或者使用下面的写法</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">dbFuc</span>(<span class="params">db</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> docs = [&#123;&#125;, &#123;&#125;, &#123;&#125;];</span><br><span class="line">  <span class="keyword">let</span> promises = docs.<span class="title function_">map</span>(<span class="function">(<span class="params">doc</span>) =&gt;</span> db.<span class="title function_">post</span>(doc));</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> results = [];</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> promise <span class="keyword">of</span> promises) &#123;</span><br><span class="line">    results.<span class="title function_">push</span>(<span class="keyword">await</span> promise);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(results);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1><span id="es5-实现继承">ES5 实现继承</span></h1><p><strong>第一种方式是借助call实现继承：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Parent1</span>(<span class="params"></span>)&#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">name</span> = <span class="string">&#x27;parent1&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Child1</span>(<span class="params"></span>)&#123;</span><br><span class="line">  <span class="title class_">Parent1</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">type</span> = <span class="string">&#x27;child1&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">new</span> <span class="title class_">Child1</span>);</span><br></pre></td></tr></table></figure><p>复制代码这样写的时候子类虽然能够拿到父类的属性值，但是问题是父类原型对象中一旦存在方法那么子类无法继承。那么引出下面的方法。</p><p><strong>第二种方式借助原型链实现继承：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Parent2</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">name</span> = <span class="string">&#x27;parent2&#x27;</span>;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">play</span> = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Child2</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">type</span> = <span class="string">&#x27;child2&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Child2</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Parent2</span>();</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">new</span> <span class="title class_">Child2</span>());</span><br></pre></td></tr></table></figure><p>看似没有问题，父类的方法和属性都能够访问，但实际上有一个潜在的不足。举个例子：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> s1 = <span class="keyword">new</span> <span class="title class_">Child2</span>();</span><br><span class="line"><span class="keyword">var</span> s2 = <span class="keyword">new</span> <span class="title class_">Child2</span>();</span><br><span class="line">s1.<span class="property">play</span>.<span class="title function_">push</span>(<span class="number">4</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s1.<span class="property">play</span>, s2.<span class="property">play</span>);</span><br></pre></td></tr></table></figure><p>可以看到控制台：</p><p><img src="https://jangdelong.github.io/blog_img/images/front-end-notes-3/1.jpg"></p><p>明明我只改变了s1的play属性，为什么s2也跟着变了呢？很简单，因为两个实例使用的是同一个原型对象。</p><p>那么还有更好的方式么？</p><p><strong>第三种方式：将前两种组合：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Parent3</span> (<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">name</span> = <span class="string">&#x27;parent3&#x27;</span>;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">play</span> = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Child3</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="title class_">Parent3</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">type</span> = <span class="string">&#x27;child3&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Child3</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Parent3</span>();</span><br><span class="line"><span class="keyword">var</span> s3 = <span class="keyword">new</span> <span class="title class_">Child3</span>();</span><br><span class="line"><span class="keyword">var</span> s4 = <span class="keyword">new</span> <span class="title class_">Child3</span>();</span><br><span class="line">s3.<span class="property">play</span>.<span class="title function_">push</span>(<span class="number">4</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s3.<span class="property">play</span>, s4.<span class="property">play</span>);</span><br></pre></td></tr></table></figure><p>可以看到控制台：</p><p><img src="https://jangdelong.github.io/blog_img/images/front-end-notes-3/2.png"></p><p>之前的问题都得以解决。但是这里又徒增了一个新问题，那就是Parent3的构造函数会多执行了一次（Child3.prototype &#x3D; new Parent3();）。这是我们不愿看到的。那么如何解决这个问题？</p><p><strong>第四种方式: 组合继承的优化1</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Parent4</span> (<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">name</span> = <span class="string">&#x27;parent4&#x27;</span>;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">play</span> = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Child4</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="title class_">Parent4</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">type</span> = <span class="string">&#x27;child4&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Child4</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="title class_">Parent4</span>.<span class="property"><span class="keyword">prototype</span></span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这里让将父类原型对象直接给到子类，父类构造函数只执行一次，而且父类属性和方法均能访问，但是我们来测试一下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> s3 = <span class="keyword">new</span> <span class="title class_">Child4</span>();</span><br><span class="line"><span class="keyword">var</span> s4 = <span class="keyword">new</span> <span class="title class_">Child4</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s3)</span><br></pre></td></tr></table></figure><p><img src="https://jangdelong.github.io/blog_img/images/front-end-notes-3/3.png"></p><p>子类实例的构造函数是Parent4，显然这是不对的，应该是Child4。</p><p><strong>第五种方式(最推荐使用)：优化2</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Parent5</span> (<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">name</span> = <span class="string">&#x27;parent5&#x27;</span>;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">play</span> = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Child5</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="title class_">Parent5</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">type</span> = <span class="string">&#x27;child5&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Child5</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="title class_">Object</span>.<span class="title function_">create</span>(<span class="title class_">Parent5</span>.<span class="property"><span class="keyword">prototype</span></span>);</span><br><span class="line"><span class="title class_">Child5</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> = <span class="title class_">Child5</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这是最推荐的一种方式，接近完美的继承。</p><p>因此，小小的继承虽然ES6当中简化了很多，但毋庸置疑的是，js是一门基于原型的语言，所以，用ES5来完成继承非常考验面试者对JS语言本身的理解，尤其是对于原型链是否理解清楚。</p><h1><span id="虚拟dom和diff算法">虚拟DOM和Diff算法</span></h1><p><strong>虚拟DOM</strong></p><p>虚拟Dom(virtual dom)到底是什么，简单来讲，就是将真实的dom节点用JavaScript来模拟出来，而Dom变化的对比，放到 Js 层来做。</p><ul><li>传统DOM节点</li></ul><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">ul</span> <span class="attr">id</span>=<span class="string">&quot;list&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">li</span> <span class="attr">class</span>=<span class="string">&quot;item&quot;</span>&gt;</span>jelon1<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">li</span> <span class="attr">class</span>=<span class="string">&quot;item&quot;</span>&gt;</span>jelon2<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure><ul><li>对应虚拟DOM</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">tag</span>: <span class="string">&#x27;ul&#x27;</span>,</span><br><span class="line">  <span class="attr">attrs</span>: &#123;</span><br><span class="line">    <span class="attr">id</span>: <span class="string">&#x27;list&#x27;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">children</span>: [</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">tag</span>: <span class="string">&#x27;li&#x27;</span>,</span><br><span class="line">      <span class="attr">attrs</span>: &#123;</span><br><span class="line">        <span class="attr">className</span>: <span class="string">&#x27;item&#x27;</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">children</span>: [ <span class="string">&#x27;jelon1&#x27;</span> ]</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">tag</span>: <span class="string">&#x27;li&#x27;</span>,</span><br><span class="line">      <span class="attr">attrs</span>: &#123;</span><br><span class="line">        <span class="attr">className</span>: <span class="string">&#x27;item&#x27;</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">children</span>: [ <span class="string">&#x27;jelon2&#x27;</span> ]</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>render方法</li></ul><p><strong>diff算法</strong></p><p>关键词：patch</p><p>可参考<a href="https://juejin.im/post/5affd01551882542c83301da#comment">详解vue的diff算法</a></p><p><img src="https://jangdelong.github.io/blog_img/images/front-end-notes-3/4.png?v=1"></p><h1><span id="工作中项目优化实践">工作中项目优化实践</span></h1><blockquote><p>前端优化主要基于两个目的：</p><ol><li>提升加载速度；</li><li>用户操作起来流畅。<br>因此，以下优化主要是围绕这两个目的展开。</li></ol></blockquote><ol><li>css sprite（雪碧图），iconfont；</li><li>资源懒加载、异步路由；</li><li>前端缓存 LocalStorage 及混合应用 Storage；</li><li>使用 CDN（JS、CSS等资源使用外部域名）；</li><li>Tree Shaking （Webpack 4.0+）；</li><li>预请求；</li><li>资源按需加载；</li><li>gzip （服务器）；</li><li>减少 DOM 操作；</li><li>防抖节流；</li><li>尽量少用iframe；</li><li>尽量规避 CSS 计算。</li></ol><p><strong>参考思路</strong></p><p><img src="https://jangdelong.github.io/blog_img/images/front-end-notes-3/5.jpeg?v=1"></p><p><strong>雅虎军规</strong></p><p><a href="https://developer.yahoo.com/performance/rules.html?guccounter=1">Best Practices for Speeding Up Your Web Site</a></p><h1><span id="defineproperty-vs-proxy">defineProperty vs proxy</span></h1><ul><li>Proxy可以直接监听对象而非属性；</li><li>Proxy直接可以劫持整个对象,并返回一个新对象,不管是操作便利程度还是底层功能上都远强于Object.defineProperty；</li><li>Proxy可以直接监听数组的变化；</li><li>Proxy有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的。</li></ul><h1><span id="手写-call">手写 call</span></h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">call2</span> = <span class="keyword">function</span> (<span class="params">context</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> context = context || <span class="variable language_">window</span>;</span><br><span class="line">    context.<span class="property">fn</span> = <span class="variable language_">this</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> args = [];</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">1</span>, len = <span class="variable language_">arguments</span>.<span class="property">length</span>; i &lt; len; i++) &#123;</span><br><span class="line">        args.<span class="title function_">push</span>(<span class="string">&#x27;arguments[&#x27;</span> + i + <span class="string">&#x27;]&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> result = <span class="built_in">eval</span>(<span class="string">&#x27;context.fn(&#x27;</span> + args +<span class="string">&#x27;)&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">delete</span> context.<span class="property">fn</span></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1><span id="手写-apply">手写 apply</span></h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">apply</span> = <span class="keyword">function</span> (<span class="params">context, arr</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> context = <span class="title class_">Object</span>(context) || <span class="variable language_">window</span>;</span><br><span class="line">    context.<span class="property">fn</span> = <span class="variable language_">this</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> result;</span><br><span class="line">    <span class="keyword">if</span> (!arr) &#123;</span><br><span class="line">        result = context.<span class="title function_">fn</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">var</span> args = [];</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>, len = arr.<span class="property">length</span>; i &lt; len; i++) &#123;</span><br><span class="line">            args.<span class="title function_">push</span>(<span class="string">&#x27;arr[&#x27;</span> + i + <span class="string">&#x27;]&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        result = <span class="built_in">eval</span>(<span class="string">&#x27;context.fn(&#x27;</span> + args + <span class="string">&#x27;)&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">delete</span> context.<span class="property">fn</span></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1><span id="手写bind">手写bind</span></h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">bind2</span> = <span class="keyword">function</span> (<span class="params">asThis, ...args1</span>) &#123;</span><br><span class="line">   <span class="keyword">let</span> fn = <span class="variable language_">this</span>;  <span class="comment">// 函数调用时，原this其实就是这个调用函数</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span>(<span class="params">...args2</span>) &#123;  <span class="comment">// 同时，返回的新函数也可以接受参数</span></span><br><span class="line">        <span class="keyword">return</span> fn.<span class="title function_">call</span>(asThis, ...args1, ...args2);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1><span id="preload和prefetch">preload和prefetch</span></h1><p>preload特点</p><p>preload加载的资源是在浏览器渲染机制之前进行处理的，并且不会阻塞onload事件；<br>preload可以支持加载多种类型的资源，并且可以加载跨域资源；<br>preload加载的js脚本其加载和执行的过程是分离的。即preload会预加载相应的脚本代码，待到需要时自行调用；<br>prefetch</p><p>prefetch是一种利用浏览器的空闲时间加载页面将来可能用到的资源的一种机制；通常可以用于加载非首页的其他页面所需要的资源，以便加快后续页面的首屏速度；</p><p>prefetch特点</p><p>prefetch加载的资源可以获取非当前页面所需要的资源，并且将其放入缓存至少5分钟（无论资源是否可以缓存）；并且，当页面跳转时，未完成的prefetch请求不会被中断。</p><h2><span id="对比">对比</span></h2><p>Chrome有四种缓存：http cache、memory cache、Service Worker cache和Push<br>cache。在preload或prefetch的资源加载时，两者均存储在http<br>cache。当资源加载完成后，如果资源是可以被缓存的，那么其被存储在http<br>cache中等待后续使用；如果资源不可被缓存，那么其在被使用前均存储在memory cache；<br>preload和prefetch都没有同域名的限制；<br>preload主要用于预加载当前页面需要的资源；而prefetch主要用于加载将来页面可能需要的资源；<br>不论资源是否可以缓存，prefecth会存储在net-stack cache中至少5分钟；<br>preload需要使用as属性指定特定的资源类型以便浏览器为其分配一定的优先级，并能够正确加载资源；</p><h1><span id="如何比较两个-dom-树的差异">如何比较两个 DOM 树的差异？</span></h1><p>两个树的完全 diff 算法的时间复杂度为 O(n^3) ，但是在前端中，我们很少会跨层级的移动元素，所以我们只需要比较同一层级的元素进行比较，这样就可以将算法的时间复杂度降低为 O(n)。</p><p>算法首先会对新旧两棵树进行一个深度优先的遍历，这样每个节点都会有一个序号。在深度遍历的时候，每遍历到一个节点，我们就将这个节点和新的树中的节点进行比较，如果有差异，则将这个差异记录到一个对象中。</p><p>在对列表元素进行对比的时候，由于 TagName 是重复的，所以我们不能使用这个来对比。我们需要给每一个子节点加上一个 key，列表对比的时候使用 key 来进行比较，这样我们才能够复用老的 DOM 树上的节点。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;div class=&quot;toc&quot;&gt;

&lt;!-- toc --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#async-await-%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86&quot;&gt;async await 实现原理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=</summary>
      
    
    
    
    <category term="Web技术" scheme="https://jelon.link/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="前端" scheme="https://jelon.link/tags/%E5%89%8D%E7%AB%AF/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】94. 二叉树的中序遍历</title>
    <link href="https://jelon.link/posts/leetcode-94/"/>
    <id>https://jelon.link/posts/leetcode-94/</id>
    <published>2020-05-27T00:00:00.000Z</published>
    <updated>2020-05-27T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>给定一个二叉树，返回它的中序 遍历。</p><p><strong>示例:</strong></p><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">输入: <span class="comment">[1,null,2,3]</span></span><br><span class="line">   1</span><br><span class="line">    \</span><br><span class="line">     2</span><br><span class="line">    /</span><br><span class="line">   3</span><br><span class="line"></span><br><span class="line">输出: <span class="comment">[1,3,2]</span></span><br></pre></td></tr></table></figure><p>进阶: 递归算法很简单，你可以通过迭代算法完成吗？</p><h5><span id="个人解答">个人解答</span></h5><p><strong>方法一：递归</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * function TreeNode(val) &#123;</span></span><br><span class="line"><span class="comment"> *     this.val = val;</span></span><br><span class="line"><span class="comment"> *     this.left = this.right = null;</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">TreeNode</span>&#125; <span class="variable">root</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">number[]</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> inorderTraversal = <span class="keyword">function</span>(<span class="params">root</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> res = []</span><br><span class="line">  <span class="title function_">traversal</span>(root, res)</span><br><span class="line">  <span class="keyword">return</span> res</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">traversal</span> (<span class="params">root, res</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (root) &#123;</span><br><span class="line">    <span class="keyword">if</span> (root.<span class="property">left</span>) &#123;</span><br><span class="line">      <span class="title function_">traversal</span>(root.<span class="property">left</span>, res)</span><br><span class="line">    &#125;</span><br><span class="line">    res.<span class="title function_">push</span>(root.<span class="property">val</span>)</span><br><span class="line">    <span class="keyword">if</span> (root.<span class="property">right</span>) &#123;</span><br><span class="line">      <span class="title function_">traversal</span>(root.<span class="property">right</span>, res)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>方法而：栈</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> inorderTraversal = <span class="keyword">function</span>(<span class="params">root</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> res = []</span><br><span class="line">  <span class="keyword">var</span> stack = []</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">while</span> (root || stack.<span class="property">length</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (root.<span class="property">left</span>) &#123; <span class="comment">// 如果有左节点先遍历左节点</span></span><br><span class="line">      stack.<span class="title function_">push</span>(root)</span><br><span class="line">      root = root.<span class="property">left</span></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!root.<span class="property">left</span> &amp;&amp; !root.<span class="property">right</span>) &#123; <span class="comment">// 既没有左节点也没有右节点</span></span><br><span class="line">      res.<span class="title function_">push</span>(root.<span class="property">val</span>)</span><br><span class="line">      root = stack.<span class="title function_">pop</span>() <span class="comment">// 回溯</span></span><br><span class="line">      root &amp;&amp; (root.<span class="property">left</span> = <span class="literal">null</span>)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (root.<span class="property">right</span>) &#123; <span class="comment">// 如果有右节点</span></span><br><span class="line">      res.<span class="title function_">push</span>(root.<span class="property">val</span>)</span><br><span class="line">      root = root.<span class="property">right</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> res</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5><span id="解题思路">解题思路</span></h5><p><img src="https://jangdelong.github.io/blog_img/images/leetcode-94/1.png" alt="https:&#x2F;&#x2F;jangdelong.github.io&#x2F;blog_img&#x2F;images&#x2F;leetcode-94&#x2F;1.png"></p><ul><li><p>前序遍历：先输出根节点，在依次前序遍历左子树和右子树；</p></li><li><p><strong>中序遍历：先中序遍历左子树，在输出根节点，最后中序遍历右子树；</strong></p></li><li><p>后序遍历：先后序遍历左子树，接着后序遍历右子树，最后输出根节点。</p></li></ul><p>输出</p><p>前序遍历：1，2，4，5，3，6，7；</p><p><strong>中序遍历：4，2，5，1，3，7，6</strong></p><p>后序遍历：4，5，2，7，6，3，1</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;给定一个二叉树，返回它的中序 遍历。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例:&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight inform7&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】面试题 02.05. 链表求和</title>
    <link href="https://jelon.link/posts/leetcode-02-05/"/>
    <id>https://jelon.link/posts/leetcode-02-05/</id>
    <published>2020-05-21T00:00:00.000Z</published>
    <updated>2020-05-21T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>给定两个用链表表示的整数，每个节点包含一个数位。</p><p>这些数位是反向存放的，也就是个位排在链表首部。</p><p>编写函数对这两个整数求和，并用链表形式返回结果。</p><p> </p><p><strong>示例：</strong></p><figure class="highlight clean"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入：(<span class="number">7</span> -&gt; <span class="number">1</span> -&gt; <span class="number">6</span>) + (<span class="number">5</span> -&gt; <span class="number">9</span> -&gt; <span class="number">2</span>)，即<span class="number">617</span> + <span class="number">295</span></span><br><span class="line">输出：<span class="number">2</span> -&gt; <span class="number">1</span> -&gt; <span class="number">9</span>，即<span class="number">912</span></span><br><span class="line">进阶：假设这些数位是正向存放的，请再做一遍。</span><br></pre></td></tr></table></figure><p><strong>示例：</strong></p><figure class="highlight clean"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入：(<span class="number">6</span> -&gt; <span class="number">1</span> -&gt; <span class="number">7</span>) + (<span class="number">2</span> -&gt; <span class="number">9</span> -&gt; <span class="number">5</span>)，即<span class="number">617</span> + <span class="number">295</span></span><br><span class="line">输出：<span class="number">9</span> -&gt; <span class="number">1</span> -&gt; <span class="number">2</span>，即<span class="number">912</span></span><br></pre></td></tr></table></figure><h5><span id="个人解答">个人解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) &#123;</span></span><br><span class="line"><span class="comment"> *     this.val = val;</span></span><br><span class="line"><span class="comment"> *     this.next = null;</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">ListNode</span>&#125; <span class="variable">l1</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">ListNode</span>&#125; <span class="variable">l2</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">ListNode</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> addTwoNumbers = <span class="keyword">function</span>(<span class="params">l1, l2</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> count = <span class="number">0</span> <span class="comment">// 进数位</span></span><br><span class="line">  <span class="keyword">var</span> head = &#123;&#125; <span class="comment">// 头节点</span></span><br><span class="line">  <span class="keyword">var</span> cur = head <span class="comment">// 指针节点</span></span><br><span class="line">  <span class="keyword">while</span> (l1 || l2 || count) &#123;</span><br><span class="line">    count += (l1 &amp;&amp; l1.<span class="property">val</span>) + (l2 &amp;&amp; l2.<span class="property">val</span>)</span><br><span class="line">    cur = cur.<span class="property">next</span> = <span class="keyword">new</span> <span class="title class_">ListNode</span>(count % <span class="number">10</span>)</span><br><span class="line">    l1 = l1 &amp;&amp; l1.<span class="property">next</span></span><br><span class="line">    l2 = l2 &amp;&amp; l2.<span class="property">next</span></span><br><span class="line">    count = <span class="title class_">Math</span>.<span class="title function_">floor</span>(count / <span class="number">10</span>)  <span class="comment">/* 进1 */</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> head.<span class="property">next</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5><span id="参考思路">参考思路</span></h5><p>双指针。</p><p>时间复杂度：o(n)<br>空间复杂度：o(n)</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;给定两个用链表表示的整数，每个节点包含一个数位。&lt;/p&gt;
&lt;p&gt;这些数位是反向存放的，也就是个位排在链表首部。&lt;/p&gt;
&lt;p&gt;编写函数对这两个整数求和，并用链表形式返回结果。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例：&lt;/strong&gt;&lt;/p&gt;
&lt;figure </summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】面试题22. 链表中倒数第k个节点</title>
    <link href="https://jelon.link/posts/leetcode-case-22/"/>
    <id>https://jelon.link/posts/leetcode-case-22/</id>
    <published>2020-05-21T00:00:00.000Z</published>
    <updated>2020-05-21T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>输入一个链表，输出该链表中倒数第k个节点。为了符合大多数人的习惯，本题从1开始计数，即链表的尾节点是倒数第1个节点。例如，一个链表有6个节点，从头节点开始，它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。</p><p> </p><p><strong>示例：</strong></p><figure class="highlight clean"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">给定一个链表: <span class="number">1</span>-&gt;<span class="number">2</span>-&gt;<span class="number">3</span>-&gt;<span class="number">4</span>-&gt;<span class="number">5</span>, 和 k = <span class="number">2.</span></span><br><span class="line"></span><br><span class="line">返回链表 <span class="number">4</span>-&gt;<span class="number">5.</span></span><br></pre></td></tr></table></figure><h5><span id="个人解答">个人解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) &#123;</span></span><br><span class="line"><span class="comment"> *     this.val = val;</span></span><br><span class="line"><span class="comment"> *     this.next = null;</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">ListNode</span>&#125; <span class="variable">head</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">number</span>&#125; <span class="variable">k</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">ListNode</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 双指针</span></span><br><span class="line"><span class="keyword">var</span> getKthFromEnd = <span class="keyword">function</span>(<span class="params">head, k</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (k &lt; <span class="number">0</span> || !head) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">var</span> pointer = head</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">1</span>; i &lt; k; i++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (pointer.<span class="property">next</span>) &#123;</span><br><span class="line">      pointer = pointer.<span class="property">next</span></span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">while</span> (pointer.<span class="property">next</span>) &#123;</span><br><span class="line">    head = head.<span class="property">next</span></span><br><span class="line">    pointer = pointer.<span class="property">next</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> head</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5><span id="解题思路">解题思路</span></h5><p>双指针</p><ol><li>参考指针 pointer 先从头遍历到 k，然后剩下长度为 len - k；</li><li>head 指针再从投开始遍历 len - k 个节点，即可得到倒数第 k 个节点。</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;输入一个链表，输出该链表中倒数第k个节点。为了符合大多数人的习惯，本题从1开始计数，即链表的尾节点是倒数第1个节点。例如，一个链表有6个节点，从头节点开始，它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;st</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】206. 反转链表</title>
    <link href="https://jelon.link/posts/leetcode-206/"/>
    <id>https://jelon.link/posts/leetcode-206/</id>
    <published>2020-05-20T00:00:00.000Z</published>
    <updated>2020-05-20T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>反转一个单链表。</p><p><strong>示例:</strong></p><figure class="highlight clean"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: <span class="number">1</span>-&gt;<span class="number">2</span>-&gt;<span class="number">3</span>-&gt;<span class="number">4</span>-&gt;<span class="number">5</span>-&gt;NULL</span><br><span class="line">输出: <span class="number">5</span>-&gt;<span class="number">4</span>-&gt;<span class="number">3</span>-&gt;<span class="number">2</span>-&gt;<span class="number">1</span>-&gt;NULL</span><br></pre></td></tr></table></figure><p><strong>进阶:</strong></p><p>你可以迭代或递归地反转链表。你能否用两种方法解决这道题？</p><h5><span id="个人解答">个人解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) &#123;</span></span><br><span class="line"><span class="comment"> *     this.val = val;</span></span><br><span class="line"><span class="comment"> *     this.next = null;</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">ListNode</span>&#125; <span class="variable">head</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">ListNode</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 双指针</span></span><br><span class="line"><span class="keyword">var</span> reverseList = <span class="keyword">function</span>(<span class="params">head</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> prev = <span class="literal">null</span></span><br><span class="line">  <span class="keyword">var</span> cur = head</span><br><span class="line">  <span class="keyword">var</span> tmp = <span class="literal">null</span></span><br><span class="line">  <span class="keyword">while</span> (cur) &#123;</span><br><span class="line">    tmp = cur.<span class="property">next</span></span><br><span class="line">    cur.<span class="property">next</span> = prev</span><br><span class="line">    prev = cur</span><br><span class="line">    cur = tmp</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> prev</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5><span id="参考思路">参考思路</span></h5><p>双指针</p><p><img src="https://jangdelong.github.io/blog_img/images/leetcode-206/1.gif" alt="双指针解法"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;反转一个单链表。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例:&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight clean&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;b</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】面试题 16.01. 交换数字</title>
    <link href="https://jelon.link/posts/leetcode-case-16-01/"/>
    <id>https://jelon.link/posts/leetcode-case-16-01/</id>
    <published>2020-05-18T00:00:00.000Z</published>
    <updated>2020-05-18T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>编写一个函数，不用临时变量，直接交换 <code>numbers = [a, b]</code> 中 <code>a</code> 与 <code>b</code> 的值。</p><p><strong>示例：</strong></p><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: numbers = <span class="comment">[1,2]</span></span><br><span class="line">输出: <span class="comment">[2,1]</span></span><br></pre></td></tr></table></figure><p><strong>提示：</strong></p><ul><li>numbers.length &#x3D;&#x3D; 2</li></ul><h5><span id="个人解答">个人解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">number[]</span>&#125; <span class="variable">numbers</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">number[]</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// 做减法</span></span><br><span class="line"><span class="keyword">var</span> swapNumbers = <span class="keyword">function</span>(<span class="params">numbers</span>) &#123;</span><br><span class="line">  numbers[<span class="number">1</span>] = numbers[<span class="number">0</span>] - numbers[<span class="number">1</span>];</span><br><span class="line">  numbers[<span class="number">0</span>] = numbers[<span class="number">0</span>] - numbers[<span class="number">1</span>];</span><br><span class="line">  numbers[<span class="number">1</span>] = numbers[<span class="number">0</span>] + numbers[<span class="number">1</span>];</span><br><span class="line">  <span class="keyword">return</span> numbers</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5><span id="解题思路">解题思路</span></h5><p>使用减法思路。</p><p>以 a、b 为例：a &#x3D; 1; b &#x3D; 2</p><p>第一遍：b（临时） &#x3D; a - b;<br>第二遍：a &#x3D; a - b（临时）; &#x2F;&#x2F; 得出 a &#x3D; 原b;<br>第三遍：b &#x3D; a（原b） + b（临时：原a - 原b）; &#x2F;&#x2F; 得出 b &#x3D; 原a;</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;编写一个函数，不用临时变量，直接交换 &lt;code&gt;numbers = [a, b]&lt;/code&gt; 中 &lt;code&gt;a&lt;/code&gt; 与 &lt;code&gt;b&lt;/code&gt; 的值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例：&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;hig</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>前端散记 2</title>
    <link href="https://jelon.link/posts/front-end-notes-2/"/>
    <id>https://jelon.link/posts/front-end-notes-2/</id>
    <published>2020-05-08T00:00:00.000Z</published>
    <updated>2020-05-08T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#keep-alive-vs-http2">keep-alive vs http2</a><ul><li><a href="#http-pipelining">http pipelining</a></li><li><a href="#http2">HTTP2</a></li></ul></li><li><a href="#http3%E7%9B%B8%E5%85%B3">HTTP3相关</a><ul><li><a href="#http3-%E6%96%B0%E7%89%B9%E6%80%A7">HTTP&#x2F;3 新特性</a><ul><li><a href="#1-http3%E7%AE%80%E4%BB%8B">1. HTTP&#x2F;3简介</a></li><li><a href="#2-quic%E6%96%B0%E5%8A%9F%E8%83%BD">2. QUIC新功能</a></li></ul></li><li><a href="#%E6%80%BB%E7%BB%93">总结</a></li></ul></li><li><a href="#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%BC%98%E5%8C%96">小程序优化</a></li><li><a href="#webpack-%E4%BC%98%E5%8C%96">Webpack 优化</a></li><li><a href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E6%B8%B2%E6%9F%93%E9%A1%B5%E9%9D%A2%E7%9A%84%E8%BF%87%E7%A8%8B">浏览器渲染页面的过程</a></li><li><a href="#asyncawait-%E4%B8%8E-generator-%E5%8C%BA%E5%88%AB">async&#x2F;await 与 Generator 区别</a></li><li><a href="#jsonp-%E5%B0%81%E8%A3%85">JSONP 封装</a></li><li><a href="#%E5%B9%B3%E6%B0%91%E7%89%88%E6%B7%B1%E5%BA%A6%E6%8B%B7%E8%B4%9D">平民版深度拷贝</a></li><li><a href="#instanceof-%E5%AE%9E%E7%8E%B0">instanceof 实现</a></li><li><a href="#new-%E5%B0%81%E8%A3%85">new 封装</a></li><li><a href="#%E6%89%8B%E5%86%99-promise-%E4%B9%9E%E4%B8%90%E7%89%88">手写 Promise （乞丐版）</a></li><li><a href="#flex">flex</a></li></ul><!-- tocstop --></div><blockquote><p>在写这篇前端散记之前有写过另外一篇散记，可点击 <a href="https://jelon.link/posts/front-end-notes/">前端散记</a> 访问。所谓散记，东西都比较零散，更谈不上什么深入，但是至少可以让读者知道一些概念理论，如果深入可以自行去查询相关知识。</p></blockquote><h1><span id="keep-alive-vs-http2">keep-alive vs http2</span></h1><blockquote><p>有很多文章都说 http2 相比 http1.1 增加了连接复用。这句话其实是不准确的。</p></blockquote><p><strong>在 HTTP 1.1 中 所有的连接默认都是持续连接，除非特殊声明不支持。</strong> 而在 http1.0 中，官方没有支持 keep-alive, 通常会手动在请求头中添加 Connection: Keep-Alive。</p><p>keep-alive 就是 TCP 连接复用的开端。改善的效果就是不再重新建立TCP连接，省去 三次握手 的时间。如下图：</p><p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/HTTP_persistent_connection.svg/langzh-450px-HTTP_persistent_connection.svg.png" alt="keep-alive"></p><p>优势有：</p><ul><li>较少的CPU和内存的使用（由于同时打开的连接的减少了）；</li><li>允许请求和应答的HTTP管线化；</li><li>降低拥塞控制 （TCP连接减少了）；</li><li>减少了后续请求的延迟（无需再进行握手）；</li><li>报告错误无需关闭TCP连接。</li></ul><h2><span id="http-pipelining">http pipelining</span></h2><p>有些文章中会有一个误区，就是TCP连接必须等一个请求响应完成后，才能复用。这是不对的，但其实可以注意上面优势里提到到 http pipelining，如下图：</p><p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fb/HTTP_pipelining.svg/450px-HTTP_pipelining.svg.png"></p><p>HTTP1.1 中，一个TCP连接里是可以同时发送（实际有先后，但可以在响应前）多个请求的。但它是有序的，遵循先进先出，服务端只能按顺序响应请求（如果前面的请求没有响应完成或需要很长时间，后面的请求就会被阻塞），所以可能发生 队头阻塞（HOL blocking），造成延迟。</p><p>连续的 GET 和 HEAD 请求总可以管线化的。一个连续的幂等请求，如 GET，HEAD，PUT，DELETE，是否可以被管线化取决于一连串请求是否依赖于其他的。</p><p>所以keep-alive 的劣势也很明显：</p><ul><li>Keep-Alive可能会极大的影响服务器性能，因为它在文件被请求之后还保持了不必要的连接很长时间；</li><li>可能发生队头阻塞（HOL blocking），造成延迟。</li></ul><h2><span id="http2">HTTP2</span></h2><p>HTTP2 主要解决的问题也是 TCP连接复用。但它比 keep-alive 更彻底，类似于通信工程里的时分复用，多个请求可以同时发送（不分先后），同时响应，解决了 队头阻塞（HOL blocking）的问题，极大提高效率。</p><p><img src="https://upload.wikimedia.org/wikipedia/commons/7/73/Mux_color.png"></p><p>keep-alive 的 HTTP pipelining 相当于单线程的，而 HTTP2 相当于并发。</p><p>HTTP2 的优点：</p><ul><li>对HTTP头字段进行数据压缩(即HPACK算法)；</li><li>HTTP&#x2F;2 服务端推送(Server Push)；</li><li>请求管线化；</li><li>修复HTTP&#x2F;1.0版本以来未修复的队头阻塞问题；</li><li>对数据传输采用多路复用，让多个请求合并在同一 TCP连接内。</li></ul><p>后三个优点其实都是<strong>多路复用</strong>带来的优点。</p><h1><span id="http3相关">HTTP3相关</span></h1><h2><span id="httpx2f3-新特性">HTTP&#x2F;3 新特性</span></h2><h3><span id="1-httpx2f3简介">1. HTTP&#x2F;3简介</span></h3><p>虽然 HTTP&#x2F;2 解决了很多之前旧版本的问题，但是它还是存在一个巨大的问题，主要是底层支撑的 TCP 协议造成的。</p><p>上文提到 HTTP&#x2F;2 使用了多路复用，一般来说同一域名下只需要使用一个 TCP 连接。但当这个连接中出现了丢包的情况，那就会导致 HTTP&#x2F;2 的表现情况反倒不如 HTTP&#x2F;1 了。</p><p>因为在出现丢包的情况下，整个 TCP 都要开始等待重传，也就导致了后面的所有数据都被阻塞了。但是对于 HTTP&#x2F;1.1 来说，可以开启多个 TCP 连接，出现这种情况反到只会影响其中一个连接，剩余的 TCP 连接还可以正常传输数据。</p><p>那么可能就会有人考虑到去修改 TCP 协议，其实这已经是一件不可能完成的任务了。因为 TCP 存在的时间实在太长，已经充斥在各种设备中，并且这个协议是由操作系统实现的，更新起来不大现实。</p><p>基于这个原因，<strong>Google 就更起炉灶搞了一个基于 UDP 协议的 QUIC 协议，并且使用在了 HTTP&#x2F;3 上</strong>，HTTP&#x2F;3 之前名为 HTTP-over-QUIC，从这个名字中我们也可以发现，HTTP&#x2F;3 最大的改造就是使用了 QUIC。</p><p>QUIC 虽然基于 UDP，但是在原本的基础上新增了很多功能，接下来我们重点介绍几个QUIC新功能。</p><h3><span id="2-quic新功能">2. QUIC新功能</span></h3><ul><li><strong>0-RTT</strong></li></ul><p>通过使用类似 TCP 快速打开的技术，缓存当前会话的上下文，在下次恢复会话的时候，只需要将之前的缓存传递给服务端验证通过就可以进行传输了。0RTT 建连可以说是 QUIC 相比 HTTP2 最大的性能优势。那什么是 0RTT 建连呢？</p><p>这里面有两层含义:</p><ol><li>传输层 0RTT 就能建立连接。</li><li>加密层 0RTT 就能建立加密连接。</li></ol><p><img src="https://jangdelong.github.io/blog_img/images/front-end-notes-2/1.jpg"></p><p>上图左边是 HTTPS 的一次完全握手的建连过程，需要 3 个 RTT。就算是会话复用也需要至少 2 个 RTT。</p><p>而 QUIC 呢？由于建立在 UDP 的基础上，同时又实现了 0RTT 的安全握手，所以在大部分情况下，只需要 0 个 RTT 就能实现数据发送，在实现前向加密的基础上，并且 0RTT 的成功率相比 TLS 的会话记录单要高很多。</p><ul><li><strong>多路复用</strong></li></ul><p>虽然 HTTP&#x2F;2 支持了多路复用，但是 TCP 协议终究是没有这个功能的。QUIC 原生就实现了这个功能，并且传输的单个数据流可以保证有序交付且不会影响其他的数据流，这样的技术就解决了之前 TCP 存在的问题。</p><p>同HTTP2.0一样，同一条 QUIC连接上可以创建多个stream，来发送多个HTTP请求，但是，QUIC是基于UDP的，一个连接上的多个stream之间没有依赖。比如下图中stream2丢了一个UDP包，不会影响后面跟着 Stream3 和 Stream4，不存在 TCP 队头阻塞。虽然stream2的那个包需要重新传，但是stream3、stream4的包无需等待，就可以发给用户。</p><p><img src="https://jangdelong.github.io/blog_img/images/front-end-notes-2/2.jpg"></p><p>另外QUIC 在移动端的表现也会比 TCP 好。因为 TCP 是基于 IP 和端口去识别连接的，这种方式在多变的移动端网络环境下是很脆弱的。但是 QUIC 是通过 ID 的方式去识别一个连接，不管你网络环境如何变化，只要 ID 不变，就能迅速重连上。</p><ul><li><strong>加密认证的报文</strong></li></ul><p>TCP 协议头部没有经过任何加密和认证，所以在传输过程中很容易被中间网络设备篡改，注入和窃听。比如修改序列号、滑动窗口。这些行为有可能是出于性能优化，也有可能是主动攻击。</p><p>但是 QUIC 的 packet 可以说是武装到了牙齿。除了个别报文比如 PUBLIC_RESET 和 CHLO，所有报文头部都是经过认证的，报文 Body 都是经过加密的。</p><p>这样只要对 QUIC 报文任何修改，接收端都能够及时发现，有效地降低了安全风险。</p><p><img src="https://jangdelong.github.io/blog_img/images/front-end-notes-2/3.jpg"></p><p>如上图所示，红色部分是 Stream Frame 的报文头部，有认证。绿色部分是报文内容，全部经过加密。</p><ul><li><strong>向前纠错机制</strong></li></ul><p>QUIC协议有一个非常独特的特性，称为向前纠错 (Forward Error Correction，FEC)，每个数据包除了它本身的内容之外，还包括了部分其他数据包的数据，因此少量的丢包可以通过其他包的冗余数据直接组装而无需重传。向前纠错牺牲了每个数据包可以发送数据的上限，但是减少了因为丢包导致的数据重传，因为数据重传将会消耗更多的时间（包括确认数据包丢失、请求重传、等待新数据包等步骤的时间消耗）。</p><p>假如说这次我要发送三个包，那么协议会算出这三个包的异或值并单独发出一个校验包，也就是总共发出了四个包。当出现其中的非校验包丢包的情况时，可以通过另外三个包计算出丢失的数据包的内容。当然这种技术只能使用在丢失一个包的情况下，如果出现丢失多个包就不能使用纠错机制了，只能使用重传的方式了。</p><h2><span id="总结">总结</span></h2><p>HTTP&#x2F;1.x 有连接无法复用、队头阻塞、协议开销大和安全因素等多个缺陷；<br>HTTP&#x2F;2 通过多路复用、二进制流、Header 压缩等等技术，极大地提高了性能，但是还是存在着问题的；<br>QUIC 基于 UDP 实现，是 HTTP&#x2F;3 中的底层支撑协议，该协议基于 UDP，又取了 TCP 中的精华，实现了即快又可靠的协议。</p><h1><span id="小程序优化">小程序优化</span></h1><blockquote><p>以本人所项接触的项目（IM相关）实战为例</p></blockquote><ol><li>去除后端返回来的冗余字段；</li><li>状态管理（以为项目使用的是 <code>mpVue</code> 小程序开发框架） ；</li><li>图片资源优化（采用 CDN）；</li><li>图片使用 CDN 之后发现网络请求多了还是给人感觉体验不好，所以又采取了部分较小的图片直接打包进了项目 JS，由于担心小程序项目大小过大，所以才去分包；</li><li>群组人员 ID 缓存，并通过 ID 数组是否变化来加载人员信息。</li></ol><h1><span id="webpack-优化">Webpack 优化</span></h1><ol><li>externals + cdn；</li><li>cache-loader；</li><li>happy-pack、thread-loader；</li><li>webpack-bundle-analyzer</li><li>Tree Shaking</li><li>CommonChunkPlugin (Webpack 4.0移除，使用 SplitChunkPlugin 替代)；</li><li>DllPlugin 和 DllReferencePlugin：DLLPlugin 就是将包含大量复用模块且不会频繁更新的库进行编译，只需要编译一次，编译完成后存在指定的文件（这里可以称为动态链接库）中。在之后的构建过程中不会再对这些模块进行编译，而是直接使用 DllReferencePlugin 来引用动态链接库的代码。</li></ol><h1><span id="浏览器渲染页面的过程">浏览器渲染页面的过程</span></h1><p>从耗时的角度，浏览器请求、加载、渲染一个页面，时间花在下面五件事情上：</p><ol><li>DNS 查询</li><li>TCP 连接</li><li>HTTP 请求即响应</li><li>服务器响应</li><li>客户端渲染</li></ol><p>浏览器对内容的渲染，这一部分（渲染树构建、布局及绘制），又可以分为下面五个步骤：</p><ol><li>处理 HTML 标记并构建 DOM 树。</li><li>处理 CSS 标记并构建 CSSOM 树。</li><li>将 DOM 与 CSSOM 合并成一个渲染树。</li><li>根据渲染树来布局，以计算每个节点的几何信息。</li><li>将各个节点绘制到屏幕上。</li></ol><h1><span id="asyncx2fawait-与-generator-区别">async&#x2F;await 与 Generator 区别</span></h1><p>ES7 提出的async 函数，终于让 JavaScript 对于异步操作有了终极解决方案。No more callback hell。</p><p>async 函数是 Generator 函数的语法糖。使用 关键字 async 来表示，在函数内部使用 await 来表示异步。</p><p>想较于 Generator，Async 函数的改进在于下面四点：</p><ul><li><strong>内置执行器</strong>。Generator 函数的执行必须依靠执行器，而 Aysnc 函数自带执行器，调用方式跟普通函数的调用一样；</li><li><strong>更好的语义</strong>。async 和 await 相较于 * 和 yield 更加语义化；</li><li><strong>更广的适用性</strong>。co 模块约定，yield 命令后面只能是 Thunk 函数或 Promise对象。而 async 函数的 await 命令后面则可以是 Promise 或者 原始类型的值（Number，string，boolean，但这时等同于同步操作）；</li><li><strong>返回值是 Promise</strong>。async 函数返回值是 Promise 对象，比 Generator 函数返回的 Iterator 对象方便，可以直接使用 then() 方法进行调用。</li></ul><h1><span id="jsonp-封装">JSONP 封装</span></h1><blockquote><p>以下是之前在做跨域项目所封装的 jsonp 库</p></blockquote><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">jsonp</span>(<span class="params">options</span>) &#123;</span><br><span class="line">  options = options || &#123;&#125;</span><br><span class="line">  <span class="keyword">if</span> (!options.<span class="property">url</span>) &#123;</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;参数不合法&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 创建 script 标签并加入到页面中, 如果没传callback默认生成一个</span></span><br><span class="line">  <span class="keyword">let</span> callbackName = options.<span class="property">callback</span> || options.<span class="property">data</span>[<span class="string">&#x27;callback&#x27;</span>] ||　(<span class="string">&#x27;jsonp_&#x27;</span> + <span class="title class_">Math</span>.<span class="title function_">random</span>()).<span class="title function_">replace</span>(<span class="string">&#x27;.&#x27;</span>, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> oHead = <span class="variable language_">document</span>.<span class="title function_">getElementsByTagName</span>(<span class="string">&#x27;head&#x27;</span>)[<span class="number">0</span>]</span><br><span class="line">  options.<span class="property">data</span>[<span class="string">&#x27;callback&#x27;</span>] = callbackName</span><br><span class="line">  <span class="keyword">let</span> params = <span class="title function_">formatParams</span>(options.<span class="property">data</span>)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> oScript = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;script&#x27;</span>)</span><br><span class="line">  oHead.<span class="title function_">appendChild</span>(oScript);</span><br><span class="line">  <span class="comment">// 创建jsonp回调函数</span></span><br><span class="line">  <span class="variable language_">window</span>[callbackName] = <span class="keyword">function</span> (<span class="params">json</span>) &#123;</span><br><span class="line">    oHead.<span class="title function_">removeChild</span>(oScript)</span><br><span class="line">    <span class="built_in">clearTimeout</span>(oScript.<span class="property">timer</span>)</span><br><span class="line">    <span class="variable language_">window</span>[callbackName] = <span class="literal">null</span></span><br><span class="line">    <span class="keyword">if</span> (json) &#123;</span><br><span class="line">      options.<span class="property">success</span> &amp;&amp; options.<span class="title function_">success</span>(json)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      options.<span class="property">fail</span> &amp;&amp; options.<span class="title function_">fail</span>(&#123; <span class="attr">code</span>: <span class="string">&#x27;FS_UNKNOW&#x27;</span>, <span class="attr">summary</span>: <span class="string">&#x27;请求错误&#x27;</span> &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 发送请求</span></span><br><span class="line">  oScript.<span class="property">src</span> = options.<span class="property">url</span> + (options.<span class="property">url</span>.<span class="title function_">indexOf</span>(<span class="string">&#x27;?&#x27;</span>) &gt; -<span class="number">1</span> ? <span class="string">&#x27;&amp;&#x27;</span> : <span class="string">&#x27;?&#x27;</span>) + params</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 超时处理</span></span><br><span class="line">  <span class="keyword">if</span> (options.<span class="property">time</span>) &#123;</span><br><span class="line">    oScript.<span class="property">timer</span> = <span class="built_in">setTimeout</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">window</span>[callbackName] = <span class="literal">null</span></span><br><span class="line">      oHead.<span class="title function_">removeChild</span>(oScript)</span><br><span class="line">      options.<span class="property">fail</span> &amp;&amp; options.<span class="title function_">fail</span>(&#123; <span class="attr">code</span>: <span class="string">&#x27;S_FAIL&#x27;</span>, <span class="attr">summary</span>: <span class="string">&#x27;请求超时&#x27;</span> &#125;)</span><br><span class="line">    &#125;, options.<span class="property">time</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1><span id="平民版深度拷贝">平民版深度拷贝</span></h1><blockquote><p>比乞丐版 <code>JSON.parse(JSON.stringify(obj))</code> 好点的深度拷贝</p></blockquote><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 深拷贝</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">*</span>&#125; <span class="variable">target</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">deepClone</span> = target =&gt; &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> newTarget = <span class="title class_">Array</span>.<span class="title function_">isArray</span>(target) ? [] : &#123;&#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">const</span> i <span class="keyword">in</span> target) &#123;</span><br><span class="line">      <span class="keyword">if</span> (<span class="keyword">typeof</span> target[i] === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">        newTarget[i] = <span class="title function_">deepClone</span>(target[i])</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        newTarget[i] = target[i]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> newTarget</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> target</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1><span id="instanceof-实现">instanceof 实现</span></h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">new_instance_of</span>(<span class="params">leftVaule, rightVaule</span>) &#123; </span><br><span class="line">    <span class="keyword">let</span> rightProto = rightVaule.<span class="property"><span class="keyword">prototype</span></span>; <span class="comment">// 取右表达式的 prototype 值</span></span><br><span class="line">    leftVaule = leftVaule.<span class="property">__proto__</span>; <span class="comment">// 取左表达式的__proto__值</span></span><br><span class="line">    <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (leftVaule === <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;  </span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (leftVaule === rightProto) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;  </span><br><span class="line">        &#125; </span><br><span class="line">        leftVaule = leftVaule.<span class="property">__proto__</span> </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1><span id="new-封装">new 封装</span></h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">myNew</span>(<span class="params">Con, ...args</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> obj = <span class="title class_">Object</span>.<span class="title function_">create</span>(<span class="title class_">Con</span>.<span class="property"><span class="keyword">prototype</span></span>)</span><br><span class="line">  <span class="keyword">let</span> result = <span class="title class_">Con</span>.<span class="title function_">apply</span>(obj, args)</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">typeof</span> obj === <span class="string">&#x27;object&#x27;</span> ? result : obj</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1><span id="手写-promise-乞丐版">手写 Promise （乞丐版）</span></h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">MyPromise</span> (<span class="params">executor</span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">value</span> = <span class="literal">undefined</span></span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">reason</span> = <span class="literal">undefined</span></span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">status</span> = <span class="string">&#x27;pending&#x27;</span> <span class="comment">// 状态 pending、resolved、rejected，默认为 pending</span></span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">resolvedCallbacks</span> = []</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">rejectedCallbacks</span> = []</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">resolve</span> (<span class="params">value</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">pending</span> === <span class="string">&#x27;pending&#x27;</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">value</span> = value</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">status</span> = <span class="string">&#x27;resolved&#x27;</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">resolvedCallbacks</span>.<span class="title function_">forEach</span>(<span class="function"><span class="params">fn</span> =&gt;</span> <span class="title function_">fn</span>())</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">reject</span> (<span class="params">reason</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">pending</span> === <span class="string">&#x27;pending&#x27;</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">reason</span> = reason</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">status</span> = <span class="string">&#x27;rejected&#x27;</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">rejectedCallbacks</span>.<span class="title function_">forEach</span>(<span class="function"><span class="params">fn</span> =&gt;</span> <span class="title function_">fn</span>())</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">executor</span>(resolve, reject)</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">MyPromise</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">then</span> = <span class="keyword">function</span> (<span class="params">fn</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">status</span> === <span class="string">&#x27;resolved&#x27;</span>) &#123;</span><br><span class="line">    <span class="title function_">fn</span>(<span class="variable language_">this</span>.<span class="property">value</span>)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">status</span> === <span class="string">&#x27;pending&#x27;</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">resolvedCallbacks</span>.<span class="title function_">push</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="title function_">fn</span>(<span class="variable language_">this</span>.<span class="property">value</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">MyPromise</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">catch</span> = <span class="keyword">function</span> (<span class="params">fn</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">status</span> === <span class="string">&#x27;rejected&#x27;</span>) &#123;</span><br><span class="line">    <span class="title function_">fn</span>(<span class="variable language_">this</span>.<span class="property">reason</span>)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">status</span> === <span class="string">&#x27;pending&#x27;</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">rejectedCallbacks</span>.<span class="title function_">push</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="title function_">fn</span>(<span class="variable language_">this</span>.<span class="property">reason</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1><span id="flex">flex</span></h1><ul><li>flex-grow属性</li></ul><p>flex-grow属性定义项目的放大比例，默认为0，即如果存在剩余空间，也不放大。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.item</span> &#123;</span><br><span class="line">  <span class="attribute">flex-grow</span>: &lt;number&gt;; <span class="comment">/* default 0 */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果所有项目的flex-grow属性都为1，则它们将等分剩余空间（如果有的话）。如果一个项目的flex-grow属性为2，其他项目都为1，则前者占据的剩余空间将比其他项多一倍。</p><ul><li>flex-shrink属性</li></ul><p>flex-shrink属性定义了项目的缩小比例，默认为1，即如果空间不足，该项目将缩小。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.item</span> &#123;</span><br><span class="line">  <span class="attribute">flex-shrink</span>: &lt;number&gt;; <span class="comment">/* default 1 */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果所有项目的flex-shrink属性都为1，当空间不足时，都将等比例缩小。如果一个项目的flex-shrink属性为0，其他项目都为1，则空间不足时，前者不缩小。<br>负值对该属性无效。</p><ul><li>flex-basis属性</li></ul><p>flex-basis属性定义了在分配多余空间之前，项目占据的主轴空间（main size）。浏览器根据这个属性，计算主轴是否有多余空间。它的默认值为auto，即项目的本来大小。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.item</span> &#123;</span><br><span class="line">  <span class="attribute">flex-basis</span>: &lt;length&gt; | auto; <span class="comment">/* default auto */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>它可以设为跟width或height属性一样的值（比如350px），则项目将占据固定空间。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;div class=&quot;toc&quot;&gt;

&lt;!-- toc --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#keep-alive-vs-http2&quot;&gt;keep-alive vs http2&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#http-pipelining&quot;&gt;http pip</summary>
      
    
    
    
    <category term="Web技术" scheme="https://jelon.link/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="前端" scheme="https://jelon.link/tags/%E5%89%8D%E7%AB%AF/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】141. 环形链表</title>
    <link href="https://jelon.link/posts/leetcode-141/"/>
    <id>https://jelon.link/posts/leetcode-141/</id>
    <published>2020-05-07T00:00:00.000Z</published>
    <updated>2020-05-07T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>给定一个链表，判断链表中是否有环。</p><p>为了表示给定链表中的环，我们使用整数 <code>pos</code> 来表示链表尾连接到链表中的位置（索引从 0 开始）。 如果 <code>pos</code> 是 <code>-1</code>，则在该链表中没有环。</p><p><strong>示例 1：</strong></p><p><img src="https://jangdelong.github.io/blog_img/images/leetcode-141/circularlinkedlist.png" alt="https:&#x2F;&#x2F;jangdelong.github.io&#x2F;blog_img&#x2F;images&#x2F;leetcode-141&#x2F;circularlinkedlist.png"></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入：<span class="built_in">head</span> = [3,2,0,-4], pos = 1</span><br><span class="line">输出：<span class="literal">true</span></span><br><span class="line">解释：链表中有一个环，其尾部连接到第二个节点。</span><br></pre></td></tr></table></figure><p><strong>示例 2：</strong></p><p><img src="https://jangdelong.github.io/blog_img/images/leetcode-141/circularlinkedlist_test2.png" alt="https:&#x2F;&#x2F;jangdelong.github.io&#x2F;blog_img&#x2F;images&#x2F;leetcode-141&#x2F;circularlinkedlist_test2.png"></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入：<span class="built_in">head</span> = [1,2], pos = 0</span><br><span class="line">输出：<span class="literal">true</span></span><br><span class="line">解释：链表中有一个环，其尾部连接到第一个节点。</span><br></pre></td></tr></table></figure><p><strong>示例 3：</strong></p><p><img src="https://jangdelong.github.io/blog_img/images/leetcode-141/circularlinkedlist_test3.png" alt="https:&#x2F;&#x2F;jangdelong.github.io&#x2F;blog_img&#x2F;images&#x2F;leetcode-141&#x2F;circularlinkedlist_test2.png"></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入：<span class="built_in">head</span> = [1], pos = -1</span><br><span class="line">输出：<span class="literal">false</span></span><br><span class="line">解释：链表中没有环。</span><br></pre></td></tr></table></figure><p> </p><p><strong>进阶：</strong></p><p>你能用 O(1)（即，常量）内存解决此问题吗？</p><h5><span id="个人解答">个人解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) &#123;</span></span><br><span class="line"><span class="comment"> *     this.val = val;</span></span><br><span class="line"><span class="comment"> *     this.next = null;</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">ListNode</span>&#125; <span class="variable">head</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">boolean</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> hasCycle = <span class="keyword">function</span>(<span class="params">head</span>) &#123;</span><br><span class="line">  <span class="comment">// 快慢指针</span></span><br><span class="line">  <span class="keyword">let</span> slow = head;</span><br><span class="line">  <span class="keyword">let</span> fast = head;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (slow &amp;&amp; fast &amp;&amp; fast.<span class="property">next</span>) &#123;</span><br><span class="line">    slow = slow.<span class="property">next</span>;</span><br><span class="line">    fast = fast.<span class="property">next</span>.<span class="property">next</span>;</span><br><span class="line">    <span class="keyword">if</span> (slow === fast) <span class="keyword">return</span> <span class="literal">true</span>; </span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5><span id="解题思路">解题思路</span></h5><p>通过使用具有 不同速度 的快、慢两个指针遍历链表，空间复杂度可以被降低至 O(1)。慢指针每次移动一步，而快指针每次移动两步。</p><p>如果列表中不存在环，最终快指针将会最先到达尾部，此时我们可以返回 false。</p><p>现在考虑一个环形链表，把慢指针和快指针想象成两个在环形赛道上跑步的运动员（分别称之为慢跑者与快跑者）。而快跑者最终一定会追上慢跑者。这是为什么呢？考虑下面这种情况（记作情况 A）- 假如快跑者只落后慢跑者一步，在下一次迭代中，它们就会分别跑了一步或两步并相遇。</p><ul><li>时间复杂度：O(n)；</li><li>空间复杂度：O(1)。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;给定一个链表，判断链表中是否有环。&lt;/p&gt;
&lt;p&gt;为了表示给定链表中的环，我们使用整数 &lt;code&gt;pos&lt;/code&gt; 来表示链表尾连接到链表中的位置（索引从 0 开始）。 如果 &lt;code&gt;pos&lt;/code&gt; 是 &lt;code&gt;-1&lt;/code&gt;，则在该链表中没有环。&lt;</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】面试题 02.03. 删除中间节点</title>
    <link href="https://jelon.link/posts/leetcode-case-02-03/"/>
    <id>https://jelon.link/posts/leetcode-case-02-03/</id>
    <published>2020-05-06T00:00:00.000Z</published>
    <updated>2020-05-06T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>实现一种算法，删除单向链表中间的某个节点（除了第一个和最后一个节点，不一定是中间节点），假定你只能访问该节点。</p><p> </p><p><strong>示例：</strong></p><figure class="highlight xl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入：单向链表<span class="function"><span class="title">a</span>-&gt;</span><span class="function"><span class="title">b</span>-&gt;</span><span class="function"><span class="title">c</span>-&gt;</span><span class="function"><span class="title">d</span>-&gt;</span><span class="function"><span class="title">e</span>-&gt;</span>f中的节点c</span><br><span class="line">结果：不返回任何数据，但该链表变为<span class="function"><span class="title">a</span>-&gt;</span><span class="function"><span class="title">b</span>-&gt;</span><span class="function"><span class="title">d</span>-&gt;</span><span class="function"><span class="title">e</span>-&gt;</span>f</span><br></pre></td></tr></table></figure><h5><span id="个人解答">个人解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) &#123;</span></span><br><span class="line"><span class="comment"> *     this.val = val;</span></span><br><span class="line"><span class="comment"> *     this.next = null;</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">ListNode</span>&#125; <span class="variable">node</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">void</span>&#125; Do not return anything, modify node in-place instead.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> deleteNode = <span class="keyword">function</span>(<span class="params">node</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> current = node;</span><br><span class="line">  node.<span class="property">val</span> = current.<span class="property">next</span>.<span class="property">val</span>;</span><br><span class="line">  node.<span class="property">next</span> = current.<span class="property">next</span>.<span class="property">next</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5><span id="解题思路">解题思路</span></h5><p>删除当前节点只需要把当前节点指向下个节点值即可。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;实现一种算法，删除单向链表中间的某个节点（除了第一个和最后一个节点，不一定是中间节点），假定你只能访问该节点。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例：&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight xl&quot;&gt;&lt;table&gt;&lt;tr&gt;</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>【每日一题】22. 括号生成</title>
    <link href="https://jelon.link/posts/leetcode-22/"/>
    <id>https://jelon.link/posts/leetcode-22/</id>
    <published>2020-04-09T00:00:00.000Z</published>
    <updated>2020-04-09T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>数字 n 代表生成括号的对数，请你设计一个函数，用于能够生成所有可能的并且 有效的 括号组合。</p><p> </p><p><strong>示例：</strong></p><figure class="highlight excel"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">输入：<span class="built_in">n</span> = <span class="number">3</span></span><br><span class="line">输出：[</span><br><span class="line">       <span class="string">&quot;((()))&quot;</span>,</span><br><span class="line">       <span class="string">&quot;(()())&quot;</span>,</span><br><span class="line">       <span class="string">&quot;(())()&quot;</span>,</span><br><span class="line">       <span class="string">&quot;()(())&quot;</span>,</span><br><span class="line">       <span class="string">&quot;()()()&quot;</span></span><br><span class="line">     ]</span><br></pre></td></tr></table></figure><h5><span id="参考解答">参考解答</span></h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">number</span>&#125; <span class="variable">n</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">string[]</span>&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> generateParenthesis = <span class="keyword">function</span>(<span class="params">n</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> res = []</span><br><span class="line">  <span class="title function_">dfs</span>(<span class="string">&#x27;&#x27;</span>, n, n, res)</span><br><span class="line">  <span class="keyword">return</span> res</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 深度遍历（回溯）</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">dfs</span> (<span class="params">curStr, left, right, res</span>) &#123;</span><br><span class="line">  <span class="comment">// 当左括号、右括号剩余数均为0时终止递归</span></span><br><span class="line">  <span class="keyword">if</span> (left === <span class="number">0</span> &amp;&amp; right === <span class="number">0</span>) &#123;</span><br><span class="line">    res.<span class="title function_">push</span>(curStr)</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 当左括号剩余数大于右括号剩余数</span></span><br><span class="line">  <span class="comment">// 即，已使用的左括号数少于已使用的右括号数</span></span><br><span class="line">  <span class="comment">// 终止递归</span></span><br><span class="line">  <span class="keyword">if</span> (left &gt; right) &#123;</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (left &gt; <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="title function_">dfs</span>(curStr + <span class="string">&#x27;(&#x27;</span>, left - <span class="number">1</span>, right, res)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (right &gt; <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="title function_">dfs</span>(curStr + <span class="string">&#x27;)&#x27;</span>, left, right - <span class="number">1</span>, res)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5><span id="解题思路">解题思路</span></h5><p>深度优先（回溯）：</p><ol><li><p>当前左右括号都有大于 0 个可以使用的时候，才产生分支；</p></li><li><p>产生左分支的时候，只看当前是否还有左括号可以使用；</p></li><li><p>产生右分支的时候，还受到左分支的限制，右边剩余可以使用的括号数量一定得在严格大于左边剩余的数量的时候，才可以产生分支；</p></li><li><p>在左边和右边剩余的括号数都等于 0 的时候结算。</p></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;数字 n 代表生成括号的对数，请你设计一个函数，用于能够生成所有可能的并且 有效的 括号组合。&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例：&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight excel&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td c</summary>
      
    
    
    
    <category term="算法练习" scheme="https://jelon.link/categories/%E7%AE%97%E6%B3%95%E7%BB%83%E4%B9%A0/"/>
    
    
    <category term="LeetCode" scheme="https://jelon.link/tags/LeetCode/"/>
    
    <category term="算法" scheme="https://jelon.link/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
</feed>
