<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Gblog</title>
  
  <subtitle>Mangon&#39;s Technology Blog</subtitle>
  <link href="https://mangon.cn/blog/atom.xml" rel="self"/>
  
  <link href="https://mangon.cn/blog/"/>
  <updated>2026-01-22T02:59:11.580Z</updated>
  <id>https://mangon.cn/blog/</id>
  
  <author>
    <name>Mangon</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>React19.2版本新增功能</title>
    <link href="https://mangon.cn/blog/2025/11/01/React-React19-2%E7%89%88%E6%9C%AC%E6%96%B0%E5%A2%9E%E5%8A%9F%E8%83%BD/"/>
    <id>https://mangon.cn/blog/2025/11/01/React-React19-2%E7%89%88%E6%9C%AC%E6%96%B0%E5%A2%9E%E5%8A%9F%E8%83%BD/</id>
    <published>2025-11-01T10:00:00.000Z</published>
    <updated>2026-01-22T02:59:11.580Z</updated>
    
    <content type="html"><![CDATA[<p>React 19.2 于2025年10月1日正式发布。该版本引入了多项新功能和显著改进，为开发者带来了更强大的工具和更好的性能优化能力。</p><span id="more"></span><h2 id="新增-React-特性"><a href="#新增-React-特性" class="headerlink" title="新增 React 特性"></a>新增 React 特性</h2><h3 id="lt-Activity-gt-组件"><a href="#lt-Activity-gt-组件" class="headerlink" title="&lt;Activity /&gt;组件"></a><code>&lt;Activity /&gt;</code>组件</h3><p><code>&lt;Activity /&gt;</code>允许你将应用程序分解为可以控制和优先处理的”活动”部分。这个组件可以作为条件渲染页面部分的替代方案：</p><figure class="highlight jsx"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 之前</span></span><br><span class="line">&#123;</span><br><span class="line">  isVisible &amp;&amp; <span class="language-xml"><span class="tag">&lt;<span class="name">Page</span> /&gt;</span></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">&lt;<span class="title class_">Activity</span> mode=&#123;isVisible ? <span class="string">&#x27;visible&#x27;</span> : <span class="string">&#x27;hidden&#x27;</span>&#125;&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">Page</span> /&gt;</span></span></span><br><span class="line">&lt;/<span class="title class_">Activity</span>&gt;;</span><br></pre></td></tr></table></figure><p>在React 19.2中，<code>&lt;Activity /&gt;</code> 支持两种模式：visible（可见）和 hidden（隐藏）：</p><ul><li>hidden: 隐藏子元素，卸载效果，并推迟所有更新，直到 React 没有其他工作要处理。</li><li>visible: 显示子元素，挂载效果，并允许正常处理更新。</li></ul><p>这意味着你可以预渲染并继续渲染应用程序中隐藏的部分，而不会影响屏幕上可见内容的性能。你可以使用 <code>&lt;Activity /&gt;</code> 渲染用户可能接下来会导航到的隐藏部分，或保存用户导航离开时部分的状态。这通过在后台加载数据、CSS和图像来帮助加快导航速度，并允许返回导航保持状态，如输入字段。</p><h3 id="useEffectEvent"><a href="#useEffectEvent" class="headerlink" title="useEffectEvent"></a>useEffectEvent</h3><p>useEffectEvent 是解决 useEffect 中一个常见模式的工具，用于通知应用代码来自外部系统的某些”事件”。例如，当聊天室连接时，你可能想要显示通知。</p><p>传统方法的问题在于，内部”事件”使用的任何值的更改都会导致周围的 Effect 重新运行。例如，更改主题会导致聊天室重新连接。这对于与 Effect 逻辑本身相关的值（如 roomId）是有意义的，但对于 theme 则没有意义。</p><p>使用 useEffectEvent ，你可以将”事件”部分的逻辑从发出它的 Effect 中分离出来：</p><figure class="highlight jsx"><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">function</span> <span class="title function_">ChatRoom</span>(<span class="params">&#123; roomId, theme &#125;</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> onConnected = <span class="title function_">useEffectEvent</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="title function_">showNotification</span>(<span class="string">&#x27;Connected!&#x27;</span>, theme);</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="title function_">useEffect</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> connection = <span class="title function_">createConnection</span>(serverUrl, roomId);</span><br><span class="line">    connection.<span class="title function_">on</span>(<span class="string">&#x27;connected&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="title function_">onConnected</span>();</span><br><span class="line">    &#125;);</span><br><span class="line">    connection.<span class="title function_">connect</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="function">() =&gt;</span> connection.<span class="title function_">disconnect</span>();</span><br><span class="line">  &#125;, [roomId]); <span class="comment">// ✅ 所有依赖项已声明（Effect Events 不是依赖项）</span></span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>类似于DOM事件，Effect Events 始终”看到”最新的 props 和 state。</p><h3 id="cacheSignal"><a href="#cacheSignal" class="headerlink" title="cacheSignal"></a>cacheSignal</h3><p>cacheSignal 仅用于 React 服务器组件。它允许你知道 <code>cache()</code> 生命周期何时结束：</p><figure class="highlight jsx"><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="keyword">import</span> &#123; cache, cacheSignal &#125; <span class="keyword">from</span> <span class="string">&#x27;react&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> dedupedFetch = <span class="title function_">cache</span>(fetch);</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">Component</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">await</span> <span class="title function_">dedupedFetch</span>(url, &#123; <span class="attr">signal</span>: <span class="title function_">cacheSignal</span>() &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这允许你在缓存不再使用结果时清理或中止工作，例如：</p><ul><li>React 已成功完成渲染</li><li>渲染被中止</li><li>渲染失败</li></ul><h3 id="性能追踪（Performance-Tracks）"><a href="#性能追踪（Performance-Tracks）" class="headerlink" title="性能追踪（Performance Tracks）"></a>性能追踪（Performance Tracks）</h3><p>React 19.2 在 Chrome DevTools 性能配置文件中添加了一组新的自定义轨道，为你的 React 应用性能提供更多信息：</p><h4 id="调度器（Scheduler）轨道"><a href="#调度器（Scheduler）轨道" class="headerlink" title="调度器（Scheduler）轨道"></a>调度器（Scheduler）轨道</h4><p>显示 React 正在处理的不同优先级的工作，如针对用户交互的 “blocking” 或针对 startTransition 内更新的 “transition” 。在每个轨道内部，你将看到正在执行的工作类型，如调度更新的事件以及该更新渲染发生的时间。</p><h4 id="组件（Components）轨道"><a href="#组件（Components）轨道" class="headerlink" title="组件（Components）轨道"></a>组件（Components）轨道</h4><p>显示 React 正在处理以进行渲染或运行效果的组件树。在内部，你会看到诸如 “Mount” 标签表示子项挂载或效果被挂载，或 “Blocked” 表示由于让位于 React 之外的工作而阻塞渲染。</p><h2 id="新增-React-DOM-特性"><a href="#新增-React-DOM-特性" class="headerlink" title="新增 React DOM 特性"></a>新增 React DOM 特性</h2><h3 id="部分预渲染（Partial-Pre-rendering）"><a href="#部分预渲染（Partial-Pre-rendering）" class="headerlink" title="部分预渲染（Partial Pre-rendering）"></a>部分预渲染（Partial Pre-rendering）</h3><p>在 React 19.2 中，添加了一个新功能，允许提前预渲染应用程序的一部分，然后稍后恢复渲染。</p><p>这个功能被称为”部分预渲染”，允许你预渲染应用程序的静态部分并从 CDN 提供服务，然后稍后恢复渲染外壳以填充动态内容。</p><p>要预渲染稍后恢复的应用程序，首先使用 AbortController 调用 prerender：</p><figure class="highlight jsx"><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">const</span> &#123; prelude, postponed &#125; = <span class="keyword">await</span> <span class="title function_">prerender</span>(<span class="language-xml"><span class="tag">&lt;<span class="name">App</span> /&gt;</span></span>, &#123;</span><br><span class="line">  <span class="attr">signal</span>: controller.<span class="property">signal</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">await</span> <span class="title function_">savePostponedState</span>(postponed);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 发送前奏到客户端或CDN</span></span><br></pre></td></tr></table></figure><p>然后，你可以将前奏返回给客户端，随后调用 resume 以”恢复”到 SSR 流：</p><figure class="highlight jsx"><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">const</span> postponed = <span class="keyword">await</span> <span class="title function_">getPostponedState</span>(request);</span><br><span class="line"><span class="keyword">const</span> resumeStream = <span class="keyword">await</span> <span class="title function_">resume</span>(<span class="language-xml"><span class="tag">&lt;<span class="name">App</span> /&gt;</span></span>, postponed);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将流发送到客户端</span></span><br></pre></td></tr></table></figure><p>或者你可以调用 resumeAndPrerender 以恢复以获取静态 HTML 进行 SSG：</p><figure class="highlight jsx"><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">const</span> postponedState = <span class="keyword">await</span> <span class="title function_">getPostponedState</span>(request);</span><br><span class="line"><span class="keyword">const</span> &#123; prelude &#125; = <span class="keyword">await</span> <span class="title function_">resumeAndPrerender</span>(<span class="language-xml"><span class="tag">&lt;<span class="name">App</span> /&gt;</span></span>, postponedState);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将完整的HTML前奏发送到CDN</span></span><br></pre></td></tr></table></figure><h2 id="值得注意的变更"><a href="#值得注意的变更" class="headerlink" title="值得注意的变更"></a>值得注意的变更</h2><h3 id="服务端渲染中的-Suspense-边界批处理"><a href="#服务端渲染中的-Suspense-边界批处理" class="headerlink" title="服务端渲染中的 Suspense 边界批处理"></a>服务端渲染中的 Suspense 边界批处理</h3><p>修复了一个行为错误，即 Suspense 边界的显示会根据它们是在客户端还是服务器端流式渲染时而有所不同。</p><p>从 React 19.2 开始，React 将短暂地批处理服务器渲染的 Suspense 边界的显示，以允许更多内容一起显示，并与客户端渲染行为对齐。</p><h3 id="服务端渲染：Node-的-Web-Streams-支持"><a href="#服务端渲染：Node-的-Web-Streams-支持" class="headerlink" title="服务端渲染：Node 的 Web Streams 支持"></a>服务端渲染：Node 的 Web Streams 支持</h3><p>增加了对 Node 环境 Web Streams API 的支持，使得服务端渲染更加高效。</p><h3 id="eslint-plugin-react-hooks-v6"><a href="#eslint-plugin-react-hooks-v6" class="headerlink" title="eslint-plugin-react-hooks v6"></a>eslint-plugin-react-hooks v6</h3><p>更新了 React Hooks 的 ESLint 插件，以支持新的 useEffectEvent 语法，并确保不会将 Effect Events 误添加到依赖数组中。</p><h3 id="更新默认-useId-前缀"><a href="#更新默认-useId-前缀" class="headerlink" title="更新默认 useId 前缀"></a>更新默认 useId 前缀</h3><p>调整了 useId 生成 ID 的默认前缀，使其更符合现代 Web 开发需求。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>React 19.2 的发布标志着 React 生态系统持续发展的又一重要里程碑。新加入的 <code>&lt;Activity /&gt;</code> 组件为应用状态管理提供了更精细的控制方式；<code>useEffectEvent</code> 解决了 Effect 依赖管理的经典问题；部分预渲染功能进一步提升了应用性能和用户体验；而性能追踪工具则为开发者提供了更深入的性能分析能力。</p><p>这些改进不仅提高了 React 应用的性能和可维护性，也为未来 React 的发展奠定了基础。特别是 <code>&lt;Activity /&gt;</code> 组件的设计理念，预示着 React 在应用架构方面的新方向，未来可能会增加更多模式以满足不同场景的需求。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;React 19.2 于2025年10月1日正式发布。该版本引入了多项新功能和显著改进，为开发者带来了更强大的工具和更好的性能优化能力。&lt;/p&gt;</summary>
    
    
    
    <category term="javascript" scheme="https://mangon.cn/blog/categories/javascript/"/>
    
    
    <category term="react" scheme="https://mangon.cn/blog/tags/react/"/>
    
  </entry>
  
  <entry>
    <title>模块联邦 Module Federation</title>
    <link href="https://mangon.cn/blog/2025/07/24/FE-%E6%A8%A1%E5%9D%97%E8%81%94%E9%82%A6Module-Federation/"/>
    <id>https://mangon.cn/blog/2025/07/24/FE-%E6%A8%A1%E5%9D%97%E8%81%94%E9%82%A6Module-Federation/</id>
    <published>2025-07-24T08:09:59.000Z</published>
    <updated>2025-07-24T08:30:34.710Z</updated>
    
    <content type="html"><![CDATA[<p>模块联邦（Module Federation）是 Webpack 5 引入的核心功能，旨在实现多个独立构建的前端应用在运行时动态共享代码、依赖或组件，支持微前端架构和跨项目模块复用。</p><h2 id="‌模块联邦的核心概念‌"><a href="#‌模块联邦的核心概念‌" class="headerlink" title="‌模块联邦的核心概念‌"></a>‌模块联邦的核心概念‌</h2><p>模块联邦通过去中心化的设计，允许不同应用在运行时直接共享模块，无需重复打包或依赖 NPM 安装。其核心特点包括：</p><ol><li><p>‌独立构建与部署‌：每个应用（容器或远程）可单独开发、部署，通过暴露（exposes）和引用（remotes）机制实现模块共享。‌‌‌‌</p></li><li><p>运行时动态加载‌：模块按需异步加载，减少初始包体积，提升性能。‌‌</p></li><li><p>‌依赖共享‌：通过 shared 配置（如React、ReactDOM）避免重复加载，确保单例模式。‌‌‌‌</p></li></ol><h2 id="‌典型应用场景‌"><a href="#‌典型应用场景‌" class="headerlink" title="‌典型应用场景‌"></a>‌典型应用场景‌</h2><ol><li><p>‌微前端架构‌：将多个子应用集成到宿主容器中，实现技术栈解耦和独立部署。‌‌</p></li><li><p>‌跨项目组件复用‌：通用组件（如按钮、表单）可被多个项目动态引用，减少重复开发。‌‌</p></li><li><p>依赖优化‌：共享第三方库（如 Lodash ）以降低整体打包体积。‌‌</p></li></ol><h2 id="实现步骤与配置"><a href="#实现步骤与配置" class="headerlink" title="实现步骤与配置"></a>实现步骤与配置</h2><ol><li>使用 <code>ModuleFederationPlugin</code> 声明远程模块入口（<code>remotes</code>）和共享依赖（<code>shared</code>）。‌‌</li></ol><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="keyword">const</span> &#123; <span class="title class_">ModuleFederationPlugin</span> &#125; = <span class="built_in">require</span>(<span class="string">&#x27;webpack&#x27;</span>).<span class="property">container</span>;</span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123;</span><br><span class="line">  <span class="attr">plugins</span>: [</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">ModuleFederationPlugin</span>(&#123;</span><br><span class="line">      <span class="attr">name</span>: <span class="string">&#x27;container&#x27;</span>,</span><br><span class="line">      <span class="attr">remotes</span>: &#123; <span class="attr">app1</span>: <span class="string">&#x27;app1@http://example.com/remoteEntry.js&#x27;</span> &#125;,</span><br><span class="line">      <span class="attr">shared</span>: &#123; <span class="attr">react</span>: &#123; <span class="attr">singleton</span>: <span class="literal">true</span> &#125; &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  ]</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><ol start="2"><li>远程应用配置通过 exposes 暴露模块，并配置共享依赖</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">ModuleFederationPlugin</span>(&#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;app1&#x27;</span>,</span><br><span class="line">  <span class="attr">filename</span>: <span class="string">&#x27;remoteEntry.js&#x27;</span>,</span><br><span class="line">  <span class="attr">exposes</span>: &#123; <span class="string">&#x27;./Button&#x27;</span>: <span class="string">&#x27;./src/Button&#x27;</span> &#125;,</span><br><span class="line">  <span class="attr">shared</span>: &#123; <span class="attr">react</span>: &#123; <span class="attr">singleton</span>: <span class="literal">true</span> &#125; &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;模块联邦（Module Federation）是 Webpack 5 引入的核心功能，旨在实现多个独立构建的前端应用在运行时动态共享代码、依赖或组件，支持微前端架构和跨项目模块复用。&lt;/p&gt;
&lt;h2 id=&quot;‌模块联邦的核心概念‌&quot;&gt;&lt;a href=&quot;#‌模块联邦的核心概念</summary>
      
    
    
    
    
    <category term="webpack" scheme="https://mangon.cn/blog/tags/webpack/"/>
    
  </entry>
  
  <entry>
    <title>FE-ECMAScript2025新特性</title>
    <link href="https://mangon.cn/blog/2025/07/01/FE-ECMAScript2025%E6%96%B0%E7%89%B9%E6%80%A7/"/>
    <id>https://mangon.cn/blog/2025/07/01/FE-ECMAScript2025%E6%96%B0%E7%89%B9%E6%80%A7/</id>
    <published>2025-07-01T10:00:00.000Z</published>
    <updated>2026-01-22T02:59:11.474Z</updated>
    
    <content type="html"><![CDATA[<p>ECMAScript 2025（ES2025）于2025年6月正式发布，带来了一系列实用的新特性和改进。以下列举一些主要的特性：</p><span id="more"></span><h2 id="导入属性（Import-Attributes）"><a href="#导入属性（Import-Attributes）" class="headerlink" title="导入属性（Import Attributes）"></a>导入属性（Import Attributes）</h2><p>解决的问题：<br>之前无法直接将 JSON 文件作为模块导入，需要借助 Node.js 的 require 或其他工具函数。这使得在不同环境中处理 JSON 数据缺乏统一的标准方式。<br>现在提供了一种标准化的方式在导入模块时指定附加信息，如类型断言，确保导入的内容符合预期格式。<br>例如可以使用 <code>import</code> 语句导入 JSON 文件，并使用 <code>with</code> 关键字指定模块类型为 json。</p><p>代码示例：</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><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用 import attributes 特性导入JSON</span></span><br><span class="line"><span class="keyword">import</span> config <span class="keyword">from</span> <span class="string">&#x27;./config.json&#x27;</span> <span class="keyword">with</span> &#123; <span class="attr">type</span>: <span class="string">&#x27;json&#x27;</span> &#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> dynamicModule = <span class="keyword">await</span> <span class="keyword">import</span>(<span class="string">&#x27;./data.json&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">with</span>: &#123; <span class="attr">type</span>: <span class="string">&#x27;json&#x27;</span> &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(config.<span class="property">environment</span>); <span class="comment">// 访问JSON内容</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(dynamicModule.<span class="property">default</span>); <span class="comment">// 访问动态导入的JSON内容</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 未来可能支持其他类型的模块</span></span><br><span class="line"><span class="comment">// import wasmModule from &#x27;./module.wasm&#x27; with &#123; type: &#x27;webassembly&#x27; &#125;;</span></span><br><span class="line"><span class="comment">// import cssModule from &#x27;./styles.css&#x27; with &#123; type: &#x27;css&#x27; &#125;;</span></span><br></pre></td></tr></table></figure><h2 id="迭代器辅助方法（Iterator-Helpers）"><a href="#迭代器辅助方法（Iterator-Helpers）" class="headerlink" title="迭代器辅助方法（Iterator Helpers）"></a>迭代器辅助方法（Iterator Helpers）</h2><p>解决的问题：<br>传统上，在处理迭代器时，如果想使用 map、filter 等方法，必须先转换为数组，这会消耗大量内存。<br>现在迭代器辅助方法提供了链式操作的能力，同时保持惰性求值的优势。</p><p>代码示例：</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 旧方式 - 需要转换为数组，占用内存</span></span><br><span class="line"><span class="keyword">const</span> result1 = <span class="title class_">Array</span>.<span class="title function_">from</span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>])</span><br><span class="line">  .<span class="title function_">filter</span>(<span class="function"><span class="params">x</span> =&gt;</span> x % <span class="number">2</span> === <span class="number">0</span>)</span><br><span class="line">  .<span class="title function_">map</span>(<span class="function"><span class="params">x</span> =&gt;</span> x * <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 新方式 - 直接在迭代器上操作，内存友好</span></span><br><span class="line"><span class="keyword">const</span> result2 = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line">  .<span class="title function_">values</span>()</span><br><span class="line">  .<span class="title function_">filter</span>(<span class="function"><span class="params">x</span> =&gt;</span> x % <span class="number">2</span> === <span class="number">0</span>)</span><br><span class="line">  .<span class="title function_">map</span>(<span class="function"><span class="params">x</span> =&gt;</span> x * <span class="number">2</span>)</span><br><span class="line">  .<span class="title function_">toArray</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用其他迭代器方法</span></span><br><span class="line"><span class="keyword">const</span> filtered = [<span class="number">1</span>, <span class="string">&#x27;&#x27;</span>, <span class="number">2</span>, <span class="literal">null</span>, <span class="number">3</span>, <span class="literal">undefined</span>, <span class="number">4</span>]</span><br><span class="line">  .<span class="title function_">values</span>()</span><br><span class="line">  .<span class="title function_">filter</span>(<span class="title class_">Boolean</span>) <span class="comment">// 过滤假值</span></span><br><span class="line">  .<span class="title function_">map</span>(<span class="function"><span class="params">x</span> =&gt;</span> x * <span class="number">2</span>)</span><br><span class="line">  .<span class="title function_">take</span>(<span class="number">3</span>) <span class="comment">// 只取前3个元素</span></span><br><span class="line">  .<span class="title function_">toArray</span>();</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(filtered); <span class="comment">// [2, 6, 8]</span></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_">fibonacci</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> a = <span class="number">0</span>,</span><br><span class="line">    b = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">yield</span> a;</span><br><span class="line">  <span class="keyword">yield</span> b;</span><br><span class="line">  <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">    [a, b] = [b, a + b];</span><br><span class="line">    <span class="keyword">yield</span> b;</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">const</span> fib10 = <span class="title function_">fibonacci</span>()</span><br><span class="line">  .<span class="title function_">drop</span>(<span class="number">5</span>) <span class="comment">// 跳过前5个</span></span><br><span class="line">  .<span class="title function_">take</span>(<span class="number">10</span>) <span class="comment">// 取接下来的10个</span></span><br><span class="line">  .<span class="title function_">toArray</span>();</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(fib10); <span class="comment">// [斐波那契数列中第5到15个数]</span></span><br></pre></td></tr></table></figure><h2 id="Set集合方法增强（New-Set-Methods）"><a href="#Set集合方法增强（New-Set-Methods）" class="headerlink" title="Set集合方法增强（New Set Methods）"></a>Set集合方法增强（New Set Methods）</h2><p>解决的问题：<br>之前的 Set 对象缺少集合运算方法，开发者需要自己实现并集、交集、差集等操作，代码冗长且容易出错。<br>新增了7个集合方法包括：并集 <code>union()</code>、交集 <code>intersection()</code>、差集 <code>difference()</code>、对称差集 <code>symmetricDifference()</code>、子集判断 <code>isSubsetOf()</code>、超集判断 <code>isSupersetOf()</code>、不相交判断<code>isDisjointFrom()</code>，基于哈希表实现，性能高效。</p><p>代码示例：</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> setA = <span class="keyword">new</span> <span class="title class_">Set</span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]);</span><br><span class="line"><span class="keyword">const</span> setB = <span class="keyword">new</span> <span class="title class_">Set</span>([<span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>]);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 并集</span></span><br><span class="line"><span class="keyword">const</span> union = setA.<span class="title function_">union</span>(setB);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>([...union]); <span class="comment">// [1, 2, 3, 4, 5, 6]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 交集</span></span><br><span class="line"><span class="keyword">const</span> intersection = setA.<span class="title function_">intersection</span>(setB);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>([...intersection]); <span class="comment">// [3, 4]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 差集</span></span><br><span class="line"><span class="keyword">const</span> difference = setA.<span class="title function_">difference</span>(setB);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>([...difference]); <span class="comment">// [1, 2]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 对称差集（异或）</span></span><br><span class="line"><span class="keyword">const</span> symmetricDiff = setA.<span class="title function_">symmetricDifference</span>(setB);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>([...symmetricDiff]); <span class="comment">// [1, 2, 5, 6]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 子集判断</span></span><br><span class="line"><span class="keyword">const</span> setC = <span class="keyword">new</span> <span class="title class_">Set</span>([<span class="number">1</span>, <span class="number">2</span>]);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(setC.<span class="title function_">isSubsetOf</span>(setA)); <span class="comment">// true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 超集判断</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(setA.<span class="title function_">isSupersetOf</span>(setC)); <span class="comment">// true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 不相交判断</span></span><br><span class="line"><span class="keyword">const</span> setD = <span class="keyword">new</span> <span class="title class_">Set</span>([<span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>]);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(setA.<span class="title function_">isDisjointFrom</span>(setD)); <span class="comment">// true (没有共同元素)</span></span><br></pre></td></tr></table></figure><h2 id="正则表达式增强"><a href="#正则表达式增强" class="headerlink" title="正则表达式增强"></a>正则表达式增强</h2><p>解决的问题：<br>包括三个方面的增强：<code>RegExp.escape()</code> 防止特殊字符被误解释，重复命名捕获组，以及内联修饰符，解决了复杂正则表达式的构建和维护问题。</p><p>代码示例：</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><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"><span class="comment">// 1. RegExp.escape() - 安全地将字符串转换为正则表达式片段</span></span><br><span class="line"><span class="keyword">const</span> userInput = <span class="string">&#x27;How much does it cost? $50.00!&#x27;</span>; <span class="comment">// 用户输入可能包含特殊字符</span></span><br><span class="line"><span class="keyword">const</span> escapedInput = <span class="title class_">RegExp</span>.<span class="built_in">escape</span>(userInput);</span><br><span class="line"><span class="keyword">const</span> regex1 = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">`.*<span class="subst">$&#123;escapedInput&#125;</span>.*`</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(regex1.<span class="title function_">test</span>(<span class="string">&#x27;Prefix How much does it cost? $50.00! Suffix&#x27;</span>)); <span class="comment">// true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2. 重复命名捕获组</span></span><br><span class="line"><span class="keyword">const</span> dateRegex = <span class="regexp">/(?&lt;year&gt;\d&#123;4&#125;)-(?&lt;month&gt;\d&#123;2&#125;)|(?&lt;month&gt;\d&#123;2&#125;)-(?&lt;day&gt;\d&#123;2&#125;)/</span>;</span><br><span class="line"><span class="keyword">const</span> dateStr = <span class="string">&#x27;2025-03-15&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> match = dateStr.<span class="title function_">match</span>(dateRegex);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(match.<span class="property">groups</span>.<span class="property">year</span>); <span class="comment">// 2025</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(match.<span class="property">groups</span>.<span class="property">month</span>); <span class="comment">// 03 (第一个匹配的月份)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 3. 内联修饰符 - 在模式内部设置标志</span></span><br><span class="line"><span class="keyword">const</span> caseInsensitiveHello = <span class="regexp">/^x(?i:hello)x$/</span>; <span class="comment">// 局部设置忽略大小写</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(caseInsensitiveHello.<span class="title function_">test</span>(<span class="string">&#x27;xHELLOx&#x27;</span>)); <span class="comment">// true</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(caseInsensitiveHello.<span class="title function_">test</span>(<span class="string">&#x27;xHeLLox&#x27;</span>)); <span class="comment">// true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 也可以嵌套使用</span></span><br><span class="line"><span class="keyword">const</span> mixedFlags = <span class="regexp">/start(?i:case(?-i:sensitive))end/</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(mixedFlags.<span class="title function_">test</span>(<span class="string">&#x27;startCASEsensitiveend&#x27;</span>)); <span class="comment">// false</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(mixedFlags.<span class="title function_">test</span>(<span class="string">&#x27;startcasesensitiveend&#x27;</span>)); <span class="comment">// true</span></span><br></pre></td></tr></table></figure><h2 id="Promise-try"><a href="#Promise-try" class="headerlink" title="Promise.try()"></a>Promise.try()</h2><p>解决的问题：<br>之前同步函数抛出的错误无法直接被 <code>Promise.catch</code> 捕获，开发者通常需要额外的 try/catch 包裹统一同步和异步错误处理。<br>现在可以使用 <code>Promise.try()</code> 当函数可能同步抛出错误或异步产生错误时，提供一致的错误处理方式。</p><p>代码示例：</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><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><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 一个可能同步抛出错误也可能返回 Promise 的函数</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">riskyOperation</span>(<span class="params">value</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (value &lt; <span class="number">0</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;Value cannot be negative&#x27;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (value &gt; <span class="number">100</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">resolve</span>(value * <span class="number">2</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> value * <span class="number">2</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">function</span> <span class="title function_">handleWithTryCatch</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">return</span> <span class="title class_">Promise</span>.<span class="title function_">resolve</span>(<span class="title function_">riskyOperation</span>(-<span class="number">5</span>));</span><br><span class="line">  &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">reject</span>(error);</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">// 新方式 - 统一使用Promise.try</span></span><br><span class="line"><span class="title class_">Promise</span>.<span class="title function_">try</span>(<span class="function">() =&gt;</span> <span class="title function_">riskyOperation</span>(-<span class="number">5</span>))</span><br><span class="line">  .<span class="title function_">then</span>(<span class="function"><span class="params">result</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Success:&#x27;</span>, result))</span><br><span class="line">  .<span class="title function_">catch</span>(<span class="function"><span class="params">error</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Error:&#x27;</span>, error.<span class="property">message</span>));</span><br><span class="line"></span><br><span class="line"><span class="title class_">Promise</span>.<span class="title function_">try</span>(<span class="function">() =&gt;</span> <span class="title function_">riskyOperation</span>(<span class="number">150</span>)) <span class="comment">// 返回Promise</span></span><br><span class="line">  .<span class="title function_">then</span>(<span class="function"><span class="params">result</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Async Success:&#x27;</span>, result))</span><br><span class="line">  .<span class="title function_">catch</span>(<span class="function"><span class="params">error</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Async Error:&#x27;</span>, error.<span class="property">message</span>));</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_">validateAndProcess</span>(<span class="params">userData</span>) &#123;</span><br><span class="line">  <span class="comment">// 可能同步验证失败</span></span><br><span class="line">  <span class="keyword">if</span> (!userData.<span class="property">email</span> || !userData.<span class="property">email</span>.<span class="title function_">includes</span>(<span class="string">&#x27;@&#x27;</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;Invalid email&#x27;</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> <span class="title function_">fetch</span>(<span class="string">&#x27;/api/process-user&#x27;</span>, &#123;</span><br><span class="line">    <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">    <span class="attr">body</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(userData)</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 class_">Promise</span>.<span class="title function_">try</span>(<span class="function">() =&gt;</span> <span class="title function_">validateAndProcess</span>(&#123; <span class="attr">email</span>: <span class="string">&#x27;invalid&#x27;</span> &#125;))</span><br><span class="line">  .<span class="title function_">then</span>(<span class="function"><span class="params">response</span> =&gt;</span> response.<span class="title function_">json</span>())</span><br><span class="line">  .<span class="title function_">then</span>(<span class="function"><span class="params">data</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(data))</span><br><span class="line">  .<span class="title function_">catch</span>(<span class="function"><span class="params">error</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;Validation or API error:&#x27;</span>, error.<span class="property">message</span>));</span><br></pre></td></tr></table></figure><h2 id="Float16支持（Float16Array-Math-f16round等）"><a href="#Float16支持（Float16Array-Math-f16round等）" class="headerlink" title="Float16支持（Float16Array, Math.f16round等）"></a>Float16支持（Float16Array, Math.f16round等）</h2><p>解决的问题：<br>在图形处理、机器学习等领域，16位浮点数（半精度）比32位浮点数节省一半内存，提高了GPU操作和大数据处理的效率。</p><p>代码示例：</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建Float16数组</span></span><br><span class="line"><span class="keyword">const</span> f16Array = <span class="keyword">new</span> <span class="title class_">Float16Array</span>([<span class="number">1.5</span>, <span class="number">2.7</span>, <span class="number">3.14</span>, <span class="number">4.0</span>, <span class="number">5.5</span>]);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(f16Array[<span class="number">2</span>]); <span class="comment">// 3.140625 (由于精度限制)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用DataView进行精确读写</span></span><br><span class="line"><span class="keyword">const</span> buffer = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(<span class="number">16</span>);</span><br><span class="line"><span class="keyword">const</span> dataView = <span class="keyword">new</span> <span class="title class_">DataView</span>(buffer);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 设置和获取Float16值</span></span><br><span class="line">dataView.<span class="title function_">setFloat16</span>(<span class="number">0</span>, <span class="number">3.14159</span>, <span class="literal">true</span>); <span class="comment">// 第三个参数表示是否小端序</span></span><br><span class="line"><span class="keyword">const</span> value = dataView.<span class="title function_">getFloat16</span>(<span class="number">0</span>, <span class="literal">true</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(value); <span class="comment">// 3.140625</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 数学运算中的Float16舍入</span></span><br><span class="line"><span class="keyword">const</span> preciseValue = <span class="number">3.141592653589793</span>;</span><br><span class="line"><span class="keyword">const</span> roundedF16 = <span class="title class_">Math</span>.<span class="title function_">f16round</span>(preciseValue);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(roundedF16); <span class="comment">// 3.140625</span></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_">processImageData</span>(<span class="params">imageData</span>) &#123;</span><br><span class="line">  <span class="comment">// 将RGB值存储在Float16中以节省内存</span></span><br><span class="line">  <span class="keyword">const</span> pixels = <span class="keyword">new</span> <span class="title class_">Float16Array</span>(imageData.<span class="property">length</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; imageData.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    pixels[i] = <span class="title class_">Math</span>.<span class="title function_">f16round</span>(imageData[i] / <span class="number">255</span>); <span class="comment">// 归一化到[0,1]</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> pixels;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;ECMAScript 2025（ES2025）于2025年6月正式发布，带来了一系列实用的新特性和改进。以下列举一些主要的特性：&lt;/p&gt;</summary>
    
    
    
    <category term="javascript" scheme="https://mangon.cn/blog/categories/javascript/"/>
    
    
    <category term="ECMAScript" scheme="https://mangon.cn/blog/tags/ECMAScript/"/>
    
  </entry>
  
  <entry>
    <title>Recoil小抄</title>
    <link href="https://mangon.cn/blog/2025/05/12/React-Recoil%E5%B0%8F%E6%8A%84/"/>
    <id>https://mangon.cn/blog/2025/05/12/React-Recoil%E5%B0%8F%E6%8A%84/</id>
    <published>2025-05-12T02:00:00.000Z</published>
    <updated>2025-05-12T06:13:45.919Z</updated>
    
    <content type="html"><![CDATA[<p>Recoil 是 React 的一个状态管理库，它提供了一种简洁的方式来管理 React 应用的状态。Recoil 的最新一个版本是 2023年3月1日发布的 0.7.7。 2025年1月1日，Recoil 已经被作者归档。</p><h2 id="Recoild-应用示例"><a href="#Recoild-应用示例" class="headerlink" title="Recoild 应用示例"></a>Recoild 应用示例</h2><figure class="highlight jsx"><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><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">&#x27;react&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">RecoilRoot</span>, atom, selector, useRecoilState, useRecoilValue &#125; <span class="keyword">from</span> <span class="string">&#x27;recoil&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将 RecoilRoot 设置为根组件</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">App</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">RecoilRoot</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">CharacterCounter</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">RecoilRoot</span>&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// atom 代表一个状态。atom 可在任意组件中进行读写。读取 atom 值的组件隐式订阅了该 atom，因此任何 atom 的更新都将致使使用对应 atom 的组件重新渲染</span></span><br><span class="line"><span class="keyword">const</span> textState = <span class="title function_">atom</span>(&#123;</span><br><span class="line">  <span class="attr">key</span>: <span class="string">&#x27;textState&#x27;</span>, <span class="comment">// 唯一 ID (相对于其它 atoms/selectors)</span></span><br><span class="line">  <span class="attr">default</span>: <span class="string">&#x27;&#x27;</span> <span class="comment">// 默认值 (也被称为初始值)</span></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_">CharacterCounter</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">TextInput</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">CharacterCount</span> <span class="attr">userID</span>=<span class="string">&#123;123&#125;</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在需要使用的组件中，引入 atom 并使用 useRecoilState()</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">TextInput</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> [text, setText] = <span class="title function_">useRecoilState</span>(textState);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">onChange</span> = event =&gt; &#123;</span><br><span class="line">    <span class="title function_">setText</span>(event.<span class="property">target</span>.<span class="property">value</span>);</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&#x27;text&#x27;</span> <span class="attr">value</span>=<span class="string">&#123;text&#125;</span> <span class="attr">onChange</span>=<span class="string">&#123;onChange&#125;</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">      Echo: &#123;text&#125;</span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// selector 代表一个派生状态，派生状态是状态的转换。你可以将派生状态视为将状态传递给以某种方式修改给定状态的纯函数的输出</span></span><br><span class="line"><span class="keyword">const</span> charCountState = <span class="title function_">selector</span>(&#123;</span><br><span class="line">  <span class="attr">key</span>: <span class="string">&#x27;charCountState&#x27;</span>, <span class="comment">// 唯一 ID (相对于其它 atoms/selectors)</span></span><br><span class="line">  <span class="attr">get</span>: <span class="function">(<span class="params">&#123; get &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> text = <span class="title function_">get</span>(textState);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> text.<span class="property">length</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="comment">// 如果希望基于参数进行查询，而不仅仅是基于派生状态。例如，需要根据组件的 props 来查询时可以使用 selectorFamily helper 来实现</span></span><br><span class="line"><span class="keyword">const</span> userNameQuery = <span class="title function_">selectorFamily</span>(&#123;</span><br><span class="line">  <span class="attr">key</span>: <span class="string">&#x27;UserName&#x27;</span>,</span><br><span class="line">  <span class="attr">get</span>: <span class="function"><span class="params">userID</span> =&gt;</span> <span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">myDBQuery</span>(&#123; userID &#125;);</span><br><span class="line">    <span class="keyword">if</span> (response.<span class="property">error</span>) &#123;</span><br><span class="line">      <span class="keyword">throw</span> response.<span class="property">error</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> response.<span class="property">name</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="comment">// 使用 useRecoilValue() 的 来读取 selector 的值</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">CharacterCount</span>(<span class="params">&#123; userID &#125;</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> count = <span class="title function_">useRecoilValue</span>(charCountState);</span><br><span class="line">  <span class="keyword">const</span> userName = <span class="title function_">useRecoilValue</span>(<span class="title function_">userNameQuery</span>(userID));</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">div</span>&gt;</span>Character Count: &#123;count&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;userName&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Recoil 是 React 的一个状态管理库，它提供了一种简洁的方式来管理 React 应用的状态。Recoil 的最新一个版本是 2023年3月1日发布的 0.7.7。 2025年1月1日，Recoil 已经被作者归档。&lt;/p&gt;
&lt;h2 id=&quot;Recoild-应用示例</summary>
      
    
    
    
    
    <category term="react" scheme="https://mangon.cn/blog/tags/react/"/>
    
    <category term="Recoil" scheme="https://mangon.cn/blog/tags/Recoil/"/>
    
  </entry>
  
  <entry>
    <title>Zustand小抄</title>
    <link href="https://mangon.cn/blog/2025/05/12/React-Zustand%E5%B0%8F%E6%8A%84/"/>
    <id>https://mangon.cn/blog/2025/05/12/React-Zustand%E5%B0%8F%E6%8A%84/</id>
    <published>2025-05-12T02:00:00.000Z</published>
    <updated>2026-01-21T03:29:15.221Z</updated>
    
    <content type="html"><![CDATA[<p>Zustand 是一个基于 Flux 原理实现的轻量级的状态管理库。截止到 2025年5月12日，Zustand 的最新版本是 5.0.4，Github 收藏数量为52.2k，npmjs周下载量为7m。</p><h2 id="Zustand-应用示例"><a href="#Zustand-应用示例" class="headerlink" title="Zustand 应用示例"></a>Zustand 应用示例</h2><figure class="highlight jsx"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; create &#125; <span class="keyword">from</span> <span class="string">&#x27;zustand&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用 create 创建一个 store, store 包含了状态和修改状态的方法</span></span><br><span class="line"><span class="keyword">const</span> useStore = <span class="title function_">create</span>(<span class="function"><span class="params">set</span> =&gt;</span> (&#123;</span><br><span class="line">  <span class="attr">count</span>: <span class="number">1</span>,</span><br><span class="line">  <span class="attr">inc</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function"><span class="params">state</span> =&gt;</span> (&#123; <span class="attr">count</span>: state.<span class="property">count</span> + <span class="number">1</span> &#125;))</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_">Counter</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="comment">// 通过 useStore 访问状态和更新方法</span></span><br><span class="line">  <span class="keyword">const</span> &#123; count, inc &#125; = <span class="title function_">useStore</span>();</span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">span</span>&gt;</span>&#123;count&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">&#123;inc&#125;</span>&gt;</span>one up<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="API"><a href="#API" class="headerlink" title="API"></a>API</h2><h3 id="create"><a href="#create" class="headerlink" title="create"></a>create</h3><p>create 函数用于创建一个 store。</p><p>create 接受一个函数，这个函数接收一个 set 函数和 get 函数，用于更新状态和获取状态。返回一个 useStore hook，在组件中可以通过 useStore hook 来访问状态和调用状态更新函数。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> useStore = <span class="title function_">create</span>(<span class="function">(<span class="params">set, get</span>) =&gt;</span> (&#123;</span><br><span class="line">  <span class="attr">count</span>: <span class="number">0</span>,</span><br><span class="line">  <span class="attr">increase</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function">() =&gt;</span> (&#123; <span class="attr">count</span>: <span class="title function_">get</span>().<span class="property">count</span> + <span class="number">1</span> &#125;)),</span><br><span class="line">  <span class="attr">decrease</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function">() =&gt;</span> (&#123; <span class="attr">count</span>: <span class="title function_">get</span>().<span class="property">count</span> - <span class="number">1</span> &#125;))</span><br><span class="line">&#125;));</span><br></pre></td></tr></table></figure><h3 id="subscribe"><a href="#subscribe" class="headerlink" title="subscribe"></a>subscribe</h3><p>subscribe 函数用于订阅 store 的变化。</p><p>subscribe 方法允许订阅状态的变化。当状态发生变化时，订阅的回调函数会被调用。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> useStore = <span class="title function_">create</span>(<span class="function"><span class="params">set</span> =&gt;</span> (&#123;</span><br><span class="line">  <span class="attr">count</span>: <span class="number">0</span>,</span><br><span class="line">  <span class="attr">increase</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function"><span class="params">state</span> =&gt;</span> (&#123; <span class="attr">count</span>: state.<span class="property">count</span> + <span class="number">1</span> &#125;))</span><br><span class="line">&#125;));</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> unsubscribe = useStore.<span class="title function_">subscribe</span>(</span><br><span class="line">  <span class="function"><span class="params">state</span> =&gt;</span> state.<span class="property">count</span>,</span><br><span class="line">  <span class="function"><span class="params">count</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Count changed to&#x27;</span>, count)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 取消订阅</span></span><br><span class="line"><span class="title function_">unsubscribe</span>();</span><br></pre></td></tr></table></figure><h3 id="destroy"><a href="#destroy" class="headerlink" title="destroy"></a>destroy</h3><p>destroy 函数用于销毁 store，清除所有订阅。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> useStore = <span class="title function_">create</span>(<span class="function"><span class="params">set</span> =&gt;</span> (&#123;</span><br><span class="line">  <span class="attr">count</span>: <span class="number">0</span>,</span><br><span class="line">  <span class="attr">increase</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function"><span class="params">state</span> =&gt;</span> (&#123; <span class="attr">count</span>: state.<span class="property">count</span> + <span class="number">1</span> &#125;))</span><br><span class="line">&#125;));</span><br><span class="line"></span><br><span class="line">useStore.<span class="title function_">destroy</span>();</span><br></pre></td></tr></table></figure><h3 id="setState"><a href="#setState" class="headerlink" title="setState"></a>setState</h3><p>setState 函数用于直接更新 store 的状态，而不是通过定义的状态更新函数来更新状态。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> useStore = <span class="title function_">create</span>(<span class="function"><span class="params">set</span> =&gt;</span> (&#123;</span><br><span class="line">  <span class="attr">count</span>: <span class="number">0</span></span><br><span class="line">&#125;));</span><br><span class="line"></span><br><span class="line">useStore.<span class="title function_">setState</span>(&#123; <span class="attr">count</span>: <span class="number">10</span> &#125;);</span><br></pre></td></tr></table></figure><h3 id="getState"><a href="#getState" class="headerlink" title="getState"></a>getState</h3><p>getState 函数用于直接获取 store 的状态。与 get 方法类似，但 getState 是在 store 上调用的。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> useStore = <span class="title function_">create</span>(<span class="function"><span class="params">set</span> =&gt;</span> (&#123;</span><br><span class="line">  <span class="attr">count</span>: <span class="number">0</span></span><br><span class="line">&#125;));</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> currentState = useStore.<span class="title function_">getState</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(currentState.<span class="property">count</span>);</span><br></pre></td></tr></table></figure><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li>状态更新函数可以是异步的</li></ol><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">const</span> useStore = <span class="title function_">create</span>(<span class="function"><span class="params">set</span> =&gt;</span> (&#123;</span><br><span class="line">  <span class="attr">data</span>: <span class="literal">null</span>,</span><br><span class="line">  <span class="attr">fetchData</span>: <span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">&#x27;https://api.example.com/data&#x27;</span>);</span><br><span class="line">    <span class="keyword">const</span> data = <span class="keyword">await</span> response.<span class="title function_">json</span>();</span><br><span class="line">    <span class="title function_">set</span>(&#123; data &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;));</span><br></pre></td></tr></table></figure><ol start="2"><li>zustand 支持使用中间件来扩展功能，常用的中间件包括：</li></ol><ul><li>devtools: 与 Redux DevTools 兼容的中间件，可以方便地调试状态变化</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> create <span class="keyword">from</span> <span class="string">&#x27;zustand&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; devtools &#125; <span class="keyword">from</span> <span class="string">&#x27;zustand/middleware&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> useStore = <span class="title function_">create</span>(</span><br><span class="line">  <span class="title function_">devtools</span>(<span class="function"><span class="params">set</span> =&gt;</span> (&#123;</span><br><span class="line">    <span class="attr">count</span>: <span class="number">0</span>,</span><br><span class="line">    <span class="attr">increase</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function"><span class="params">state</span> =&gt;</span> (&#123; <span class="attr">count</span>: state.<span class="property">count</span> + <span class="number">1</span> &#125;)),</span><br><span class="line">    <span class="attr">decrease</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function"><span class="params">state</span> =&gt;</span> (&#123; <span class="attr">count</span>: state.<span class="property">count</span> - <span class="number">1</span> &#125;))</span><br><span class="line">  &#125;))</span><br><span class="line">);</span><br></pre></td></tr></table></figure><ul><li>persist: 持久化中间件，可以使用中间件将状态持久化到 localStorage 或 sessionStorage</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> create <span class="keyword">from</span> <span class="string">&#x27;zustand&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; persist, createJSONStorage &#125; <span class="keyword">from</span> <span class="string">&#x27;zustand/middleware&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> useStore = <span class="title function_">create</span>(</span><br><span class="line">  <span class="title function_">persist</span>(</span><br><span class="line">    <span class="function"><span class="params">set</span> =&gt;</span> (&#123;</span><br><span class="line">      <span class="attr">count</span>: <span class="number">0</span>,</span><br><span class="line">      <span class="attr">increase</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function"><span class="params">state</span> =&gt;</span> (&#123; <span class="attr">count</span>: state.<span class="property">count</span> + <span class="number">1</span> &#125;)),</span><br><span class="line">      <span class="attr">decrease</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function"><span class="params">state</span> =&gt;</span> (&#123; <span class="attr">count</span>: state.<span class="property">count</span> - <span class="number">1</span> &#125;))</span><br><span class="line">    &#125;),</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">name</span>: <span class="string">&#x27;count-storage&#x27;</span>, <span class="comment">// 存储的键名</span></span><br><span class="line">      <span class="attr">storage</span>: <span class="title function_">createJSONStorage</span>(<span class="function">() =&gt;</span> <span class="variable language_">sessionStorage</span>) <span class="comment">// (可选) 默认使用 localStorage</span></span><br><span class="line">    &#125;</span><br><span class="line">  )</span><br><span class="line">);</span><br></pre></td></tr></table></figure><ul><li>redux: Redux 中间件，可以将状态管理库与 Redux 库结合使用</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; createStore, applyMiddleware &#125; <span class="keyword">from</span> <span class="string">&#x27;redux&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; createStore <span class="keyword">as</span> createZustandStore &#125; <span class="keyword">from</span> <span class="string">&#x27;zustand&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; redux &#125; <span class="keyword">from</span> <span class="string">&#x27;zustand/middleware&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> store = <span class="title function_">createZustandStore</span>(<span class="title function_">redux</span>(reducer, initialState, <span class="title function_">applyMiddleware</span>(logger)));</span><br></pre></td></tr></table></figure><ol start="3"><li><p>避免将所有状态放在一个大 store 中，建议将状态拆分成多个小的 store，根据不同的功能模块来管理各自的状态</p></li><li><p>为状态提供合理的默认值，避免因状态未初始化而引起的错误。</p></li><li><p>避免不必要的状态变化，以减少组件的重新渲染次数</p></li><li><p>使用 <code>useStore(state =&gt; state.count)</code> 精确订阅状态的某一部分变化，避免 <code>useStore.getState()</code> 订阅所有状态。</p></li></ol><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> useStore = <span class="title function_">create</span>(<span class="function"><span class="params">set</span> =&gt;</span> (&#123;</span><br><span class="line">  <span class="attr">count</span>: <span class="number">0</span>,</span><br><span class="line">  <span class="attr">increase</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function"><span class="params">state</span> =&gt;</span> (&#123; <span class="attr">count</span>: state.<span class="property">count</span> + <span class="number">1</span> &#125;)),</span><br><span class="line">  <span class="attr">decrease</span>: <span class="function">() =&gt;</span> <span class="title function_">set</span>(<span class="function"><span class="params">state</span> =&gt;</span> (&#123; <span class="attr">count</span>: state.<span class="property">count</span> - <span class="number">1</span> &#125;))</span><br><span class="line">&#125;));</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">useCount</span> = (<span class="params"></span>) =&gt; <span class="title function_">useStore</span>(<span class="function"><span class="params">state</span> =&gt;</span> state.<span class="property">count</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Counter</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> count = <span class="title function_">useCount</span>();</span><br><span class="line">  <span class="keyword">const</span> increase = <span class="title function_">useStore</span>(<span class="function"><span class="params">state</span> =&gt;</span> state.<span class="property">increase</span>);</span><br><span class="line">  <span class="keyword">const</span> decrease = <span class="title function_">useStore</span>(<span class="function"><span class="params">state</span> =&gt;</span> state.<span class="property">decrease</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">h1</span>&gt;</span>&#123;count&#125;<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">&#123;increase&#125;</span>&gt;</span>Increase<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">&#123;decrease&#125;</span>&gt;</span>Decrease<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Zustand 是一个基于 Flux 原理实现的轻量级的状态管理库。截止到 2025年5月12日，Zustand 的最新版本是 5.0.4，Github 收藏数量为52.2k，npmjs周下载量为7m。&lt;/p&gt;
&lt;h2 id=&quot;Zustand-应用示例&quot;&gt;&lt;a href=&quot;</summary>
      
    
    
    
    
    <category term="react" scheme="https://mangon.cn/blog/tags/react/"/>
    
    <category term="Zustand" scheme="https://mangon.cn/blog/tags/Zustand/"/>
    
  </entry>
  
  <entry>
    <title>JSDoc 小抄</title>
    <link href="https://mangon.cn/blog/2025/02/24/FE-JSDoc%E5%B0%8F%E6%8A%84/"/>
    <id>https://mangon.cn/blog/2025/02/24/FE-JSDoc%E5%B0%8F%E6%8A%84/</id>
    <published>2025-02-24T08:40:39.000Z</published>
    <updated>2025-02-24T12:00:48.888Z</updated>
    
    <content type="html"><![CDATA[<h2 id="什么是-JSDoc"><a href="#什么是-JSDoc" class="headerlink" title="什么是 JSDoc"></a>什么是 JSDoc</h2><p><a href="https://jsdoc.app/">JSDoc</a> (<a href="https://github.com/jsdoc/jsdoc">Github地址</a>) 是一种用于 JavaScript 代码的 API 文档生成工具，它允许开发者通过注释的方式为代码添加文档说明。JSDoc 可以解析这些注释，并生成 HTML 格式的文档，帮助开发者更好地理解和使用代码。JSDoc 采用了 Apache License 2.0 开源协议。VS Code 内置了对 JSDoc 风格注释的支持，在 Javascript 和 TypeScript 代码中书写 JSDoc 风格的注释会自动高亮。</p><h2 id="JSDoc-的实现原理"><a href="#JSDoc-的实现原理" class="headerlink" title="JSDoc 的实现原理"></a>JSDoc 的实现原理</h2><p>JSDoc 的实现原理主要基于注释解析。开发者在 JavaScript 代码中使用特定格式的注释（通常是以 <code>/**</code> 开头的多行注释），JSDoc 工具会扫描这些注释并提取信息。提取的信息包括函数的参数、返回值、类型、描述等。然后，JSDoc 会将这些信息转换为结构化的文档格式（如 HTML），并生成相应的文档。</p><h2 id="JSDoc-常见用法"><a href="#JSDoc-常见用法" class="headerlink" title="JSDoc 常见用法"></a>JSDoc 常见用法</h2><ol><li>基本注释格式：</li></ol><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></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></span><br><span class="line"><span class="comment"> * <span class="doctag">@returns</span> &#123;<span class="type">类型</span>&#125; 返回值描述</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">example</span>(<span class="params">param</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> param;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="2"><li>类型注释：<br>可以使用 <code>&#123;&#125;</code> 来指定参数和返回值的类型，例如：</li></ol><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></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; name 用户名</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">number</span>&#125; age 用户年龄</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@returns</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">function</span> <span class="title function_">isAdult</span>(<span class="params">name, age</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> age &gt;= <span class="number">18</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="3"><li>模块和类注释：<br>JSDoc 也支持模块和类的文档注释：</li></ol><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="comment"> * <span class="doctag">@class</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span> &#123;</span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@constructor</span></span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> &#123;<span class="type">string</span>&#125; <span class="variable">name</span></span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">name</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="5"><li>使用名称路径<br>如果涉及到一个 JavaScript 变量，这个变量在文档中的其他地方，你必须提供一个唯一标识符映射到该变量。名称路径提供了一种这样做的方法，并且消除实例成员，静态成员和内部变量之间的歧义</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Person#say  // 名为&quot;say&quot;的实例方法</span></span><br><span class="line"><span class="comment"> * Person.say  // 名为&quot;say&quot;的静态方法</span></span><br><span class="line"><span class="comment"> * Person~say  // 名为&quot;say&quot;的内部函数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@module</span> foo/bar // 名为&quot;foo/bar&quot;的模块</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@external</span> String // 内置的 string 对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@event</span> module:foo/bar.event:MyEvent // 一个名为 module:foo/bar.event:MyEvent 的事件</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><h2 id="JSDoc-块标签与内联标签"><a href="#JSDoc-块标签与内联标签" class="headerlink" title="JSDoc 块标签与内联标签"></a>JSDoc 块标签与内联标签</h2><p>JSDoc支持两种不同类型的标签：</p><p>· 块标签(Block): 这是在一个 JSDoc 注释的最高级别。<br>· 内联标签(inline): 块标签文本中的标签或说明。</p><p>块标签通常会提供有关代码的详细信息，如一个函数接受的参数。内联标签通常链接到文件的其他部分，类似于HTML中的锚（<code>&lt;a&gt;</code>）标记。</p><p>块标签总是以 <code>@</code> 符号开头。除了 JSDoc 注释中最后一个块标记，每个块标签后面必须跟一个换行符。</p><p>内联标签也以 <code>@</code> 符号开。然而，内联标签及其文本必须用花括号 <code>&#123;</code> 与 <code>&#125;</code> 括起来。 <code>&#123;</code> 表示行内联标签的开始，而 <code>&#125;</code> 表示内联标签的结束。如果标签文本中包含 <code>&#125;</code>，则必须用 <code>\</code> 进行转义。在内联标签后，你并不需要使用一个换行符。</p><p>大多数 JSDoc 标签是块标签。一般来说，当这个网站上说“JSDoc 标签”，我们真正的意思是“块标签”。<a href="https://jsdoc.app/#block-tags">block-tags</a> 记录了在 JSDoc 中所有识别的块标签。</p><p>如下是一个示例，<code>@param</code> 是一个块标签，而 <code>&#123;@link&#125;</code> 是一个内联标签：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Set the shoe&#x27;s color. Use &#123;<span class="doctag">@link</span> Shoe#setSize&#125; to set the shoe size.</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">string</span>&#125; <span class="variable">color</span> - The shoe&#x27;s color.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="title class_">Shoe</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">setColor</span> = <span class="keyword">function</span> (<span class="params">color</span>) &#123;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="JSDoc-命令行"><a href="#JSDoc-命令行" class="headerlink" title="JSDoc 命令行"></a>JSDoc 命令行</h2><p>JSDoc 可以使用命令行工具生成文档：</p><figure class="highlight shell"><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">npm install -g jsdoc</span><br><span class="line">jsdoc yourfile.js</span><br></pre></td></tr></table></figure><p>执行该命令后，JSDoc 会在 <code>/out</code> 目录下生成当前目录的文档。JSDoc 支持大量的命令行选项，其中许多选项有长和短两种形式。</p><table><thead><tr><th>短选项</th><th>完整选项</th><th>描述</th></tr></thead><tbody><tr><td><code>-c &lt;value&gt;</code></td><td><code>--configure &lt;value&gt;</code></td><td>JSDoc 配置文件的路径。默认为安装 JSDoc 目录下的 <code>conf.json</code> 或 <code>conf.json.EXAMPLE</code></td></tr><tr><td><code>-d &lt;value&gt;</code></td><td><code>--destination &lt;value&gt;</code></td><td>输出生成文档的文件夹路径。默认为 <code>./out</code></td></tr><tr><td><code>-e &lt;value&gt;</code></td><td><code>--encoding &lt;value&gt;</code></td><td>源文件的编码。默认为 <code>utf8</code></td></tr><tr><td><code>-h</code></td><td><code>--help</code></td><td>显示 JSDoc 的命令行选项的信息，然后退出</td></tr><tr><td><code>-p</code></td><td><code>--private</code></td><td>将标记有 <code>@private</code> 标签的标识符也生成到文档中。默认情况下，不包括私有标识符</td></tr><tr><td><code>-r</code></td><td><code>--recurse</code></td><td>扫描源文件和导览时递归到子目录</td></tr><tr><td><code>-t &lt;value&gt;</code></td><td><code>--template &lt;value&gt;</code></td><td>指定模板文件夹的路径。默认为 <code>./templates/default</code></td></tr><tr><td><code>-v</code></td><td><code>--version</code></td><td>显示 JSDoc 的版本号，然后退出</td></tr><tr><td></td><td><code>--verbose</code></td><td>日志的详细信息到控制台 JSDoc 运行。默认为 false</td></tr><tr><td></td><td><code>--debug</code></td><td>显示调试信息到控制台 JSDoc 运行。默认为 false</td></tr><tr><td></td><td><code>--pedantic</code></td><td>当 JSDoc 遇到错误时，它将停止运行。默认为 false</td></tr></tbody></table><h2 id="JSDoc-配置文件"><a href="#JSDoc-配置文件" class="headerlink" title="JSDoc 配置文件"></a>JSDoc 配置文件</h2><p>JSDoc 的命令行选项也可以在配置文件中指定。要使用配置文件运行 JSDoc，需要使用 <code>-c</code> 命令行选项（例如，<code>jsdoc -c /path/to/conf.json</code> 或 <code>jsdoc -c /path/to/conf.js</code>）。</p><p>默认配置如下：</p><figure class="highlight json"><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="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;plugins&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="comment">// 无插件加载</span></span><br><span class="line">  <span class="attr">&quot;recurseDepth&quot;</span><span class="punctuation">:</span> <span class="number">10</span><span class="punctuation">,</span> <span class="comment">// 如果使用 -r 命令行标志启用递归，JSDoc 将搜索 10 层深的文件</span></span><br><span class="line">  <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="comment">// 源代码配置</span></span><br><span class="line">    <span class="attr">&quot;includePattern&quot;</span><span class="punctuation">:</span> <span class="string">&quot;.+\\.js(doc|x)?$&quot;</span><span class="punctuation">,</span> <span class="comment">// 只有以 .js、.jsdoc 和 .jsx 结尾的文件将会被处理</span></span><br><span class="line">    <span class="attr">&quot;excludePattern&quot;</span><span class="punctuation">:</span> <span class="string">&quot;(^|\\/|\\\\)_&quot;</span> <span class="comment">// 任何文件或目录如果以 _ 开始将被忽略</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;sourceType&quot;</span><span class="punctuation">:</span> <span class="string">&quot;module&quot;</span><span class="punctuation">,</span> <span class="comment">// &quot;script&quot;，表示脚本文件，&quot;module&quot; 表示模块文件</span></span><br><span class="line">  <span class="attr">&quot;tags&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="comment">// 标签配置</span></span><br><span class="line">    <span class="attr">&quot;allowUnknownTags&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span> <span class="comment">// 允许使用未知的标签</span></span><br><span class="line">    <span class="attr">&quot;dictionaries&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;jsdoc&quot;</span><span class="punctuation">,</span> <span class="string">&quot;closure&quot;</span><span class="punctuation">]</span> <span class="comment">// 允许使用 jsdoc 标签 和 [closure 标签](https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler#jsdoc-tags)</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;templates&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="comment">// 模板配置</span></span><br><span class="line">    <span class="attr">&quot;cleverLinks&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span> <span class="comment">// 链接到源码</span></span><br><span class="line">    <span class="attr">&quot;monospaceLinks&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span> <span class="comment">// 源码行号</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h2 id="JSDoc-插件"><a href="#JSDoc-插件" class="headerlink" title="JSDoc 插件"></a>JSDoc 插件</h2><p>在 JSDoc 中，插件的作用是扩展 JSDoc 的功能，比如添加新的标签、解析新的语法等。首先，需要创建一个包含插件代码的 Javascript 模块，然后将该模块添加到 JSDoc 的配置文件 <code>plugin</code> 参数中，以启用插件。</p><p>一个 JSDoc 插件可以：<br>· 定义事件处理程序<br>· 定义自定义标签，如 <code>@author</code>、<code>@version</code> 等。<br>· 定义一个抽象的解析器，用于解析自定义标签。</p><p>JSDoc 插件的事件处理程序包括：<br><code>Event: parseBegin</code>: JSDoc 开始加载和解析源文件之前，parseBegin 事件被触发。插件可以通过修改事件的内容，来控制哪些文件将被 JSDoc 解析。(&gt;<a href="mailto:=JSDoc@3.2.0">=JSDoc@3.2.0</a>)<br><code>Event: fileBegin</code>: 当解析器即将解析一个文件 fileBegin 事件触发。如果需要，插件可以使用此事件触发每个文件的初始化。<br><code>Event: beforeParse</code>: beforeParse 事件在解析开始之前被触发。插件可以使用此方法来修改将被解析的源代码。<br><code>Event: jsdocCommentFound</code>: 每当 JSDoc 注释被发现，jsdocCommentFound 事件就会被触发。注释可以或不与任何代码相关联。你可以在注释被处理之前使用此事件修改注释的内容。(&gt;<a href="mailto:=JSDoc@3.5.0">=JSDoc@3.5.0</a>)<br><code>Event: symbolFound</code>: 当解析器在代码中遇到一个可能需要被文档化的标识符时，symbolFound 事件就会被触发。<br><code>Event: newDoclet</code>: newDoclet事件是最高级别的事件。新的 doclet 已被创建时，它就会被触发。这意味着一个 JSDoc 注释或标识符已被处理，并且实际传递给模板的 doclet 已被创建。<br><code>Event: fileComplete</code>: 当解析器解析完一个文件时，fileComplete 事件就会被触发。插件可以使用这个事件来触发每个文件的清理。<br><code>Event: parseComplete</code>: JSDoc 解析所有指定的源文件之后，parseComplete 事件就会被触发。(&gt;<a href="mailto:=JSDoc@3.2.0">=JSDoc@3.2.0</a>)<br><code>Event: processingComplete</code>: JSDoc 更新反映继承和借来的标识符的解析结果后，processingComplete 事件被触发。(&gt;<a href="mailto:=JSDoc@3.2.1">=JSDoc@3.2.1</a>)</p><p>JSDoc 包含一个 Markdown 插件来自动将 Markdown 格式文本转换成 HTML。可以通过如下配置开启：</p><figure class="highlight json"><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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;plugins&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;plugins/markdown&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;markdown&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;tags&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;foo&quot;</span><span class="punctuation">,</span> <span class="string">&quot;bar&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="comment">// 扩展需解析 markdown 的标签</span></span><br><span class="line">      <span class="attr">&quot;excludeTags&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;author&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span>  <span class="comment">// 不解析 markdown 的标签</span></span><br><span class="line">      <span class="attr">&quot;hardwrap&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span> <span class="comment">// 是否强制换行(&gt;=JSDoc@3.4.0)</span></span><br><span class="line">      <span class="attr">&quot;idInHeadings&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span> <span class="comment">// 是否在标题中添加 id(&gt;=JSDoc@3.4.0)</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>Markdown 插件默认只解析特定的 JSDoc 标签（<code>@author</code>,<code>@classdesc</code>,<code>@description</code>,<code>@param</code>,<code>@property</code>,<code>@return</code>,<code>@see</code>,<code>@throws</code>），可以通过在配置文件的 <code>markdown.tags</code> 字段中添加标签来扩展解析范围。可以通过 <code>markdown.excludeTags</code> 字段来排除默认标签的解析。</p><h2 id="其他功能"><a href="#其他功能" class="headerlink" title="其他功能"></a>其他功能</h2><p>· JSDoc 支持通过 <code>--tutorials</code> 或 <code>-u</code> 选项提供 JSDoc 要搜索的教程目录从而为 API 文档添加教程。<br>· JSDoc 支持通过 <code>--package</code> 或 <code>-P</code> 选项指定 package.json 文件的路径从而在生成文档的时候自动使用 package.json 的信息。(&gt;<a href="mailto:=JSDoc@3.3.0">=JSDoc@3.3.0</a>)<br>· JSDoc 支持通过 <code>--readme</code> 或 <code>-R</code> 选项指定将 README 文件中的信息合并到文档中。(&gt;<a href="mailto:=JSDoc@3.3.0">=JSDoc@3.3.0</a>)</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;什么是-JSDoc&quot;&gt;&lt;a href=&quot;#什么是-JSDoc&quot; class=&quot;headerlink&quot; title=&quot;什么是 JSDoc&quot;&gt;&lt;/a&gt;什么是 JSDoc&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://jsdoc.app/&quot;&gt;JSDoc&lt;/a&gt; (&lt;a</summary>
      
    
    
    
    
    <category term="JSDoc" scheme="https://mangon.cn/blog/tags/JSDoc/"/>
    
  </entry>
  
  <entry>
    <title>linux系统下常用命令</title>
    <link href="https://mangon.cn/blog/2025/01/20/CS-linux%E7%B3%BB%E7%BB%9F%E4%B8%8B%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/"/>
    <id>https://mangon.cn/blog/2025/01/20/CS-linux%E7%B3%BB%E7%BB%9F%E4%B8%8B%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/</id>
    <published>2025-01-20T09:17:59.000Z</published>
    <updated>2025-01-22T08:04:24.798Z</updated>
    
    <content type="html"><![CDATA[<h2 id="alias"><a href="#alias" class="headerlink" title="alias"></a>alias</h2><p><code>alias</code> 命令用于为命令创建别名，以便简化输入和提高效率。</p><h3 id="用法示例"><a href="#用法示例" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span> ll=<span class="string">&#x27;ls -la&#x27;</span></span><br></pre></td></tr></table></figure><p>这个命令会创建一个别名 <code>ll</code>，用于执行 <code>ls -la</code> 命令。</p><h3 id="常见用法"><a href="#常见用法" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>创建简单别名：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span> gs=<span class="string">&#x27;git status&#x27;</span></span><br></pre></td></tr></table></figure><p>这个命令会创建一个别名 <code>gs</code>，用于快速查看 Git 状态。</p><ul><li>创建带参数的别名：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span> <span class="built_in">rm</span>=<span class="string">&#x27;rm -i&#x27;</span></span><br></pre></td></tr></table></figure><p>这个命令会创建一个别名 <code>rm</code>，在删除文件时提示确认。</p><ul><li>查看当前所有别名：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span></span><br></pre></td></tr></table></figure><p>这个命令会列出当前会话中所有已定义的别名。</p><ul><li>删除别名：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">unalias</span> ll</span><br></pre></td></tr></table></figure><p>这个命令会删除别名 <code>ll</code>。</p><ul><li>将别名永久保存：<br>可以将别名添加到用户的 <code>~/.bashrc</code> 或 <code>~/.bash_aliases</code> 文件中，以便在每次登录时自动加载。</li></ul><figure class="highlight bash"><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="built_in">echo</span> <span class="string">&quot;alias ll=&#x27;ls -la&#x27;&quot;</span> &gt;&gt; ~/.bashrc</span><br><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br></pre></td></tr></table></figure><ul><li>创建复杂的别名（使用函数）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span> mygrep=<span class="string">&#x27;grep --color=auto&#x27;</span></span><br></pre></td></tr></table></figure><p>这个命令会创建一个别名 <code>mygrep</code>，在使用 <code>grep</code> 时自动启用颜色高亮。</p><ul><li>使用别名时显示帮助信息：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span> h=<span class="string">&#x27;history&#x27;</span></span><br></pre></td></tr></table></figure><p>这个命令会创建一个别名 <code>h</code>，用于快速查看命令历史。</p><h2 id="awk"><a href="#awk" class="headerlink" title="awk"></a>awk</h2><p><code>awk</code> 是一个强大的文本处理工具，主要用于模式扫描和处理。它可以从文本文件中提取和处理数据。</p><h3 id="用法示例-1"><a href="#用法示例-1" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk <span class="string">&#x27;&#123;print $1&#125;&#x27;</span> filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会打印 <code>filename.txt</code> 文件中每一行的第一个字段。</p><h3 id="常见用法-1"><a href="#常见用法-1" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>统计文件中的行数：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk <span class="string">&#x27;END &#123;print NR&#125;&#x27;</span> filename.txt</span><br></pre></td></tr></table></figure><ul><li>计算某一列的总和：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk <span class="string">&#x27;&#123;sum += $1&#125; END &#123;print sum&#125;&#x27;</span> filename.txt</span><br></pre></td></tr></table></figure><ul><li>过滤特定模式的行：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk <span class="string">&#x27;/pattern/&#x27;</span> filename.txt</span><br></pre></td></tr></table></figure><h2 id="cat"><a href="#cat" class="headerlink" title="cat"></a>cat</h2><p><code>cat</code> 命令用于连接文件并打印到标准输出，常用于查看文件内容。</p><h3 id="用法示例-2"><a href="#用法示例-2" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会打印 <code>filename.txt</code> 文件的所有内容。</p><h3 id="常见用法-2"><a href="#常见用法-2" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>查看多个文件的内容：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> file1.txt file2.txt</span><br></pre></td></tr></table></figure><ul><li>将文件内容输出到另一个文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> filename.txt &gt; newfile.txt</span><br></pre></td></tr></table></figure><ul><li>追加文件内容到另一个文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> filename.txt &gt;&gt; existingfile.txt</span><br></pre></td></tr></table></figure><ul><li>显示行号：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> -n filename.txt</span><br></pre></td></tr></table></figure><h2 id="cd"><a href="#cd" class="headerlink" title="cd"></a>cd</h2><p><code>cd</code> 命令用于更改当前工作目录。</p><h3 id="用法示例-3"><a href="#用法示例-3" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /path/to/directory</span><br></pre></td></tr></table></figure><p>这个命令会将当前工作目录更改为指定的目录。</p><h3 id="常见用法-3"><a href="#常见用法-3" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>返回上一级目录：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ..</span><br></pre></td></tr></table></figure><ul><li>返回用户主目录：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~</span><br></pre></td></tr></table></figure><ul><li>切换到上一次访问的目录：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> -</span><br></pre></td></tr></table></figure><ul><li>使用相对路径切换目录：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> subdirectory/</span><br></pre></td></tr></table></figure><p>这个命令会切换到当前目录下的 <code>subdirectory</code> 目录。</p><ul><li>切换到多个目录（使用 <code>pushd</code> 和 <code>popd</code>）：</li></ul><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">pushd</span> /path/to/directory</span><br><span class="line"><span class="comment"># ... 在新目录中工作 ...</span></span><br><span class="line"><span class="built_in">popd</span></span><br></pre></td></tr></table></figure><p>这个命令会将当前目录推入目录栈并切换到指定目录，<code>popd</code> 则会返回到之前的目录。</p><h2 id="chmod"><a href="#chmod" class="headerlink" title="chmod"></a>chmod</h2><p><code>chmod</code> 命令用于更改文件或目录的权限。</p><h3 id="用法示例-4"><a href="#用法示例-4" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 755 filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会将 <code>filename.txt</code> 的权限更改为可读、可写和可执行（所有者），可读和可执行（组和其他用户）。</p><h3 id="常见用法-4"><a href="#常见用法-4" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>递归更改目录及其内容的权限：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> -R 755 directory_name</span><br></pre></td></tr></table></figure><ul><li>仅添加执行权限：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> +x filename.sh</span><br></pre></td></tr></table></figure><ul><li>仅移除写权限：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> -w filename.txt</span><br></pre></td></tr></table></figure><ul><li>设置特定权限（如只读）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 444 filename.txt</span><br></pre></td></tr></table></figure><ul><li>使用符号模式更改权限：</li></ul><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">chmod</span> u+x filename.txt  <span class="comment"># 为文件所有者添加执行权限</span></span><br><span class="line"><span class="built_in">chmod</span> g-w filename.txt  <span class="comment"># 从组中移除写权限</span></span><br><span class="line"><span class="built_in">chmod</span> o=r filename.txt  <span class="comment"># 设置其他用户为只读权限</span></span><br></pre></td></tr></table></figure><h2 id="chown"><a href="#chown" class="headerlink" title="chown"></a>chown</h2><p><code>chown</code> 命令用于更改文件或目录的所有者和所属组。</p><h3 id="用法示例-5"><a href="#用法示例-5" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chown</span> user:group filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会将 <code>filename.txt</code> 的所有者更改为 <code>user</code>，所属组更改为 <code>group</code>。</p><h3 id="常见用法-5"><a href="#常见用法-5" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>仅更改文件的所有者：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chown</span> user filename.txt</span><br></pre></td></tr></table></figure><ul><li>仅更改文件的所属组：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chown</span> :group filename.txt</span><br></pre></td></tr></table></figure><ul><li>递归更改目录及其内容的所有者和所属组：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chown</span> -R user:group directory_name</span><br></pre></td></tr></table></figure><ul><li>显示当前文件的所有者和所属组：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> -l filename.txt</span><br></pre></td></tr></table></figure><ul><li>更改多个文件的所有者：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chown</span> user1:usergroup file1.txt file2.txt</span><br></pre></td></tr></table></figure><h2 id="cp"><a href="#cp" class="headerlink" title="cp"></a>cp</h2><p><code>cp</code> 命令用于复制文件和目录。</p><h3 id="用法示例-6"><a href="#用法示例-6" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> source.txt destination.txt</span><br></pre></td></tr></table></figure><p>这个命令会将 <code>source.txt</code> 文件复制到 <code>destination.txt</code>。</p><h3 id="常见用法-6"><a href="#常见用法-6" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>复制文件到另一个目录：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> filename.txt /path/to/directory/</span><br></pre></td></tr></table></figure><ul><li>复制目录及其内容（使用 <code>-r</code> 选项）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> -r sourcedir/ targetdir/</span><br></pre></td></tr></table></figure><ul><li>复制并重命名文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> filename.txt newname.txt</span><br></pre></td></tr></table></figure><ul><li>交互式复制（在覆盖文件前提示确认）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> -i filename.txt destination.txt</span><br></pre></td></tr></table></figure><ul><li>复制文件并保留文件属性：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> -p filename.txt destination.txt</span><br></pre></td></tr></table></figure><h2 id="curl"><a href="#curl" class="headerlink" title="curl"></a>curl</h2><p><code>curl</code> 是一个用于在命令行中进行数据传输的工具，支持多种协议，包括 HTTP、HTTPS、FTP 等。</p><h3 id="用法示例-7"><a href="#用法示例-7" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl http://example.com</span><br></pre></td></tr></table></figure><p>这个命令会从 <code>http://example.com</code> 下载内容并打印到标准输出。</p><h3 id="常见用法-7"><a href="#常见用法-7" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>下载文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -O http://example.com/file.txt</span><br></pre></td></tr></table></figure><ul><li>发送 POST 请求：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -X POST -d <span class="string">&quot;param1=value1&amp;param2=value2&quot;</span> http://example.com/api</span><br></pre></td></tr></table></figure><ul><li>添加请求头：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -H <span class="string">&quot;Authorization: Bearer TOKEN&quot;</span> http://example.com/api</span><br></pre></td></tr></table></figure><ul><li>显示请求和响应的详细信息：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -v http://example.com</span><br></pre></td></tr></table></figure><ul><li>保存输出到文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -o output.txt http://example.com</span><br></pre></td></tr></table></figure><h2 id="df"><a href="#df" class="headerlink" title="df"></a>df</h2><p><code>df</code> 命令用于显示文件系统的磁盘空间使用情况。</p><h3 id="用法示例-8"><a href="#用法示例-8" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span></span><br></pre></td></tr></table></figure><p>这个命令会显示所有挂载的文件系统的磁盘使用情况。</p><h3 id="常见用法-8"><a href="#常见用法-8" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>以人类可读的格式显示（例如，KB、MB、GB）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span> -h</span><br></pre></td></tr></table></figure><ul><li>显示特定文件系统的信息：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span> /path/to/directory</span><br></pre></td></tr></table></figure><ul><li>显示所有文件系统，包括虚拟文件系统：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span> -a</span><br></pre></td></tr></table></figure><ul><li>显示 inode 使用情况：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span> -i</span><br></pre></td></tr></table></figure><p>这个命令会显示每个文件系统的 inode 使用情况。</p><h2 id="du"><a href="#du" class="headerlink" title="du"></a>du</h2><p><code>du</code> 命令用于显示目录或文件的磁盘使用情况。</p><h3 id="用法示例-9"><a href="#用法示例-9" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">du</span> /path/to/directory</span><br></pre></td></tr></table></figure><p>这个命令会显示指定目录及其子目录的磁盘使用情况。</p><h3 id="常见用法-9"><a href="#常见用法-9" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>显示指定目录的总大小：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">du</span> -sh /path/to/directory</span><br></pre></td></tr></table></figure><p>这个命令会以人类可读的格式（如 KB、MB、GB）显示指定目录的总大小。</p><ul><li>显示每个子目录的大小：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">du</span> -h /path/to/directory</span><br></pre></td></tr></table></figure><p>这个命令会以人类可读的格式显示指定目录下每个子目录的大小。</p><ul><li>递归显示所有子目录的大小：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">du</span> -ah /path/to/directory</span><br></pre></td></tr></table></figure><p>这个命令会显示指定目录及其所有子目录和文件的大小。</p><ul><li>按大小排序显示：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">du</span> -sh /path/to/directory/* | <span class="built_in">sort</span> -h</span><br></pre></td></tr></table></figure><p>这个命令会显示指定目录下每个文件和子目录的大小，并按大小排序。</p><ul><li>显示特定深度的目录大小：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">du</span> -h --max-depth=1 /path/to/directory</span><br></pre></td></tr></table></figure><p>这个命令会显示指定目录下的每个子目录的大小，但只显示到第一层深度。</p><ul><li>显示文件系统的使用情况：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">du</span> -x /path/to/directory</span><br></pre></td></tr></table></figure><p>这个命令会限制 <code>du</code> 只计算指定目录所在的文件系统的大小。</p><h2 id="echo"><a href="#echo" class="headerlink" title="echo"></a>echo</h2><p><code>echo</code> 命令用于在终端输出文本或变量的值。</p><h3 id="用法示例-10"><a href="#用法示例-10" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Hello, World!&quot;</span></span><br></pre></td></tr></table></figure><p>这个命令会在终端打印 <code>Hello, World!</code>。</p><h3 id="常见用法-10"><a href="#常见用法-10" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>输出变量的值：</li></ul><figure class="highlight bash"><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">name=<span class="string">&quot;Alice&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Hello, <span class="variable">$name</span>!&quot;</span></span><br></pre></td></tr></table></figure><ul><li>输出带有换行符的文本：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> -e <span class="string">&quot;Line 1\nLine 2&quot;</span></span><br></pre></td></tr></table></figure><ul><li>不输出换行符：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> -n <span class="string">&quot;This is on the same line.&quot;</span></span><br></pre></td></tr></table></figure><ul><li>输出带有特殊字符的文本：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&quot;This is a dollar sign: \$&quot;</span></span><br></pre></td></tr></table></figure><h2 id="find"><a href="#find" class="headerlink" title="find"></a>find</h2><p><code>find</code> 命令用于在目录中查找文件和目录，支持多种搜索条件。</p><h3 id="用法示例-11"><a href="#用法示例-11" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /path/to/directory -name <span class="string">&quot;filename.txt&quot;</span></span><br></pre></td></tr></table></figure><p>这个命令会在指定目录中查找名为 <code>filename.txt</code> 的文件。</p><h3 id="常见用法-11"><a href="#常见用法-11" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>查找特定类型的文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /path/to/directory -<span class="built_in">type</span> f -name <span class="string">&quot;*.txt&quot;</span></span><br></pre></td></tr></table></figure><p>这个命令会查找所有以 <code>.txt</code> 结尾的文件。</p><ul><li>按文件大小查找：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /path/to/directory -size +10M</span><br></pre></td></tr></table></figure><p>这个命令会查找大于 10MB 的文件。</p><ul><li>按修改时间查找：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /path/to/directory -mtime -7</span><br></pre></td></tr></table></figure><p>这个命令会查找最近 7 天内修改过的文件。</p><ul><li>查找并执行命令：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /path/to/directory -name <span class="string">&quot;*.log&quot;</span> -<span class="built_in">exec</span> <span class="built_in">rm</span> &#123;&#125; \;</span><br></pre></td></tr></table></figure><p>这个命令会查找所有 <code>.log</code> 文件并删除它们。</p><ul><li>查找并显示详细信息：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /path/to/directory -name <span class="string">&quot;*.txt&quot;</span> -<span class="built_in">print</span></span><br></pre></td></tr></table></figure><p>这个命令会查找所有 <code>.txt</code> 文件并打印其路径。</p><ul><li>查找空文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /path/to/directory -<span class="built_in">type</span> f -empty</span><br></pre></td></tr></table></figure><p>这个命令会查找所有空文件。</p><ul><li>查找特定用户的文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /path/to/directory -user username</span><br></pre></td></tr></table></figure><p>这个命令会查找属于指定用户的文件。</p><h2 id="grep"><a href="#grep" class="headerlink" title="grep"></a>grep</h2><p><code>grep</code> 命令用于在文件中搜索指定的模式，并打印匹配的行。</p><h3 id="用法示例-12"><a href="#用法示例-12" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep <span class="string">&quot;pattern&quot;</span> filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会在 <code>filename.txt</code> 文件中搜索包含 <code>pattern</code> 的行并打印出来。</p><h3 id="常见用法-12"><a href="#常见用法-12" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>忽略大小写搜索：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -i <span class="string">&quot;pattern&quot;</span> filename.txt</span><br></pre></td></tr></table></figure><ul><li>显示行号：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -n <span class="string">&quot;pattern&quot;</span> filename.txt</span><br></pre></td></tr></table></figure><ul><li>递归搜索目录中的文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -r <span class="string">&quot;pattern&quot;</span> /path/to/directory/</span><br></pre></td></tr></table></figure><ul><li>只显示匹配的部分：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -o <span class="string">&quot;pattern&quot;</span> filename.txt</span><br></pre></td></tr></table></figure><ul><li>反向匹配（显示不包含模式的行）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -v <span class="string">&quot;pattern&quot;</span> filename.txt</span><br></pre></td></tr></table></figure><h2 id="head"><a href="#head" class="headerlink" title="head"></a>head</h2><p><code>head</code> 命令用于显示文件的开头部分，默认情况下显示前 10 行。</p><h3 id="用法示例-13"><a href="#用法示例-13" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">head</span> filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会打印 <code>filename.txt</code> 文件的前 10 行。</p><h3 id="常见用法-13"><a href="#常见用法-13" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>显示指定行数的开头部分：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">head</span> -n 5 filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会打印 <code>filename.txt</code> 文件的前 5 行。</p><ul><li>显示多个文件的开头部分：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">head</span> file1.txt file2.txt</span><br></pre></td></tr></table></figure><ul><li>显示文件的字节数：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">head</span> -c 20 filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会打印 <code>filename.txt</code> 文件的前 20 个字节。</p><h2 id="history"><a href="#history" class="headerlink" title="history"></a>history</h2><p><code>history</code> 命令用于显示用户在当前会话中输入的命令历史记录。</p><h3 id="用法示例-14"><a href="#用法示例-14" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">history</span></span><br></pre></td></tr></table></figure><p>这个命令会列出当前用户在终端中输入的所有命令。</p><h3 id="常见用法-14"><a href="#常见用法-14" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>显示最近的命令数量：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">history</span> 10</span><br></pre></td></tr></table></figure><p>这个命令会显示最近输入的 10 条命令。</p><ul><li>重新执行某条命令：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">!n</span><br></pre></td></tr></table></figure><p>其中 <code>n</code> 是命令在历史记录中的编号。例如，<code>!5</code> 会重新执行历史记录中编号为 5 的命令。</p><ul><li>清空命令历史：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">history</span> -c</span><br></pre></td></tr></table></figure><p>这个命令会清空当前会话的命令历史记录。</p><ul><li>将历史记录保存到文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">history</span> &gt; history.txt</span><br></pre></td></tr></table></figure><p>这个命令会将当前会话的命令历史保存到 <code>history.txt</code> 文件中。</p><ul><li>使用 <code>grep</code> 搜索历史记录：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">history</span> | grep <span class="string">&quot;pattern&quot;</span></span><br></pre></td></tr></table></figure><p>这个命令会在历史记录中搜索包含 <code>pattern</code> 的命令。</p><ul><li>在命令行中使用上一个命令：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">!!</span><br></pre></td></tr></table></figure><p>这个命令会重新执行上一个输入的命令。</p><h2 id="kill-killall"><a href="#kill-killall" class="headerlink" title="kill/killall"></a>kill/killall</h2><p><code>kill</code> 命令用于向进程发送信号，通常用于终止进程。</p><h3 id="用法示例-15"><a href="#用法示例-15" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">kill</span> PID</span><br></pre></td></tr></table></figure><p>这个命令会向指定的进程 ID（PID）发送终止信号。</p><h3 id="常见用法-15"><a href="#常见用法-15" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>强制终止进程：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">kill</span> -9 PID</span><br></pre></td></tr></table></figure><p>这个命令会强制终止指定的进程。</p><ul><li>发送其他信号（如停止进程）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">kill</span> -STOP PID</span><br></pre></td></tr></table></figure><ul><li>查看所有进程并找到 PID：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps aux | grep process_name</span><br></pre></td></tr></table></figure><ul><li>终止所有匹配的进程：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">killall process_name</span><br></pre></td></tr></table></figure><h2 id="ls"><a href="#ls" class="headerlink" title="ls"></a>ls</h2><p><code>ls</code> 命令用于列出目录中的文件和子目录。</p><h3 id="用法示例-16"><a href="#用法示例-16" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span></span><br></pre></td></tr></table></figure><p>这个命令会列出当前目录中的所有文件和子目录。</p><h3 id="常见用法-16"><a href="#常见用法-16" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>列出详细信息（包括权限、所有者、大小等）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> -l</span><br></pre></td></tr></table></figure><ul><li>列出所有文件，包括隐藏文件（以点开头的文件）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> -a</span><br></pre></td></tr></table></figure><ul><li>以人类可读的格式显示文件大小：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> -lh</span><br></pre></td></tr></table></figure><ul><li>按时间排序列出文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> -lt</span><br></pre></td></tr></table></figure><ul><li>递归列出所有子目录中的文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> -R</span><br></pre></td></tr></table></figure><ul><li>列出特定类型的文件（例如，只列出目录）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> -d */</span><br></pre></td></tr></table></figure><h2 id="man"><a href="#man" class="headerlink" title="man"></a>man</h2><p><code>man</code> 命令用于查看其他命令的手册页，提供命令的详细信息和用法。</p><h3 id="用法示例-17"><a href="#用法示例-17" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">man command_name</span><br></pre></td></tr></table></figure><p>这个命令会显示 <code>command_name</code> 的手册页。</p><h3 id="常见用法-17"><a href="#常见用法-17" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>查看特定命令的手册页：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">man <span class="built_in">ls</span></span><br></pre></td></tr></table></figure><ul><li>搜索手册页中的关键字：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">man -k keyword</span><br></pre></td></tr></table></figure><p>这个命令会列出所有包含 <code>keyword</code> 的手册页。</p><ul><li>查看手册页的特定部分（例如，用户命令、系统调用等）：</li></ul><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">man 1 command_name  <span class="comment"># 用户命令</span></span><br><span class="line">man 2 command_name  <span class="comment"># 系统调用</span></span><br><span class="line">man 3 command_name  <span class="comment"># 库函数</span></span><br></pre></td></tr></table></figure><ul><li><p>在手册页中向上或向下滚动：<br>使用 <code>↑</code> 和 <code>↓</code> 键进行滚动，使用 <code>q</code> 键退出手册页。</p></li><li><p>查看手册页的帮助信息：</p></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">man man</span><br></pre></td></tr></table></figure><p>这个命令会显示 <code>man</code> 命令本身的手册页。</p><h2 id="mv"><a href="#mv" class="headerlink" title="mv"></a>mv</h2><p><code>mv</code> 命令用于移动或重命名文件和目录。</p><h3 id="用法示例-18"><a href="#用法示例-18" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mv</span> oldname.txt newname.txt</span><br></pre></td></tr></table></figure><p>这个命令会将 <code>oldname.txt</code> 文件重命名为 <code>newname.txt</code>。</p><h3 id="常见用法-18"><a href="#常见用法-18" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>移动文件到另一个目录：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mv</span> filename.txt /path/to/directory/</span><br></pre></td></tr></table></figure><ul><li>移动并重命名文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mv</span> filename.txt /path/to/directory/newname.txt</span><br></pre></td></tr></table></figure><ul><li>交互式移动（在覆盖文件前提示确认）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mv</span> -i filename.txt /path/to/directory/</span><br></pre></td></tr></table></figure><ul><li>强制移动（不提示确认）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mv</span> -f filename.txt /path/to/directory/</span><br></pre></td></tr></table></figure><h2 id="ps"><a href="#ps" class="headerlink" title="ps"></a>ps</h2><p><code>ps</code> 命令用于显示当前运行的进程信息。</p><h3 id="用法示例-19"><a href="#用法示例-19" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps</span><br></pre></td></tr></table></figure><p>这个命令会列出当前用户的所有进程。</p><h3 id="常见用法-19"><a href="#常见用法-19" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>显示所有进程，包括其他用户的进程：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -e</span><br></pre></td></tr></table></figure><ul><li>显示详细信息：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -f</span><br></pre></td></tr></table></figure><ul><li>显示进程树：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -ejH</span><br></pre></td></tr></table></figure><ul><li>显示特定用户的进程：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -u username</span><br></pre></td></tr></table></figure><ul><li>显示与特定命令相关的进程：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -C command_name</span><br></pre></td></tr></table></figure><h2 id="pwd"><a href="#pwd" class="headerlink" title="pwd"></a>pwd</h2><p><code>pwd</code> 命令用于显示当前工作目录的完整路径。</p><h3 id="用法示例-20"><a href="#用法示例-20" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">pwd</span></span><br></pre></td></tr></table></figure><p>这个命令会打印当前工作目录的绝对路径。</p><h3 id="常见用法-20"><a href="#常见用法-20" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>在脚本中使用 <code>pwd</code> 获取当前目录：</li></ul><figure class="highlight bash"><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">current_dir=$(<span class="built_in">pwd</span>)</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;当前目录是: <span class="variable">$current_dir</span>&quot;</span></span><br></pre></td></tr></table></figure><ul><li>与其他命令结合使用：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /path/to/directory &amp;&amp; <span class="built_in">pwd</span></span><br></pre></td></tr></table></figure><p>这个命令会切换到指定目录并显示该目录的路径。</p><h2 id="rm"><a href="#rm" class="headerlink" title="rm"></a>rm</h2><p><code>rm</code> 命令用于删除文件和目录。</p><h3 id="用法示例-21"><a href="#用法示例-21" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会删除 <code>filename.txt</code> 文件。</p><h3 id="常见用法-21"><a href="#常见用法-21" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>删除多个文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> file1.txt file2.txt</span><br></pre></td></tr></table></figure><ul><li>递归删除目录及其内容（使用 <code>-r</code> 选项）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> -r directory_name</span><br></pre></td></tr></table></figure><ul><li>强制删除文件（不提示确认）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> -f filename.txt</span><br></pre></td></tr></table></figure><ul><li>交互式删除（在删除前提示确认）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> -i filename.txt</span><br></pre></td></tr></table></figure><ul><li>删除空目录：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rmdir</span> directory_name</span><br></pre></td></tr></table></figure><h2 id="scp"><a href="#scp" class="headerlink" title="scp"></a>scp</h2><p><code>scp</code> 命令用于在本地和远程主机之间安全地复制文件。</p><h3 id="用法示例-22"><a href="#用法示例-22" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">scp localfile.txt user@remotehost:/path/to/destination</span><br></pre></td></tr></table></figure><p>这个命令会将本地的 <code>localfile.txt</code> 文件复制到远程主机的指定路径。</p><h3 id="常见用法-22"><a href="#常见用法-22" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>从远程主机复制文件到本地：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">scp user@remotehost:/path/to/remotefile.txt /local/path</span><br></pre></td></tr></table></figure><ul><li>递归复制整个目录：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">scp -r localdir user@remotehost:/path/to/destination</span><br></pre></td></tr></table></figure><ul><li>使用特定端口进行连接：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">scp -P 2222 localfile.txt user@remotehost:/path/to/destination</span><br></pre></td></tr></table></figure><ul><li>复制文件并保留文件属性：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">scp -p localfile.txt user@remotehost:/path/to/destination</span><br></pre></td></tr></table></figure><ul><li>显示详细的传输过程：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">scp -v localfile.txt user@remotehost:/path/to/destination</span><br></pre></td></tr></table></figure><h2 id="sed"><a href="#sed" class="headerlink" title="sed"></a>sed</h2><p><code>sed</code> 是一个流编辑器，用于对文本进行基本的转换和处理。</p><h3 id="用法示例-23"><a href="#用法示例-23" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed <span class="string">&#x27;s/old/new/&#x27;</span> filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会将 <code>filename.txt</code> 文件中每一行的第一个 <code>old</code> 替换为 <code>new</code>。</p><h3 id="常见用法-23"><a href="#常见用法-23" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>替换文件中的所有匹配项：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed <span class="string">&#x27;s/old/new/g&#x27;</span> filename.txt</span><br></pre></td></tr></table></figure><ul><li>在特定行进行替换：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed <span class="string">&#x27;2s/old/new/&#x27;</span> filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会在第二行中将 <code>old</code> 替换为 <code>new</code>。</p><ul><li>删除特定行：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed <span class="string">&#x27;3d&#x27;</span> filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会删除 <code>filename.txt</code> 文件的第三行。</p><ul><li>直接修改文件（使用 <code>-i</code> 选项）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed -i <span class="string">&#x27;s/old/new/g&#x27;</span> filename.txt</span><br></pre></td></tr></table></figure><ul><li>显示行号：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed = filename.txt | sed <span class="string">&#x27;N;s/\n/ /&#x27;</span></span><br></pre></td></tr></table></figure><h2 id="ssh"><a href="#ssh" class="headerlink" title="ssh"></a>ssh</h2><p><code>ssh</code> 命令用于安全地远程登录到另一台计算机。</p><h3 id="用法示例-24"><a href="#用法示例-24" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh user@remotehost</span><br></pre></td></tr></table></figure><p>这个命令会以 <code>user</code> 用户身份登录到 <code>remotehost</code>。</p><h3 id="常见用法-24"><a href="#常见用法-24" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>使用特定端口进行连接：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -p 2222 user@remotehost</span><br></pre></td></tr></table></figure><ul><li>在登录时执行命令：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh user@remotehost <span class="string">&#x27;command_to_run&#x27;</span></span><br></pre></td></tr></table></figure><ul><li>使用密钥文件进行身份验证：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -i /path/to/private_key user@remotehost</span><br></pre></td></tr></table></figure><ul><li>进行端口转发：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -L local_port:remotehost:remote_port user@remotehost</span><br></pre></td></tr></table></figure><ul><li>复制文件到远程主机（使用 <code>scp</code>）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">scp localfile.txt user@remotehost:/path/to/destination</span><br></pre></td></tr></table></figure><h2 id="tail"><a href="#tail" class="headerlink" title="tail"></a>tail</h2><p><code>tail</code> 命令用于显示文件的结尾部分，默认情况下显示最后 10 行。</p><h3 id="用法示例-25"><a href="#用法示例-25" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">tail</span> filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会打印 <code>filename.txt</code> 文件的最后 10 行。</p><h3 id="常见用法-25"><a href="#常见用法-25" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>显示指定行数的结尾部分：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">tail</span> -n 5 filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会打印 <code>filename.txt</code> 文件的最后 5 行。</p><ul><li>实时查看文件的新增内容（类似于日志文件）：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">tail</span> -f filename.txt</span><br></pre></td></tr></table></figure><ul><li>显示多个文件的结尾部分：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">tail</span> file1.txt file2.txt</span><br></pre></td></tr></table></figure><ul><li>显示文件的字节数：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">tail</span> -c 20 filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会打印 <code>filename.txt</code> 文件的最后 20 个字节。</p><h2 id="tar"><a href="#tar" class="headerlink" title="tar"></a>tar</h2><p><code>tar</code> 命令用于打包和压缩文件，常用于备份和传输文件。</p><h3 id="用法示例-26"><a href="#用法示例-26" class="headerlink" title="用法示例"></a>用法示例</h3><ul><li>创建一个 tar 包：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -cvf archive.tar /path/to/directory</span><br></pre></td></tr></table></figure><p>这个命令会将指定目录打包成 <code>archive.tar</code> 文件。</p><h3 id="常见用法-26"><a href="#常见用法-26" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>创建一个压缩的 tar.gz 包：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -czvf archive.tar.gz /path/to/directory</span><br></pre></td></tr></table></figure><p>这个命令会将指定目录打包并压缩成 <code>archive.tar.gz</code> 文件。</p><ul><li>解压 tar 包：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -xvf archive.tar</span><br></pre></td></tr></table></figure><p>这个命令会解压 <code>archive.tar</code> 文件。</p><ul><li>解压 tar.gz 包：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -xzvf archive.tar.gz</span><br></pre></td></tr></table></figure><p>这个命令会解压 <code>archive.tar.gz</code> 文件。</p><ul><li>查看 tar 包内容：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -tvf archive.tar</span><br></pre></td></tr></table></figure><p>这个命令会列出 <code>archive.tar</code> 文件中的内容。</p><h2 id="top"><a href="#top" class="headerlink" title="top"></a>top</h2><p><code>top</code> 命令用于实时显示系统中正在运行的进程和系统资源的使用情况。</p><h3 id="用法示例-27"><a href="#用法示例-27" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">top</span><br></pre></td></tr></table></figure><p>这个命令会打开一个动态更新的界面，显示当前系统的进程信息和资源使用情况。</p><h3 id="常见用法-27"><a href="#常见用法-27" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li><p>显示进程的详细信息：<br>在 <code>top</code> 界面中，可以按 <code>Shift + M</code> 按内存使用量排序，按 <code>Shift + P</code> 按 CPU 使用量排序。</p></li><li><p>结束进程：<br>在 <code>top</code> 界面中，按 <code>k</code> 键，然后输入要结束的进程 ID（PID），最后按 <code>Enter</code>。</p></li><li><p>刷新间隔：<br>在 <code>top</code> 界面中，按 <code>d</code> 键可以设置刷新间隔（以秒为单位）。</p></li><li><p>显示帮助信息：<br>在 <code>top</code> 界面中，按 <code>h</code> 键可以查看帮助信息。</p></li><li><p>退出 <code>top</code>：<br>在 <code>top</code> 界面中，按 <code>q</code> 键可以退出。</p></li></ul><h2 id="touch"><a href="#touch" class="headerlink" title="touch"></a>touch</h2><p><code>touch</code> 命令用于创建空文件或更新文件的时间戳。</p><h3 id="用法示例-28"><a href="#用法示例-28" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会创建一个名为 <code>filename.txt</code> 的空文件，如果文件已存在，则更新其最后修改时间。</p><h3 id="常见用法-28"><a href="#常见用法-28" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>创建多个空文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> file1.txt file2.txt file3.txt</span><br></pre></td></tr></table></figure><ul><li>更新文件的时间戳：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> existingfile.txt</span><br></pre></td></tr></table></figure><ul><li>创建带有特定时间戳的文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> -t 202301010101 filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会将 <code>filename.txt</code> 的时间戳设置为 2023 年 1 月 1 日 01:01。</p><ul><li>使用当前时间戳创建文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> -a filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会更新 <code>filename.txt</code> 的访问时间为当前时间。</p><h2 id="vi"><a href="#vi" class="headerlink" title="vi"></a>vi</h2><p><code>vi</code> 是一个强大的文本编辑器，广泛用于 Unix 和 Linux 系统中。</p><h3 id="用法示例-29"><a href="#用法示例-29" class="headerlink" title="用法示例"></a>用法示例</h3><p>打开文件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会打开 <code>filename.txt</code> 文件进行编辑。</p><h3 id="常见用法-29"><a href="#常见用法-29" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li><p>进入插入模式：<br>在命令模式下，按 <code>i</code> 进入插入模式，可以开始编辑文本。</p></li><li><p>保存并退出：<br>在命令模式下，输入 <code>:wq</code> 保存文件并退出 <code>vi</code>。</p></li><li><p>仅保存：<br>在命令模式下，输入 <code>:w</code> 仅保存文件而不退出。</p></li><li><p>退出不保存：<br>在命令模式下，输入 <code>:q!</code> 强制退出而不保存更改。</p></li><li><p>删除行：<br>在命令模式下，输入 <code>dd</code> 删除当前行。</p></li><li><p>撤销操作：<br>在命令模式下，输入 <code>u</code> 撤销上一步操作。</p></li><li><p>查找文本：<br>在命令模式下，输入 <code>/pattern</code> 查找指定的 <code>pattern</code>。</p></li><li><p>替换文本：<br>在命令模式下，输入 <code>:%s/old/new/g</code> 将文件中的所有 <code>old</code> 替换为 <code>new</code>。</p></li></ul><h2 id="vim"><a href="#vim" class="headerlink" title="vim"></a>vim</h2><p><code>vim</code> 是 <code>vi</code> 的增强版，提供了更多功能和更好的用户体验。</p><h3 id="用法示例-30"><a href="#用法示例-30" class="headerlink" title="用法示例"></a>用法示例</h3><p>打开文件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim filename.txt</span><br></pre></td></tr></table></figure><p>这个命令会打开 <code>filename.txt</code> 文件进行编辑。</p><h3 id="常见用法-30"><a href="#常见用法-30" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li><p>进入插入模式：<br>在命令模式下，按 <code>i</code> 进入插入模式，可以开始编辑文本。</p></li><li><p>保存并退出：<br>在命令模式下，输入 <code>:wq</code> 保存文件并退出 <code>vim</code>。</p></li><li><p>仅保存：<br>在命令模式下，输入 <code>:w</code> 仅保存文件而不退出。</p></li><li><p>退出不保存：<br>在命令模式下，输入 <code>:q!</code> 强制退出而不保存更改。</p></li><li><p>删除行：<br>在命令模式下，输入 <code>dd</code> 删除当前行。</p></li><li><p>撤销操作：<br>在命令模式下，输入 <code>u</code> 撤销上一步操作。</p></li><li><p>查找文本：<br>在命令模式下，输入 <code>/pattern</code> 查找指定的 <code>pattern</code>。</p></li><li><p>替换文本：<br>在命令模式下，输入 <code>:%s/old/new/g</code> 将文件中的所有 <code>old</code> 替换为 <code>new</code>。</p></li><li><p>显示行号：<br>在命令模式下，输入 <code>:set number</code> 显示行号。</p></li><li><p>语法高亮：<br>在命令模式下，输入 <code>:syntax on</code> 启用语法高亮。</p></li></ul><h2 id="wget"><a href="#wget" class="headerlink" title="wget"></a>wget</h2><p><code>wget</code> 是一个用于从网络下载文件的命令行工具，支持 HTTP、HTTPS 和 FTP 协议。</p><h3 id="用法示例-31"><a href="#用法示例-31" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget http://example.com/file.txt</span><br></pre></td></tr></table></figure><p>这个命令会从指定的 URL 下载 <code>file.txt</code> 文件。</p><h3 id="常见用法-31"><a href="#常见用法-31" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>下载文件并指定输出文件名：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -O newname.txt http://example.com/file.txt</span><br></pre></td></tr></table></figure><ul><li>递归下载整个网站：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -r http://example.com</span><br></pre></td></tr></table></figure><ul><li>限制下载速度：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget --limit-rate=200k http://example.com/file.txt</span><br></pre></td></tr></table></figure><ul><li>继续未完成的下载：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -c http://example.com/file.txt</span><br></pre></td></tr></table></figure><ul><li>下载时不显示进度条：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -q http://example.com/file.txt</span><br></pre></td></tr></table></figure><ul><li>下载多个文件：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -i filelist.txt</span><br></pre></td></tr></table></figure><p>这个命令会从 <code>filelist.txt</code> 文件中读取 URL 并下载。</p><h2 id="xargs"><a href="#xargs" class="headerlink" title="xargs"></a>xargs</h2><p><code>xargs</code> 命令用于将标准输入的数据转换为命令行参数，常用于处理大量数据。</p><h3 id="用法示例-32"><a href="#用法示例-32" class="headerlink" title="用法示例"></a>用法示例</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&quot;file1.txt file2.txt file3.txt&quot;</span> | xargs <span class="built_in">rm</span></span><br></pre></td></tr></table></figure><p>这个命令会删除 <code>file1.txt</code>、<code>file2.txt</code> 和 <code>file3.txt</code> 文件。</p><h3 id="常见用法-32"><a href="#常见用法-32" class="headerlink" title="常见用法"></a>常见用法</h3><ul><li>从文件中读取参数：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xargs -a filelist.txt <span class="built_in">rm</span></span><br></pre></td></tr></table></figure><p>这个命令会从 <code>filelist.txt</code> 文件中读取文件名并删除它们。</p><ul><li>限制每次执行的命令参数数量：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find . -name <span class="string">&quot;*.txt&quot;</span> | xargs -n 2 <span class="built_in">rm</span></span><br></pre></td></tr></table></figure><p>这个命令会每次删除两个 <code>.txt</code> 文件。</p><ul><li>使用自定义分隔符：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&quot;file1.txt,file2.txt,file3.txt&quot;</span> | xargs -d <span class="string">&#x27;,&#x27;</span> <span class="built_in">rm</span></span><br></pre></td></tr></table></figure><p>这个命令会使用逗号作为分隔符来删除文件。</p><ul><li>与其他命令结合使用：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find . -name <span class="string">&quot;*.log&quot;</span> | xargs grep <span class="string">&quot;error&quot;</span></span><br></pre></td></tr></table></figure><p>这个命令会在所有 <code>.log</code> 文件中搜索包含 “error” 的行。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;alias&quot;&gt;&lt;a href=&quot;#alias&quot; class=&quot;headerlink&quot; title=&quot;alias&quot;&gt;&lt;/a&gt;alias&lt;/h2&gt;&lt;p&gt;&lt;code&gt;alias&lt;/code&gt; 命令用于为命令创建别名，以便简化输入和提高效率。&lt;/p&gt;
&lt;h3 id=&quot;用法</summary>
      
    
    
    
    
    <category term="linux" scheme="https://mangon.cn/blog/tags/linux/"/>
    
  </entry>
  
  <entry>
    <title>React19版本新增功能</title>
    <link href="https://mangon.cn/blog/2025/01/01/React-React19%E7%89%88%E6%9C%AC%E6%96%B0%E5%A2%9E%E5%8A%9F%E8%83%BD/"/>
    <id>https://mangon.cn/blog/2025/01/01/React-React19%E7%89%88%E6%9C%AC%E6%96%B0%E5%A2%9E%E5%8A%9F%E8%83%BD/</id>
    <published>2025-01-01T10:00:00.000Z</published>
    <updated>2026-01-22T02:59:11.705Z</updated>
    
    <content type="html"><![CDATA[<p>React 19 于2024年12月正式发布，带来了许多重要功能和改进。这次更新延续了 React 团队专注于提升开发体验和性能的目标，引入了多项新特性，使 React 应用开发变得更加简单和高效。</p><span id="more"></span><h2 id="主要新功能"><a href="#主要新功能" class="headerlink" title="主要新功能"></a>主要新功能</h2><h3 id="Actions"><a href="#Actions" class="headerlink" title="Actions"></a>Actions</h3><p>React 19引入了”Actions”的概念，这是一个重要的数据突变处理模式。在以前的版本中，当用户提交表单或执行数据修改操作时，开发者需要手动处理等待状态(pending states)、错误处理、乐观更新和连续请求等问题。</p><p>例如，在React 19之前，处理表单提交需要这样：</p><figure class="highlight jsx"><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">// Before Actions</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">UpdateName</span>(<span class="params">&#123;&#125;</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> [name, setName] = <span class="title function_">useState</span>(<span class="string">&#x27;&#x27;</span>);</span><br><span class="line">  <span class="keyword">const</span> [error, setError] = <span class="title function_">useState</span>(<span class="literal">null</span>);</span><br><span class="line">  <span class="keyword">const</span> [isPending, setIsPending] = <span class="title function_">useState</span>(<span class="literal">false</span>);</span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">handleSubmit</span> = <span class="keyword">async</span> (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="title function_">setIsPending</span>(<span class="literal">true</span>);</span><br><span class="line">    <span class="keyword">const</span> error = <span class="keyword">await</span> <span class="title function_">updateName</span>(name);</span><br><span class="line">    <span class="title function_">setIsPending</span>(<span class="literal">false</span>);</span><br><span class="line">    <span class="keyword">if</span> (error) &#123;</span><br><span class="line">      <span class="title function_">setError</span>(error);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">redirect</span>(<span class="string">&#x27;/path&#x27;</span>);</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">input</span> <span class="attr">value</span>=<span class="string">&#123;name&#125;</span> <span class="attr">onChange</span>=<span class="string">&#123;event</span> =&gt;</span> setName(event.target.value)&#125; /&gt;</span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">&#123;handleSubmit&#125;</span> <span class="attr">disabled</span>=<span class="string">&#123;isPending&#125;</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        Update</span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      &#123;error &amp;&amp; <span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;error&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span>&#125;</span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在React 19中，通过使用异步转换(Actions)，可以自动处理这些状态：</p><figure class="highlight jsx"><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">// Using pending state from Actions</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">UpdateName</span>(<span class="params">&#123;&#125;</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> [name, setName] = <span class="title function_">useState</span>(<span class="string">&#x27;&#x27;</span>);</span><br><span class="line">  <span class="keyword">const</span> [error, setError] = <span class="title function_">useState</span>(<span class="literal">null</span>);</span><br><span class="line">  <span class="keyword">const</span> [isPending, startTransition] = <span class="title function_">useTransition</span>();</span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">handleSubmit</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="title function_">startTransition</span>(<span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line">      <span class="keyword">const</span> error = <span class="keyword">await</span> <span class="title function_">updateName</span>(name);</span><br><span class="line">      <span class="keyword">if</span> (error) &#123;</span><br><span class="line">        <span class="title function_">setError</span>(error);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title function_">redirect</span>(<span class="string">&#x27;/path&#x27;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">input</span> <span class="attr">value</span>=<span class="string">&#123;name&#125;</span> <span class="attr">onChange</span>=<span class="string">&#123;event</span> =&gt;</span> setName(event.target.value)&#125; /&gt;</span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">&#123;handleSubmit&#125;</span> <span class="attr">disabled</span>=<span class="string">&#123;isPending&#125;</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        Update</span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      &#123;error &amp;&amp; <span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;error&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span>&#125;</span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Actions自动管理以下方面：</p><ul><li>待定状态(Pending state)：在请求开始时自动设置待定状态，并在最终状态更新提交后自动重置</li><li>乐观更新：支持useOptimistic钩子，可在请求提交期间向用户提供即时反馈</li><li>错误处理：提供错误处理功能，可以在请求失败时显示错误边界，并自动将乐观更新恢复到原始值</li><li>表单：<form>元素现在支持将函数传递给action和formAction属性</li></ul><h3 id="useActionState-钩子"><a href="#useActionState-钩子" class="headerlink" title="useActionState 钩子"></a>useActionState 钩子</h3><p>为了简化 Actions 的常见用法，React 19 引入了 useActionState 钩子：</p><figure class="highlight jsx"><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">const</span> [error, submitAction, isPending] = <span class="title function_">useActionState</span>(<span class="keyword">async</span> (previousState, newName) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> error = <span class="keyword">await</span> <span class="title function_">updateName</span>(newName);</span><br><span class="line">  <span class="keyword">if</span> (error) &#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="keyword">return</span> error;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 处理成功情况</span></span><br><span class="line">  <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">&#125;, <span class="literal">null</span>);</span><br></pre></td></tr></table></figure><h3 id="React-DOM-中的表单-Actions"><a href="#React-DOM-中的表单-Actions" class="headerlink" title="React DOM 中的表单 Actions"></a>React DOM 中的表单 Actions</h3><p>Actions 还集成了 React 19 中 react-dom 的新表单功能。现在支持将函数作为 <code>&lt;form&gt;</code>、<code>&lt;input&gt;</code> 和 <code>&lt;button&gt;</code> 元素的 action 和 formAction 属性值，以自动使用 Actions 提交表单：</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;form action=&#123;actionFunction&#125;&gt;</span><br></pre></td></tr></table></figure><p>当表单 Action 成功时，React 将自动为非受控组件重置表单。</p><h3 id="useFormStatus-钩子"><a href="#useFormStatus-钩子" class="headerlink" title="useFormStatus 钩子"></a>useFormStatus 钩子</h3><p>在设计系统中，通常需要编写需要访问其所在表单信息的设计组件，而不需要将 props 层层传递下去。为此，React 19 引入了 useFormStatus 钩子：</p><figure class="highlight jsx"><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="keyword">import</span> &#123; useFormStatus &#125; <span class="keyword">from</span> <span class="string">&#x27;react-dom&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">DesignButton</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; pending &#125; = <span class="title function_">useFormStatus</span>();</span><br><span class="line">  <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> <span class="attr">type</span>=<span class="string">&#x27;submit&#x27;</span> <span class="attr">disabled</span>=<span class="string">&#123;pending&#125;</span> /&gt;</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="useOptimistic-钩子"><a href="#useOptimistic-钩子" class="headerlink" title="useOptimistic 钩子"></a>useOptimistic 钩子</h3><p>另一个常见的 UI 模式是在执行数据变更时，在异步请求进行的同时显示最终状态。React 19 引入了 useOptimistic 钩子来简化这一过程：</p><figure class="highlight jsx"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">ChangeName</span>(<span class="params">&#123; currentName, onUpdateName &#125;</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> [optimisticName, setOptimisticName] = <span class="title function_">useOptimistic</span>(currentName);</span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">submitAction</span> = <span class="keyword">async</span> formData =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> newName = formData.<span class="title function_">get</span>(<span class="string">&#x27;name&#x27;</span>);</span><br><span class="line">    <span class="title function_">setOptimisticName</span>(newName);</span><br><span class="line">    <span class="keyword">const</span> updatedName = <span class="keyword">await</span> <span class="title function_">updateName</span>(newName);</span><br><span class="line">    <span class="title function_">onUpdateName</span>(updatedName);</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&#123;submitAction&#125;</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">p</span>&gt;</span>Your name is: &#123;optimisticName&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>Change Name:<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&#x27;text&#x27;</span> <span class="attr">name</span>=<span class="string">&#x27;name&#x27;</span> <span class="attr">disabled</span>=<span class="string">&#123;currentName</span> !== <span class="string">optimisticName&#125;</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="use-API"><a href="#use-API" class="headerlink" title="use API"></a>use API</h3><p>React 19 引入了新的 use API 来读取渲染中的资源。例如，可以使用 use 读取 Promise，React 将暂停直到 Promise 解析：</p><figure class="highlight jsx"><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">import</span> &#123; use &#125; <span class="keyword">from</span> <span class="string">&#x27;react&#x27;</span>;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Comments</span>(<span class="params">&#123; commentsPromise &#125;</span>) &#123;</span><br><span class="line">  <span class="comment">// `use`将暂停直到Promise解析</span></span><br><span class="line">  <span class="keyword">const</span> comments = <span class="title function_">use</span>(commentsPromise);</span><br><span class="line">  <span class="keyword">return</span> comments.<span class="title function_">map</span>(<span class="function"><span class="params">comment</span> =&gt;</span> <span class="language-xml"><span class="tag">&lt;<span class="name">p</span> <span class="attr">key</span>=<span class="string">&#123;comment.id&#125;</span>&gt;</span>&#123;comment&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Page</span>(<span class="params">&#123; commentsPromise &#125;</span>) &#123;</span><br><span class="line">  <span class="comment">// 当Comments中的`use`暂停时，</span></span><br><span class="line">  <span class="comment">// 将显示此Suspense边界</span></span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">Suspense</span> <span class="attr">fallback</span>=<span class="string">&#123;</span>&lt;<span class="attr">div</span>&gt;</span>Loading...<span class="tag">&lt;/<span class="name">div</span>&gt;</span>&#125;&gt;</span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">Comments</span> <span class="attr">commentsPromise</span>=<span class="string">&#123;commentsPromise&#125;</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">Suspense</span>&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>use</code> API 还可以读取上下文，允许有条件地读取 Context，例如在早期返回之后：</p><figure class="highlight jsx"><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">import</span> &#123; use &#125; <span class="keyword">from</span> <span class="string">&#x27;react&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">ThemeContext</span> <span class="keyword">from</span> <span class="string">&#x27;./ThemeContext&#x27;</span>;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Heading</span>(<span class="params">&#123; children &#125;</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (children == <span class="literal">null</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">  <span class="comment">// 这不能与useContext一起使用</span></span><br><span class="line">  <span class="comment">// 因为有早期返回</span></span><br><span class="line">  <span class="keyword">const</span> theme = <span class="title function_">use</span>(<span class="title class_">ThemeContext</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">h1</span> <span class="attr">style</span>=<span class="string">&#123;&#123;</span> <span class="attr">color:</span> <span class="attr">theme.color</span> &#125;&#125;&gt;</span>&#123;children&#125;<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="重要改进"><a href="#重要改进" class="headerlink" title="重要改进"></a>重要改进</h2><h3 id="React编译器"><a href="#React编译器" class="headerlink" title="React编译器"></a>React编译器</h3><p>React 19 的明星功能是新的 React 编译器。这个编译器将 React 代码转换为纯 JavaScript，提升性能，并免除手动优化的麻烦。编译器能够自动优化重新渲染，减少手动使用 useMemo、useCallback 和 memo API的需求。</p><h3 id="性能改进"><a href="#性能改进" class="headerlink" title="性能改进"></a>性能改进</h3><p>React 19 引入了新的性能优化，包括对 React 组件和 React DOM 的优化。这些改进包括：</p><ul><li>更好的并发渲染</li><li>改进的协调算法</li><li>选择性水合(Selective hydration)</li><li>预热暂停树(Pre-warming for suspended trees)</li></ul><h3 id="服务器端渲染-SSR-改进"><a href="#服务器端渲染-SSR-改进" class="headerlink" title="服务器端渲染(SSR)改进"></a>服务器端渲染(SSR)改进</h3><p>React 19 增强了服务器端渲染功能，包括：</p><ul><li>更好的Web Streams支持</li><li>改进的水合过程</li><li>更快的初始加载时间</li></ul><h3 id="错误处理改进"><a href="#错误处理改进" class="headerlink" title="错误处理改进"></a>错误处理改进</h3><p>React 19 改进了错误处理机制，包括改进的错误信息和错误处理方式。引入了新的错误处理方法，使调试更加容易。</p><h3 id="静态API改进"><a href="#静态API改进" class="headerlink" title="静态API改进"></a>静态API改进</h3><p>React 19 引入了新的 React DOM 静态API，这些 API 有助于在构建时预渲染应用的部分内容。</p><h2 id="迁移注意事项"><a href="#迁移注意事项" class="headerlink" title="迁移注意事项"></a>迁移注意事项</h2><p>React 19 引入了一些重大变更，需要注意：</p><ol><li>JSX 转换要求：React 19 强制使用新的 JSX 转换</li><li>旧版 API 删除：<code>ReactDOM.render</code> 和 <code>ReactDOM.hydrate</code> 等API已被删除，替换为 <code>ReactDOM.createRoot</code> 和 <code>ReactDOM.hydrateRoot</code></li><li>错误处理变化：React 19 引入了新的错误处理方法</li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>React 19 是一个重要的更新，它专注于简化开发过程并提升性能。通过引入 Actions、新的 Hooks 和改进的 API，React 19 使得数据突变处理、表单管理和状态管理变得更加直观和高效。</p><p>此外，React 编译器的引入标志着 React 在自动优化方面的重大进步，有望显著提升应用性能，同时减少开发者手动优化的工作量。</p><p>总的来说，React 19 继续贯彻了 React 团队的承诺——在不增加复杂性的情况下提供更多功能，让开发者能够构建更高效、更可靠的 Web 应用程序。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;React 19 于2024年12月正式发布，带来了许多重要功能和改进。这次更新延续了 React 团队专注于提升开发体验和性能的目标，引入了多项新特性，使 React 应用开发变得更加简单和高效。&lt;/p&gt;</summary>
    
    
    
    <category term="javascript" scheme="https://mangon.cn/blog/categories/javascript/"/>
    
    
    <category term="react" scheme="https://mangon.cn/blog/tags/react/"/>
    
  </entry>
  
  <entry>
    <title>前端常用node包</title>
    <link href="https://mangon.cn/blog/2023/09/27/FE-%E5%89%8D%E7%AB%AF%E5%B8%B8%E8%A7%81node%E5%8C%85/"/>
    <id>https://mangon.cn/blog/2023/09/27/FE-%E5%89%8D%E7%AB%AF%E5%B8%B8%E8%A7%81node%E5%8C%85/</id>
    <published>2023-09-27T10:59:39.000Z</published>
    <updated>2023-10-07T00:55:20.457Z</updated>
    
    <content type="html"><![CDATA[<p>以下列举了一些前端常见node包，包括项目中引入的包和编译使用到的包，排除了知名的框架库、UI库或者工具库。开发用常见于 package.json 的 dependency 中，编译用常见于 package.json 的 devDependecy 中。</p><p>开发用：<br><a href="https://github.com/MikeMcl/big.js#readme">big.js</a>: A small, fast, easy-to-use library for arbitrary-precision decimal arithmetic<br><a href="https://github.com/thlorenz/brace">brace</a>: browserify compatible version of the ace editor.<br><a href="https://github.com/JedWatson/classnames#readme">classnames</a>: A simple utility for conditionally joining classNames together<br><a href="https://github.com/nodeca/pako#readme">pako</a>: zlib port to javascript - fast, modularized, with browser support<br><a href="http://github.com/brix/crypto-js">crypto-js</a>: JavaScript library of crypto standards.<br><a href="https://day.js.org">day.js</a>: 2KB immutable date time library alternative to Moment.js with the same modern API<br><a href="https://github.com/tsayen/dom-to-image#readme">dom-to-image</a>: Generates an image from a DOM node using HTML5 canvas and SVG<br><a href="https://echarts.apache.org">echarts</a>: Apache ECharts is a powerful, interactive charting and data visualization library for browser<br><a href="https://github.com/ecomfe/echarts-gl#readme">echarts-gl</a>: Extension pack of ECharts providing 3D plots and globe visualization<br><a href="http://www.travistidwell.com/jsencrypt">encryptlong</a>: js encrypt<br><a href="https://github.com/eligrey/FileSaver.js#readme">file-saver</a>: An HTML5 saveAs() FileSaver implementation<br><a href="https://handsontable.com/">handsontable</a>: Handsontable is a JavaScript Spreadsheet Component available for React, Angular and Vue.<br><a href="mutate a copy of data without changing the original source">immutability-helper</a>: https://github.com/kolodny/immutability-helper#readme<br><a href="https://github.com/localForage/localForage">localForage</a>: Offline storage, improved.<br><a href="https://lodash.com/">lodash</a>: Lodash modular utilities.</p><p>编译用：</p><p><a href="https://github.com/kentcdodds/cross-env">cross-env</a>: Run scripts that set and use environment variables across platforms<br><a href="https://eslint.org">eslint</a>: An AST-based pattern checker for JavaScript.<br><a href="https://typicode.github.io/husky">husky</a>: Modern native Git hooks made easy<br><a href="https://prettier.io">prettier</a>: Prettier is an opinionated code formatter<br><a href="https://stylelint.io">stylelint</a>: A mighty CSS linter that helps you avoid errors and enforce conventions.<br><a href="https://github.com/cssnano/cssnano">cssnano</a>: A modular minifier, built on top of the PostCSS ecosystem.<br><a href="https://github.com/postcss/autoprefixer#readme">autoprefixer</a>: Parse CSS and add vendor prefixes to CSS rules using values from the Can I Use website<br><a href="https://github.com/browserify/commonjs-assert">assert</a>: The assert module from Node.js, for the browser.<br><a href="https://github.com/feross/buffer">buffer</a>: Node.js Buffer API, for the browser<br><a href="https://github.com/chalk/chalk#readme">chalk</a>: Terminal string styling done right<br><a href="https://github.com/crypto-browserify/crypto-browserify">crypto-browserify</a>: implementation of crypto for the browser<br><a href="https://github.com/devongovett/browserify-zlib">browserify-zlib</a>: Full zlib module for the browser<br><a href="https://github.com/jprichardson/node-fs-extra">fs-extra</a>: fs-extra contains methods that aren’t included in the vanilla Node.js fs package. Such as recursive mkdir, copy, and remove.<br><a href="https://github.com/sindresorhus/get-port#readme">get-port</a>: Get an available port<br><a href="https://github.com/isaacs/node-glob#readme">glob</a>: the most correct and second fastest glob implementation in JavaScript<br><a href="https://github.com/indutny/node-ip">ip</a>: IP address tools for node.js<br><a href="https://github.com/minimistjs/minimist">minimist</a>: parse argument options<br><a href="https://github.com/browserify/path-browserify">path-browserify</a>: the path module from node core for browsers<br><a href="https://github.com/browserify/stream-browserify">stream-browserify</a>: the stream module from node core for browsers<br><a href="https://github.com/defunctzombie/node-url#readme">url</a>: The core <code>url</code> packaged standalone for use with Browserify.<br><a href="https://github.com/browserify/node-util">util</a>: Node.js’s util module for all engines<br><a href="https://github.com/substack/vm-browserify#readme">vm</a>: vm module for the browser<br><a href="https://github.com/SBoudrias/Inquirer.js">inquirer</a>: A collection of common interactive command line user interfaces.<br><a href="https://github.com/ZJONSSON/node-unzipper#readme">unzipper</a>: Unzip cross-platform streaming API<br><a href="https://github.com/isaacs/rimraf">rimraf</a>: The UNIX command <code>rm -rf</code> for node.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;以下列举了一些前端常见node包，包括项目中引入的包和编译使用到的包，排除了知名的框架库、UI库或者工具库。开发用常见于 package.json 的 dependency 中，编译用常见于 package.json 的 devDependecy 中。&lt;/p&gt;
&lt;p&gt;开发用</summary>
      
    
    
    
    
    <category term="node" scheme="https://mangon.cn/blog/tags/node/"/>
    
    <category term="software" scheme="https://mangon.cn/blog/tags/software/"/>
    
  </entry>
  
  <entry>
    <title>软件包管理工具</title>
    <link href="https://mangon.cn/blog/2023/09/25/CS-%E8%BD%AF%E4%BB%B6%E5%8C%85%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7/"/>
    <id>https://mangon.cn/blog/2023/09/25/CS-%E8%BD%AF%E4%BB%B6%E5%8C%85%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7/</id>
    <published>2023-09-25T11:31:28.000Z</published>
    <updated>2025-01-22T08:04:24.870Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Homebrew"><a href="#Homebrew" class="headerlink" title="Homebrew"></a>Homebrew</h2><p><a href="https://brew.sh/">Homebrew</a> 是 macOS 上最流行的软件包管理工具，允许用户轻松安装和管理软件包。<br><a href="https://github.com/Homebrew">Homebrew</a></p><h3 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h3><ul><li>简单易用，命令直观。</li><li>拥有丰富的软件库。</li><li>社区活跃，更新频繁。</li></ul><h3 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h3><ul><li>主要针对 macOS，Windows 支持有限。</li><li>某些软件包可能不够稳定。</li></ul><h2 id="Chocolatey"><a href="#Chocolatey" class="headerlink" title="Chocolatey"></a>Chocolatey</h2><p><a href="https://chocolatey.org/">Chocolatey</a> 是 Windows 平台上的软件包管理工具，基于 NuGet。<br><a href="https://github.com/chocolatey">Chocolatey</a></p><h3 id="优点-1"><a href="#优点-1" class="headerlink" title="优点"></a>优点</h3><ul><li>支持大量 Windows 软件。</li><li>可以通过命令行轻松安装和更新软件。</li><li>与 Windows PowerShell 集成良好。</li></ul><h3 id="缺点-1"><a href="#缺点-1" class="headerlink" title="缺点"></a>缺点</h3><ul><li>依赖于 .NET Framework。</li><li>有些软件包可能需要额外配置。</li></ul><h2 id="Scoop"><a href="#Scoop" class="headerlink" title="Scoop"></a>Scoop</h2><p><a href="https://scoop.sh/">Scoop</a> 是一个 Windows 软件包管理工具，提供了命令行式的安装过程。<br><a href="https://github.com/ScoopInstaller/scoop">Scoop</a></p><h3 id="优点-2"><a href="#优点-2" class="headerlink" title="优点"></a>优点</h3><ul><li>安装过程简单，不需要管理员权限。</li><li>支持从 GitHub 等源安装软件。</li><li>轻量级，易于使用。</li></ul><h3 id="缺点-2"><a href="#缺点-2" class="headerlink" title="缺点"></a>缺点</h3><ul><li>软件库相对较小。</li><li>主要针对开发者，普通用户可能不太友好。</li></ul><h2 id="APT"><a href="#APT" class="headerlink" title="APT"></a>APT</h2><p><a href="https://wiki.debian.org/Apt">APT</a>（Advanced Package Tool）是 Debian 和 Ubuntu 系统的包管理工具。常用命令为 <code>apt-get</code>。<br><a href="https://github.com/Debian/apt">APT</a></p><h3 id="优点-3"><a href="#优点-3" class="headerlink" title="优点"></a>优点</h3><ul><li>提供强大的依赖管理。</li><li>软件库丰富，更新频繁。</li><li>支持图形界面和命令行操作。</li></ul><h3 id="缺点-3"><a href="#缺点-3" class="headerlink" title="缺点"></a>缺点</h3><ul><li>主要针对 Debian 系列的 Linux 发行版。</li><li>对于新手用户，命令行操作可能有一定学习曲线。</li></ul><h2 id="YUM"><a href="#YUM" class="headerlink" title="YUM"></a>YUM</h2><p><a href="https://yum.baseurl.org/">YUM</a>（Yellowdog Updater, Modified）是 Red Hat 和 CentOS 系统的包管理工具。</p><h3 id="优点-4"><a href="#优点-4" class="headerlink" title="优点"></a>优点</h3><ul><li>支持自动解决依赖关系。</li><li>提供丰富的软件库。</li><li>可以通过命令行轻松管理软件包。</li></ul><h3 id="缺点-4"><a href="#缺点-4" class="headerlink" title="缺点"></a>缺点</h3><ul><li>主要针对 Red Hat 系列的 Linux 发行版。</li><li>在某些情况下，更新速度可能较慢。</li></ul><h2 id="NPM"><a href="#NPM" class="headerlink" title="NPM"></a>NPM</h2><p>NPM（Node Package Manager）是 Node.js 的包管理工具。</p><h3 id="优点-5"><a href="#优点-5" class="headerlink" title="优点"></a>优点</h3><ul><li>拥有庞大的 JavaScript 库。</li><li>支持快速安装和更新 Node.js 包。</li><li>与 Node.js 生态系统紧密集成。</li></ul><h3 id="缺点-5"><a href="#缺点-5" class="headerlink" title="缺点"></a>缺点</h3><ul><li>依赖管理有时可能会出现问题。</li><li>对于大型项目，可能会导致依赖树过于复杂。</li></ul><h2 id="cURL"><a href="#cURL" class="headerlink" title="cURL"></a>cURL</h2><p><a href="https://curl.se/">cURL</a> 是一个命令行数据传输工具，它支持 DICT、FILE、FTP、FTPS、Gopher、HTTP、HTTPS、IMAP、IMAPS、LDAP、LDAPS、POP3、POP3S、RTMP、RTSP、SCP、SFTP、SMB、SMBS、SMTP、SMTPS、Telnet 与 TFTP 等协议。<br><a href="https://github.com/curl/curl">cURL</a></p><h3 id="优点-6"><a href="#优点-6" class="headerlink" title="优点"></a>优点</h3><ul><li>支持多种协议，灵活性高。</li><li>可以处理复杂的请求，如表单提交和文件上传。</li><li>支持代理和认证。</li></ul><h3 id="缺点-6"><a href="#缺点-6" class="headerlink" title="缺点"></a>缺点</h3><ul><li>对新手用户可能不太友好，学习曲线较陡。</li><li>在某些情况下，错误信息不够明确。</li></ul><h2 id="wget"><a href="#wget" class="headerlink" title="wget"></a>wget</h2><p><a href="https://www.gnu.org/software/wget/">wget</a> 是 linux 上的命令行下载工具。这是一个 GPL 许可证下的自由软件。wget 支持 HTTP 和 FTP 协议，支持代理服务器和断点续传功能，能够自动递归远程主机的目录，找到合乎条件的文件并将其下载到本地硬盘上；如果必要，wget 将恰当地转换页面中的超链接以在本地生成可浏览的镜像。</p><p><a href="https://github.com/mirror/wget">wget</a></p><h3 id="优点-7"><a href="#优点-7" class="headerlink" title="优点"></a>优点</h3><ul><li>简单易用，适合批量下载。</li><li>支持断点续传，下载中断后可以继续。</li><li>可以递归下载整个网站。</li></ul><h3 id="缺点-7"><a href="#缺点-7" class="headerlink" title="缺点"></a>缺点</h3><ul><li>对于复杂的请求支持有限。</li><li>处理 HTTPS 时可能需要额外配置。</li></ul><h2 id="aira2"><a href="#aira2" class="headerlink" title="aira2"></a>aira2</h2><p><a href="https://github.com/aria2/aria2">aria2</a>是一个轻量级的多协议、多源、跨平台下载实用程序，在命令行中运行。它支持 HTTP/HTTPS、FTP、SFTP、BitTorrent 和 Metalink 。</p><h2 id="比较"><a href="#比较" class="headerlink" title="比较"></a>比较</h2><ul><li><strong>平台支持</strong>：Homebrew 主要用于 macOS，Chocolatey 和 Scoop 主要用于 Windows，APT 和 YUM 主要用于 Linux，NPM 主要用于 Node.js。</li><li><strong>易用性</strong>：Homebrew 和 Scoop 的安装过程相对简单，而 Chocolatey 和 APT 需要一些额外的配置。</li><li><strong>软件库</strong>：Homebrew 和 NPM 的软件库最为丰富，Chocolatey、APT 和 YUM 的软件库也相对较大，而 Scoop 的软件库较小。</li><li><strong>社区支持</strong>：Homebrew 和 NPM 拥有最活跃的社区，更新频繁。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Homebrew&quot;&gt;&lt;a href=&quot;#Homebrew&quot; class=&quot;headerlink&quot; title=&quot;Homebrew&quot;&gt;&lt;/a&gt;Homebrew&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt; 是 macO</summary>
      
    
    
    
    
    <category term="package" scheme="https://mangon.cn/blog/tags/package/"/>
    
    <category term="installer" scheme="https://mangon.cn/blog/tags/installer/"/>
    
  </entry>
  
  <entry>
    <title>glob通配符</title>
    <link href="https://mangon.cn/blog/2023/09/25/CS-glob%E9%80%9A%E9%85%8D%E7%AC%A6/"/>
    <id>https://mangon.cn/blog/2023/09/25/CS-glob%E9%80%9A%E9%85%8D%E7%AC%A6/</id>
    <published>2023-09-25T08:52:57.000Z</published>
    <updated>2023-10-07T00:51:25.879Z</updated>
    
    <content type="html"><![CDATA[<p>Unix 早期版本的命令解释器依赖于一个单独的程序来将未引用参数中的通配符扩展为命令：<code>/etc/glob</code>。该程序执行了扩展，并将扩展后的文件路径列表提供给命令执行。其名称是“global command”的缩写。后来，这个功能被提供为库函数 <code>glob()</code>，由 shell 等程序使用。</p><p>glob 通配符早于正则表达式出现，没有正则表达式强大，但提供了简单方便的功用于匹配符合指定模式的文件集合。</p><p>glog 通配符现在常用于执行 <em>命令行</em> 例如 <code>ls *.js</code> 或者在一些 ignore 文件，例如 <code>.gitignore</code> 中，或者用到路径匹配功能的工具，例如代理工具 whistle 支持 glob 路径匹配。</p><h2 id="glob-语法"><a href="#glob-语法" class="headerlink" title="glob 语法"></a>glob 语法</h2><table><thead><tr><th>通配符</th><th>描述</th><th>例子</th><th>匹配</th><th>不匹配</th></tr></thead><tbody><tr><td><code>*</code></td><td>匹配任意数量的任何字符，包括无字符</td><td><code>Law*</code></td><td>Law, Laws, Lawyer</td><td>GrokLaw, La, aw</td></tr><tr><td><code>?</code></td><td>匹配任何 <strong>单个</strong> 字符</td><td><code>?at</code></td><td>Cat, cat, Bat, bat</td><td>at</td></tr><tr><td><code>**</code></td><td>匹配任意数量的文件夹和子文件夹</td><td></td><td></td></tr><tr><td><code>[abc]</code></td><td>匹配括号中给出的一个字符</td><td><code>[CB]at</code></td><td>Cat, Bat</td><td>cat, bat</td></tr><tr><td><code>[a-z]</code></td><td>匹配括号中给出的范围中的一个字符</td><td><code>Letter[0-9]</code></td><td>Letter0, Letter1 … Letter9</td><td>Letters, Letter, Letter10</td></tr><tr><td><code>[!abc]</code> 或 <code>[^abc]</code></td><td>匹配括号中未给出的一个字符</td><td><code>[!C]at</code></td><td>Bat, bat, cat</td><td>Cat</td></tr><tr><td><code>[!a-z]</code></td><td>匹配不在括号内给定范围内的一个字符</td><td><code>Letter[!3-5]</code></td><td>Letter1…</td><td>Letter3 … Letter5, Letterxx</td></tr><tr><td><code>&#123;a,b&#125;</code></td><td>匹配括号中给出的多个字符/通配符</td><td><code>&#123;C,B&#125;at</code></td><td>Cat, Bat</td><td>cat, bat</td></tr><tr><td><code>&#123;start..end&#125;</code></td><td>会匹配连续范围的字符</td><td><code>d&#123;a..d&#125;g</code></td><td>dag, dbg, dcg, ddg</td></tr></tbody></table><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li>通配符是先解释，再执行<br>Bash 接收到命令以后，发现里面有通配符，会进行通配符扩展，然后再执行命令。<figure class="highlight bash"><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="built_in">ls</span> a*.txt</span><br><span class="line">ab.txt</span><br></pre></td></tr></table></figure>上面命令的执行过程是，Bash 先将 <code>a*.txt</code> 扩展成 <code>ab.txt</code> ，然后再执行 <code>ls ab.txt</code>。</li><li>通配符不匹配，会原样输出<br>Bash 扩展通配符的时候，发现不存在匹配的文件，会将通配符原样输出。<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="comment"># 不存在 r 开头的文件名</span></span><br><span class="line">$ <span class="built_in">echo</span> r*</span><br><span class="line">r*</span><br></pre></td></tr></table></figure>上面代码中，由于不存在 r 开头的文件名，<code>r*</code> 会原样输出。</li><li>只适用于单层路径<br>上面所有通配符只匹配单层路径，不能跨目录匹配，即无法匹配子目录里面的文件。或者说，<code>?</code> 或 <code>*</code> 这样的通配符，不能匹配路径分隔符 <code>（/）</code>。<br>如果要匹配子目录里面的文件，可以写成下面这样：<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">ls</span> */*.txt</span><br></pre></td></tr></table></figure></li><li>可用于文件名<br>Bash 允许文件名使用通配符。这时，引用文件名的时候，需要把文件名放在单引号里面。<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">touch</span> <span class="string">&#x27;fo*&#x27;</span></span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">fo*</span><br></pre></td></tr></table></figure></li></ol><h2 id="gitignore"><a href="#gitignore" class="headerlink" title="gitignore"></a>gitignore</h2><p>git 中的 .gitignore 文件可以使用 glob 模式匹配，另外还有一些规则：</p><ul><li>所有空行或者以 <code>#</code> 开头的行都会被 Git 忽略</li><li>匹配模式可以以 <code>/</code> 开头防止递归</li><li>匹配模式可以以 <code>/</code> 结尾指定目录</li><li>要忽略指定模式以外的文件或目录，可以在模式前加上惊叹号 <code>!</code> 取反</li></ul><h2 id="vite"><a href="#vite" class="headerlink" title="vite"></a>vite</h2><p>Vite 支持使用特殊的 <code>import.meta.glob</code> 函数从文件系统导入多个模块：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> modules = <span class="keyword">import</span>.<span class="property">meta</span>.<span class="title function_">glob</span>(<span class="string">&#x27;./dir/*.js&#x27;</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><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// vite 生成的代码</span></span><br><span class="line"><span class="keyword">const</span> modules = &#123;</span><br><span class="line">  <span class="string">&#x27;./dir/foo.js&#x27;</span>: <span class="function">() =&gt;</span> <span class="keyword">import</span>(<span class="string">&#x27;./dir/foo.js&#x27;</span>),</span><br><span class="line">  <span class="string">&#x27;./dir/bar.js&#x27;</span>: <span class="function">() =&gt;</span> <span class="keyword">import</span>(<span class="string">&#x27;./dir/bar.js&#x27;</span>)</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>你可以遍历 modules 对象的 key 值来访问相应的模块：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">const</span> path <span class="keyword">in</span> modules) &#123;</span><br><span class="line">  modules[path]().<span class="title function_">then</span>(<span class="function"><span class="params">mod</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(path, mod);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>匹配到的文件默认是懒加载的，通过动态导入实现，并会在构建时分离为独立的 chunk。如果你倾向于直接引入所有的模块（例如依赖于这些模块中的副作用首先被应用），你可以传入 <code>&#123; eager: true &#125;</code> 作为第二个参数：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> modules = <span class="keyword">import</span>.<span class="property">meta</span>.<span class="title function_">glob</span>(<span class="string">&#x27;./dir/*.js&#x27;</span>, &#123; <span class="attr">eager</span>: <span class="literal">true</span> &#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></pre></td><td class="code"><pre><span class="line"><span class="comment">// vite 生成的代码</span></span><br><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> __glob__0_0 <span class="keyword">from</span> <span class="string">&#x27;./dir/foo.js&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> __glob__0_1 <span class="keyword">from</span> <span class="string">&#x27;./dir/bar.js&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> modules = &#123;</span><br><span class="line">  <span class="string">&#x27;./dir/foo.js&#x27;</span>: __glob__0_0,</span><br><span class="line">  <span class="string">&#x27;./dir/bar.js&#x27;</span>: __glob__0_1</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="相关-node-库"><a href="#相关-node-库" class="headerlink" title="相关 node 库"></a>相关 node 库</h2><p>https://github.com/mrmlnc/fast-glob<br>https://github.com/isaacs/node-glob<br>https://github.com/sindresorhus/globby</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Unix 早期版本的命令解释器依赖于一个单独的程序来将未引用参数中的通配符扩展为命令：&lt;code&gt;/etc/glob&lt;/code&gt;。该程序执行了扩展，并将扩展后的文件路径列表提供给命令执行。其名称是“global command”的缩写。后来，这个功能被提供为库函数 &lt;co</summary>
      
    
    
    
    
    <category term="unix" scheme="https://mangon.cn/blog/tags/unix/"/>
    
    <category term="glob" scheme="https://mangon.cn/blog/tags/glob/"/>
    
    <category term="gitignore" scheme="https://mangon.cn/blog/tags/gitignore/"/>
    
  </entry>
  
  <entry>
    <title>Pinia小抄</title>
    <link href="https://mangon.cn/blog/2023/09/22/Vue-Pinia%E5%B0%8F%E6%8A%84/"/>
    <id>https://mangon.cn/blog/2023/09/22/Vue-Pinia%E5%B0%8F%E6%8A%84/</id>
    <published>2023-09-22T05:54:32.000Z</published>
    <updated>2023-09-25T11:14:04.330Z</updated>
    
    <content type="html"><![CDATA[<p>Pinia (<code>/piːnjʌ/</code>)是一款类型安全、可扩展以及模块化设计的 Vue.js 状态管理库。</p><h2 id="Pinia-应用示例"><a href="#Pinia-应用示例" class="headerlink" title="Pinia 应用示例"></a>Pinia 应用示例</h2><p>通过 <code>defineStore</code> 先创建一个 Store:</p><figure class="highlight js"><figcaption><span>stores/counter.js</span></figcaption><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="keyword">import</span> &#123; defineStore &#125; <span class="keyword">from</span> <span class="string">&#x27;pinia&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> useCounterStore = <span class="title function_">defineStore</span>(<span class="string">&#x27;counter&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">state</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123; <span class="attr">count</span>: <span class="number">0</span> &#125;;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 也可以这样定义</span></span><br><span class="line">  <span class="comment">// state: () =&gt; (&#123; count: 0 &#125;)</span></span><br><span class="line">  <span class="attr">actions</span>: &#123;</span><br><span class="line">    <span class="title function_">increment</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">count</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><p>在组件中引入该 Store 并使用：</p><figure class="highlight plaintext"><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">&lt;script setup&gt;</span><br><span class="line">// setup() 函数</span><br><span class="line">import &#123; useCounterStore &#125; from &#x27;@/stores/counter&#x27;;</span><br><span class="line">const counter = useCounterStore();</span><br><span class="line">counter.count++;</span><br><span class="line">// 自动补全</span><br><span class="line">counter.$patch(&#123; count: counter.count + 1 &#125;);</span><br><span class="line">// 或使用 action 代替</span><br><span class="line">counter.increment();</span><br><span class="line">&lt;/script&gt;</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;!-- 直接从 store 中访问 state --&gt;</span><br><span class="line">  &lt;div&gt;Current Count: &#123;&#123; counter.count &#125;&#125;&lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure><p>Pinia 也提供了一组类似 Vuex 的映射 state 的辅助函数：</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="keyword">const</span> useCounterStore = <span class="title function_">defineStore</span>(<span class="string">&#x27;counter&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">state</span>: <span class="function">() =&gt;</span> (&#123; <span class="attr">count</span>: <span class="number">0</span> &#125;),</span><br><span class="line">  <span class="attr">getters</span>: &#123;</span><br><span class="line">    <span class="attr">double</span>: <span class="function"><span class="params">state</span> =&gt;</span> state.<span class="property">count</span> * <span class="number">2</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">actions</span>: &#123;</span><br><span class="line">    <span class="title function_">increment</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">count</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">const</span> useUserStore = <span class="title function_">defineStore</span>(<span class="string">&#x27;user&#x27;</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="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span><br><span class="line">  <span class="attr">computed</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">// 允许访问 this.counterStore 和 this.userStore</span></span><br><span class="line">    ...<span class="title function_">mapStores</span>(useCounterStore, useUserStore),</span><br><span class="line">    <span class="comment">// 允许读取 this.count 和 this.double</span></span><br><span class="line">    ...<span class="title function_">mapState</span>(useCounterStore, [<span class="string">&#x27;count&#x27;</span>, <span class="string">&#x27;double&#x27;</span>])</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="comment">// 允许读取 this.increment()</span></span><br><span class="line">    ...<span class="title function_">mapActions</span>(useCounterStore, [<span class="string">&#x27;increment&#x27;</span>])</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="Pinia-应用方式"><a href="#Pinia-应用方式" class="headerlink" title="Pinia 应用方式"></a>Pinia 应用方式</h2><p>使用包管理器安装 Pinia:</p><ul><li>Yarn: <code>yarn add pinia</code></li><li>NPM: <code>npm install pinia</code></li></ul><p>Pinia 使用到了组合式 API，如果你是用的 Vue&lt;2.7版本，还需要安装组合式API包： <code>@vue/composition-api</code> 。</p><p>在 Vue3 中，创建一个 pinia 实例 并将其传递给应用：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; createApp &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; createPinia &#125; <span class="keyword">from</span> <span class="string">&#x27;pinia&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">App</span> <span class="keyword">from</span> <span class="string">&#x27;./App.vue&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> pinia = <span class="title function_">createPinia</span>();</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">createApp</span>(<span class="title class_">App</span>);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">use</span>(pinia);</span><br><span class="line">app.<span class="title function_">mount</span>(<span class="string">&#x27;#app&#x27;</span>);</span><br></pre></td></tr></table></figure><p>在 Vue2 中，还需要安装一个插件：</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">import</span> &#123; createPinia, <span class="title class_">PiniaVuePlugin</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;pinia&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Vue</span>.<span class="title function_">use</span>(<span class="title class_">PiniaVuePlugin</span>);</span><br><span class="line"><span class="keyword">const</span> pinia = <span class="title function_">createPinia</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span><br><span class="line">  <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</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">// 请注意，同一个`pinia&#x27;实例</span></span><br><span class="line">  <span class="comment">// 可以在同一个页面的多个 Vue 应用中使用。</span></span><br><span class="line">  pinia</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="Pinia-概念"><a href="#Pinia-概念" class="headerlink" title="Pinia 概念"></a>Pinia 概念</h2><h3 id="Store"><a href="#Store" class="headerlink" title="Store"></a>Store</h3><p>Store 是一个保存状态和业务逻辑的实体，它并不与你的组件树绑定，承载着全局状态。一个 Store 应该包含可以在整个应用中访问的数据，你应该避免在 Store 中引入那些原本可以在组件中保存的本地数据。</p><p>Store 是用 <code>defineStore()</code> 定义的，它的第一个参数要求是一个唯一的名字，用作id，返回一个函数，为了符合组合式函数风格，通常命名为 <code>use&lt;id&gt;Store</code>。<code>defineStore()</code> 的第二个参数可接受两类值：Setup 函数或 Option 对象</p><p>当第二个参数使用 Option 对象时，可以传入一个带有 <code>state</code> 、<code>action</code>、<code>getters</code> 属性的 Option 对象。</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">export</span> <span class="keyword">const</span> useCounterStore = <span class="title function_">defineStore</span>(<span class="string">&#x27;counter&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">state</span>: <span class="function">() =&gt;</span> (&#123; <span class="attr">count</span>: <span class="number">0</span> &#125;),</span><br><span class="line">  <span class="attr">getters</span>: &#123;</span><br><span class="line">    <span class="attr">double</span>: <span class="function"><span class="params">state</span> =&gt;</span> state.<span class="property">count</span> * <span class="number">2</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">actions</span>: &#123;</span><br><span class="line">    <span class="title function_">increment</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">count</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><p>第二个参数使用 Setup 函数时，该函数定义了一些响应式属性和方法，并且返回一个带有我们想暴露出去的属性和方法的对象：</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">export</span> <span class="keyword">const</span> useCounterStore = <span class="title function_">defineStore</span>(<span class="string">&#x27;counter&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> count = <span class="title function_">ref</span>(<span class="number">0</span>);</span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">increment</span>(<span class="params"></span>) &#123;</span><br><span class="line">    count.<span class="property">value</span>++;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> &#123; count, increment &#125;;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>在 Setup Store 中：</p><ul><li><code>ref()</code> 就是 <code>state</code> 属性</li><li><code>computed()</code> 就是 <code>getters</code></li><li><code>function()</code> 就是 <code>actions</code></li></ul><p>Store 在使用 <code>&lt;script setup&gt;</code> 调用 <code>useStore()</code> (或者调用 <code>setup()</code> 函数)时，会被创建。</p><figure class="highlight plaintext"><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">&lt;script setup&gt;</span><br><span class="line">import &#123; useCounterStore &#125; from &#x27;@/stores/counter&#x27;;</span><br><span class="line">// 可以在组件中的任意位置访问 `store` 变量</span><br><span class="line">const store = useCounterStore();</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>为了从 store 中提取属性时保持其响应性，你需要使用 <code>storeToRefs()</code>，它将为每一个响应式属性创建引用。</p><figure class="highlight plaintext"><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">&lt;script setup&gt;</span><br><span class="line">import &#123; storeToRefs &#125; from &#x27;pinia&#x27;;</span><br><span class="line">const store = useCounterStore();</span><br><span class="line">// `name` 和 `doubleCount` 是响应式的 ref</span><br><span class="line">// 同时通过插件添加的属性也会被提取为 ref</span><br><span class="line">// 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性</span><br><span class="line">const &#123; name, doubleCount &#125; = storeToRefs(store);</span><br><span class="line">// 作为 action 的 increment 可以直接解构</span><br><span class="line">const &#123; increment &#125; = store;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="State"><a href="#State" class="headerlink" title="State"></a>State</h3><p>state 被定义为一个返回初始状态的函数，代表了应用中的状态。</p><p>默认情况下，可以通过 <code>store</code> 实例访问 state，并进行读写。</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="keyword">const</span> store = <span class="title function_">useStore</span>();</span><br><span class="line">store.<span class="property">count</span>++;</span><br></pre></td></tr></table></figure><p>使用选项式 API 时，可以通过调用 <code>$reset</code> 方法将 state 重置。</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="keyword">const</span> store = <span class="title function_">useStore</span>();</span><br><span class="line">store.$reset();</span><br></pre></td></tr></table></figure><p>可以通过调用 <code>$patch</code> 方法同时修改多个属性：</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></pre></td><td class="code"><pre><span class="line">store.$patch(&#123;</span><br><span class="line">  <span class="attr">count</span>: store.<span class="property">count</span> + <span class="number">1</span>,</span><br><span class="line">  <span class="attr">age</span>: <span class="number">120</span>,</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;DIO&#x27;</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p><code>$patch</code> 方法也接受一个函数来对集合进行修改：</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">store.$patch(<span class="function"><span class="params">state</span> =&gt;</span> &#123;</span><br><span class="line">  state.<span class="property">items</span>.<span class="title function_">push</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;shoes&#x27;</span>, <span class="attr">quantity</span>: <span class="number">1</span> &#125;);</span><br><span class="line">  state.<span class="property">hasChanged</span> = <span class="literal">true</span>;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>你不能完全替换掉 store 的 state，因为那样会破坏其响应性。但是，你可以通过 <code>$patch</code> 方法替换它：</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="comment">// 这实际上并没有替换`$state`</span></span><br><span class="line">store.<span class="property">$state</span> = &#123; <span class="attr">count</span>: <span class="number">24</span> &#125;;</span><br><span class="line"><span class="comment">// 在它内部调用 `$patch()`：</span></span><br><span class="line">store.$patch(&#123; <span class="attr">count</span>: <span class="number">24</span> &#125;);</span><br></pre></td></tr></table></figure><p>你可以通过 store 的 <code>$subscribe</code> 方法侦听 state 及其变化,相当于组件中的 <code>watch()</code>, 比起普通的 <code>watch()</code>，使用 <code>$subscribe()</code> 的好处是 subscriptions 在 patch 后只触发一次 (例如，当使用上面的函数版本时)。</p><h3 id="Getter"><a href="#Getter" class="headerlink" title="Getter"></a>Getter</h3><p>Getter 完全等同于 store 的 state 的计算值（computed value）。推荐使用箭头函数，并且它将接收 <code>state</code> 作为第一个参数。在使用常规函数定义 getter 时，我们也可以通过 this 访问到整个 store 实例，从而访问其他 getter。</p><p>你可以访问其他 store 的 getter:</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">import</span> &#123; useOtherStore &#125; <span class="keyword">from</span> <span class="string">&#x27;./other-store&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> useStore = <span class="title function_">defineStore</span>(<span class="string">&#x27;main&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">state</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 class="attr">getters</span>: &#123;</span><br><span class="line">    <span class="title function_">otherGetter</span>(<span class="params">state</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> otherStore = <span class="title function_">useOtherStore</span>();</span><br><span class="line">      <span class="keyword">return</span> state.<span class="property">localData</span> + otherStore.<span class="property">data</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><h3 id="Action"><a href="#Action" class="headerlink" title="Action"></a>Action</h3><p>Action 相当于组件中的 method，它们定义了业务逻辑。action 也可通过 this 访问整个 store 实例。action 也可以是异步的，可以像函数或方法一样被调用，也可以在另一个 store 的 action 中被调用。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; useAuthStore &#125; <span class="keyword">from</span> <span class="string">&#x27;./auth-store&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> useSettingsStore = <span class="title function_">defineStore</span>(<span class="string">&#x27;settings&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">state</span>: <span class="function">() =&gt;</span> (&#123;</span><br><span class="line">    <span class="attr">preferences</span>: <span class="literal">null</span></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">  &#125;),</span><br><span class="line">  <span class="attr">actions</span>: &#123;</span><br><span class="line">    <span class="keyword">async</span> <span class="title function_">fetchUserPreferences</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> auth = <span class="title function_">useAuthStore</span>();</span><br><span class="line">      <span class="keyword">if</span> (auth.<span class="property">isAuthenticated</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">preferences</span> = <span class="keyword">await</span> <span class="title function_">fetchPreferences</span>();</span><br><span class="line">      &#125; <span class="keyword">else</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;User must be authenticated&#x27;</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></pre></td></tr></table></figure><p>你可以通过 <code>store.$onAction()</code> 来监听 action 和他们的结果。传递给它的回调函数会在 action 本身之前执行。<code>after</code> 允许在 promise 解决之后执行回调函数。onError 允许在 action 抛出错误或 reject 时执行回调函数。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> unsubscribe = someStore.$onAction(</span><br><span class="line">  <span class="function">(<span class="params">&#123;</span></span></span><br><span class="line"><span class="params"><span class="function">    name, // action 名称</span></span></span><br><span class="line"><span class="params"><span class="function">    store, // store 实例，类似 <span class="string">`someStore`</span></span></span></span><br><span class="line"><span class="params"><span class="function">    args, // 传递给 action 的参数数组</span></span></span><br><span class="line"><span class="params"><span class="function">    after, // 在 action 返回或解决后的钩子</span></span></span><br><span class="line"><span class="params"><span class="function">    onError // action 抛出或拒绝的钩子</span></span></span><br><span class="line"><span class="params"><span class="function">  &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 为这个特定的 action 调用提供一个共享变量</span></span><br><span class="line">    <span class="keyword">const</span> startTime = <span class="title class_">Date</span>.<span class="title function_">now</span>();</span><br><span class="line">    <span class="comment">// 这将在执行 &quot;store &quot;的 action 之前触发。</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Start &quot;<span class="subst">$&#123;name&#125;</span>&quot; with params [<span class="subst">$&#123;args.join(<span class="string">&#x27;, &#x27;</span>)&#125;</span>].`</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 这将在 action 成功并完全运行后触发。</span></span><br><span class="line">    <span class="comment">// 它等待着任何返回的 promise</span></span><br><span class="line">    <span class="title function_">after</span>(<span class="function"><span class="params">result</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Finished &quot;<span class="subst">$&#123;name&#125;</span>&quot; after <span class="subst">$&#123;<span class="built_in">Date</span>.now() - startTime&#125;</span>ms.\nResult: <span class="subst">$&#123;result&#125;</span>.`</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 如果 action 抛出或返回一个拒绝的 promise，这将触发</span></span><br><span class="line">    <span class="title function_">onError</span>(<span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">warn</span>(<span class="string">`Failed &quot;<span class="subst">$&#123;name&#125;</span>&quot; after <span class="subst">$&#123;<span class="built_in">Date</span>.now() - startTime&#125;</span>ms.\nError: <span class="subst">$&#123;error&#125;</span>.`</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 手动删除监听器</span></span><br><span class="line"><span class="title function_">unsubscribe</span>();</span><br></pre></td></tr></table></figure><h2 id="Pinia-插件"><a href="#Pinia-插件" class="headerlink" title="Pinia 插件"></a>Pinia 插件</h2><p>Pinia 支持通过 <code>pinia.use()</code> 添加插件，Pinia 插件是一个函数，可以选择性地返回要添加到 store 的属性。它接收一个可选参数，即 context：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; createPinia &#125; <span class="keyword">from</span> <span class="string">&#x27;pinia&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建的每个 store 中都会添加一个名为 `secret` 的属性。</span></span><br><span class="line"><span class="comment">// 在安装此插件后，插件可以保存在不同的文件中</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">SecretPiniaPlugin</span>(<span class="params">context</span>) &#123;</span><br><span class="line">  <span class="comment">// context.pinia // 用 `createPinia()` 创建的 pinia。</span></span><br><span class="line">  <span class="comment">// context.app // 用 `createApp()` 创建的当前应用(仅 Vue 3)。</span></span><br><span class="line">  <span class="comment">// context.store // 该插件想扩展的 store</span></span><br><span class="line">  <span class="comment">// context.options // 定义传给 `defineStore()` 的 store 的可选对象。</span></span><br><span class="line">  <span class="keyword">return</span> &#123; <span class="attr">secret</span>: <span class="string">&#x27;the cake is a lie&#x27;</span> &#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> pinia = <span class="title function_">createPinia</span>();</span><br><span class="line"><span class="comment">// 将该插件交给 Pinia</span></span><br><span class="line">pinia.<span class="title function_">use</span>(<span class="title class_">SecretPiniaPlugin</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在另一个文件中</span></span><br><span class="line"><span class="keyword">const</span> store = <span class="title function_">useStore</span>();</span><br><span class="line">store.<span class="property">secret</span>; <span class="comment">// &#x27;the cake is a lie&#x27;</span></span><br></pre></td></tr></table></figure><p>以下为插件可扩展的内容：</p><ul><li>为 store 添加新的属性</li><li>定义 store 时增加新的选项</li><li>为 store 增加新的方法</li><li>包装现有的方法</li><li>改变甚至取消 action</li><li>实现副作用，如本地存储</li><li>仅应用插件于特定 store</li></ul><p>当添加外部属性、第三方库的类实例或非响应式的简单值时，你应该先用 markRaw() 来包装一下它，再将它传给 pinia。下面是一个在每个 store 中添加路由器的例子：</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">import</span> &#123; markRaw &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span>;</span><br><span class="line"><span class="comment">// 根据你的路由器的位置来调整</span></span><br><span class="line"><span class="keyword">import</span> &#123; router &#125; <span class="keyword">from</span> <span class="string">&#x27;./router&#x27;</span>;</span><br><span class="line"></span><br><span class="line">pinia.<span class="title function_">use</span>(<span class="function">(<span class="params">&#123; store &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">  store.<span class="property">router</span> = <span class="title function_">markRaw</span>(router);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="Pinia-与-Vuex-区别"><a href="#Pinia-与-Vuex-区别" class="headerlink" title="Pinia 与 Vuex 区别"></a>Pinia 与 Vuex 区别</h2><p>Pinia 是 Vue3 推荐的状态管理库，而 Vuex 将不再更迭，从事件顺序上看，Pinia 可以看做是 Vuex5 。</p><ol><li>Pinia 提供了更简单的 API，也提供了符合组合式 API 风格的 API，搭配 Typescript 一起使用时有可靠的类型推断支持。</li><li>Pinia API 已经稳定，新功能需要经过 RFC 流程。Vuex 不再更新。</li><li>Vuex3.x 只适配 Vue2，Vuex 4.x 适配 Vue3, Pinia 适配 Vue3 和 Vue2。</li><li>Pinia 没有 mutation，Vuex 中使用 mutation 记录数据的更新。<br>Pinia 在 action 执行完成后会自动发布给订阅者，所以不需要 mutation。</li><li>Pinia 无需要创建自定义的复杂包装器来支持 TypeScript。</li><li>Pinia 无过多的魔法字符串注入，只需要导入函数并调用它们。</li><li>Pinia 无需动态添加 Store，默认即是动态的。</li><li>Pinia 不再有嵌套结构的模块，提供扁平的 Store 结构。</li><li>Pinia 不再有可命名的模块。</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Pinia (&lt;code&gt;/piːnjʌ/&lt;/code&gt;)是一款类型安全、可扩展以及模块化设计的 Vue.js 状态管理库。&lt;/p&gt;
&lt;h2 id=&quot;Pinia-应用示例&quot;&gt;&lt;a href=&quot;#Pinia-应用示例&quot; class=&quot;headerlink&quot; title=&quot;Pi</summary>
      
    
    
    
    
    <category term="vue" scheme="https://mangon.cn/blog/tags/vue/"/>
    
    <category term="vue3" scheme="https://mangon.cn/blog/tags/vue3/"/>
    
    <category term="pinia" scheme="https://mangon.cn/blog/tags/pinia/"/>
    
  </entry>
  
  <entry>
    <title>MobX小抄</title>
    <link href="https://mangon.cn/blog/2023/09/21/React-MobX%E5%B0%8F%E6%8A%84/"/>
    <id>https://mangon.cn/blog/2023/09/21/React-MobX%E5%B0%8F%E6%8A%84/</id>
    <published>2023-09-21T08:53:10.000Z</published>
    <updated>2026-01-21T03:29:15.003Z</updated>
    
    <content type="html"><![CDATA[<p>MobX 是一款简单可扩展的状态管理库。它通过运用透明的函数式响应编程（Transparent Functional Reactive Programming，TFRP）使状态管理变得简单和可扩展。</p><h2 id="MobX-应用示例"><a href="#MobX-应用示例" class="headerlink" title="MobX 应用示例"></a>MobX 应用示例</h2><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="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">&#x27;react&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">ReactDOM</span> <span class="keyword">from</span> <span class="string">&#x27;react-dom&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; makeAutoObservable &#125; <span class="keyword">from</span> <span class="string">&#x27;mobx&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; observer &#125; <span class="keyword">from</span> <span class="string">&#x27;mobx-react&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 对应用状态进行建模。</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Timer</span> &#123;</span><br><span class="line">  secondsPassed = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">makeAutoObservable</span>(<span class="variable language_">this</span>);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">increase</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">secondsPassed</span> += <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">reset</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">secondsPassed</span> = <span class="number">0</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="comment">// 生成应用状态实例</span></span><br><span class="line"><span class="keyword">const</span> myTimer = <span class="keyword">new</span> <span class="title class_">Timer</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 构建一个使用 observable 状态的“用户界面”。</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">TimerView</span> = <span class="title function_">observer</span>(<span class="function">(<span class="params">&#123; timer &#125;</span>) =&gt;</span> (</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">&#123;()</span> =&gt;</span> timer.reset()&#125;&gt;已过秒数：&#123;timer.secondsPassed&#125;<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line">));</span><br><span class="line"></span><br><span class="line"><span class="title class_">ReactDOM</span>.<span class="title function_">render</span>(<span class="language-xml"><span class="tag">&lt;<span class="name">TimerView</span> <span class="attr">timer</span>=<span class="string">&#123;myTimer&#125;</span> /&gt;</span></span>, <span class="variable language_">document</span>.<span class="property">body</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 每秒更新一次‘已过秒数：X’中的文本。</span></span><br><span class="line"><span class="built_in">setInterval</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  myTimer.<span class="title function_">increase</span>();</span><br><span class="line">&#125;, <span class="number">1000</span>);</span><br></pre></td></tr></table></figure><p>围绕 React 组件 <code>TimerView</code> 的 <code>observer</code> 包装会自动侦测到依赖于 observable <code>timer.secondsPassed</code> 的渲染——即使这种依赖关系没有被明确定义出来。 响应性系统会负责在未来恰好那个字段被更新的时候将组件重新渲染。<br>每个事件（<code>onClick</code> 或 <code>setInterval</code>）都会调用一个用来更新 observable 状态 <code>myTimer.secondsPassed</code> 的 action（<code>myTimer.increase</code> 或 <code>myTimer.reset</code>）。Observable 状态的变更会被精确地传送到 <code>TimerView</code> 中所有依赖于它们的计算和副作用里。</p><p>状态流转概念图如下所示：</p><p><img src="/blog/static/imgs/mobx/mobxflow.png" alt="mobx_inner"></p><h2 id="MobX-应用方式"><a href="#MobX-应用方式" class="headerlink" title="MobX 应用方式"></a>MobX 应用方式</h2><p>MobX 有两种 React 绑定方式，其中 <code>mobx-react-lite</code> 仅支持函数组件，<code>mobx-react</code> 还支持基于类的组件。可以使用 Yarn、NPM、CDN 集成 MobX 到项目中：</p><ul><li>Yarn: <code>yarn add mobx</code></li><li>NPM: <code>npm install --save mobx</code></li><li>CDN: https://cdnjs.com/libraries/mobx 或者 https://unpkg.com/mobx/dist/mobx.umd.production.min.js</li></ul><p>因为使用到了类属性特性，在与 Typescript 或 Babel 一起使用时且计划使用类时，需要转换类字段。</p><ul><li><p>Babel: 需要使用版本&gt;7.12 同时开启以下配置</p><figure class="highlight json"><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="punctuation">&#123;</span></span><br><span class="line">  <span class="comment">// Babel &lt; 7.13.0</span></span><br><span class="line">  <span class="attr">&quot;plugins&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">[</span><span class="string">&quot;@babel/plugin-proposal-class-properties&quot;</span><span class="punctuation">,</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;loose&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span> <span class="punctuation">&#125;</span><span class="punctuation">]</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// Babel &gt;= 7.13.0 (https://babeljs.io/docs/en/assumptions)</span></span><br><span class="line">  <span class="attr">&quot;plugins&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">[</span><span class="string">&quot;@babel/plugin-proposal-class-properties&quot;</span><span class="punctuation">]</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;assumptions&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;setPublicClassFields&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></li><li><p>Typescript: 在 tsconfig.json 中启用编译器选项 <code>&quot;useDefineForClassFields&quot;: true</code></p></li></ul><p>MobX 使用到了 Proxy 特性，如果在不支持 Proxy 特性的运行时上使用 MobX ，需要明确启用降级方案：</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="keyword">import</span> &#123; configure &#125; <span class="keyword">from</span> <span class="string">&#x27;mobx&#x27;</span>;</span><br><span class="line"><span class="title function_">configure</span>(&#123; <span class="attr">useProxies</span>: <span class="string">&#x27;never&#x27;</span> &#125;); <span class="comment">// Or &quot;ifavailable&quot;.</span></span><br></pre></td></tr></table></figure><p>在 MobX6 中，为了与标准 Javascript 兼容，放弃了装饰器语法，如果需要使用 <code>@observable</code> 等装饰器，需要明确启用同时使用 Typescript 或 Babel 进行转译：</p><ul><li>Typescript：在 tsconfig.json 中启用编译器选项 <code>&quot;experimentalDecorators&quot;: true</code> 和 <code>&quot;useDefineForClassFields&quot;: true</code>。</li><li>Babel: 使用 <code>@babel/plugin-proposal-class-properties</code> 和 <code>@babel/plugin-proposal-decorators</code> 插件，配置：</li></ul><figure class="highlight json"><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="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;plugins&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">[</span><span class="string">&quot;@babel/plugin-proposal-decorators&quot;</span><span class="punctuation">,</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;legacy&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span> <span class="punctuation">&#125;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">[</span><span class="string">&quot;@babel/plugin-proposal-class-properties&quot;</span><span class="punctuation">,</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;loose&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span> <span class="punctuation">&#125;</span><span class="punctuation">]</span></span><br><span class="line">    <span class="comment">// 与MobX 4/5不同的是, &quot;loose&quot; 必须为 false!    ^</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h2 id="MobX-概念"><a href="#MobX-概念" class="headerlink" title="MobX 概念"></a>MobX 概念</h2><p>MobX区分了应用程序中的以下三个概念：</p><ul><li>State(状态)</li><li>Actions(动作)</li><li>Derivations(派生)</li></ul><p>State(状态): 是驱动你的应用程序的数据。通常来说，状态有领域 <em>特定状态</em> 和 <em>视图状态</em>。State 可以使用任何数据结构，但是需要被标记为 <code>observable</code> 从而使 MobX 可跟踪它。<br>Action(动作) : 是任意可以改变 State(状态) 的代码，比如用户事件处理、后端推送数据处理、调度器事件处理等等。<br>Derivation(派生): 任何来源是 State(状态) 并且不需要进一步交互的东西都是 Derivation(派生)。<br>Mobx 区分了两种 Derivation :</p><ul><li>Computed values：总是可以通过纯函数从当前的可观测 State 中派生</li><li>Reactions：当 State 改变时需要自动运行的副作用 (命令式编程和响应式编程之间的桥梁)</li></ul><h2 id="MobX-数据流向"><a href="#MobX-数据流向" class="headerlink" title="MobX 数据流向"></a>MobX 数据流向</h2><p>Mobx 使用单向数据流，利用 action 改变 state ，进而更新所有受影响的 view:</p><p><img src="/blog/static/imgs/mobx/mobx.png" alt="mobx_inner"></p><ol><li>所有的 derivations 将在 state 改变时<em>自动且原子化地更新</em>。因此不能观察中间值。</li><li>所有的 derivations 默认将会<em>同步</em>更新，这意味着 action 可以在 state 改变之后安全的直接获得 computed value。</li><li>computed value 的更新是<em>惰性</em>的，任何 computed value 在需要他们的副作用发生之前都是不激活的。</li><li>所有的 computed value 都应是<em>纯函数</em>，他们不应该修改 state。</li></ol><h2 id="MobX核心"><a href="#MobX核心" class="headerlink" title="MobX核心"></a>MobX核心</h2><h3 id="创建可观察-observable-state"><a href="#创建可观察-observable-state" class="headerlink" title="创建可观察(observable) state"></a>创建可观察(observable) state</h3><h4 id="makeObservable"><a href="#makeObservable" class="headerlink" title="makeObservable"></a>makeObservable</h4><p>用法： <code>makeObservable(target, annotations?, options?)</code></p><p><code>makeObservable</code> 为每个属性指定一个注解:</p><ul><li><code>observable</code> 定义一个存储 state 的可追踪字段。</li><li><code>action</code> 将一个方法标记为可以修改 state 的 action。</li><li><code>computed</code> 标记一个可以由 state 派生出新的值并且缓存其输出的 getter。</li><li><code>flow</code> 创建一个 flow 管理异步进程。</li><li><code>override</code> 用于子类覆盖继承的 <code>action</code>，<code>flow</code>，<code>computed</code>，<code>action.bound</code></li><li><code>autoAction</code> 不应被显式调用，但 <code>makeAutoObservable</code> 内部会对其进行调用，以便根据调用上下文将方法标识为 action 或者派生值。</li></ul><p>一般情况下，<code>makeObservable</code> 是在类的构造函数中调用的，并且它的第一个参数是 <code>this</code> 。</p><p>所有带注解 的字段都是 不可配置的。<br>所有的不可观察（无状态）的字段（<code>action</code>, <code>flow</code>）都是 不可写的。</p><h4 id="makeAutoObservable"><a href="#makeAutoObservable" class="headerlink" title="makeAutoObservable"></a>makeAutoObservable</h4><p>用法：<code>makeAutoObservable(target, overrides?, options?)</code></p><p><code>makeAutoObservable</code> 就像是加强版的 <code>makeObservable</code>，在默认情况下它将推断所有的属性。<code>makeAutoObservable</code> 不能被用于带有 super 的类或 子类。</p><p>推断规则：</p><ul><li>所有 _自有_ 属性都成为 <code>observable</code>。</li><li>所有 <code>get</code>ters 都成为 <code>computed</code>。</li><li>所有 <code>set</code>ters 都成为 <code>action</code>。</li><li>所有 <em>prototype 中的 functions</em> 都成为 <code>autoAction</code>。</li><li>所有 <em>prototype 中的 generator functions</em> 都成为 <code>flow</code>。（需要注意，generators 函数在某些编译器配置中无法被检测到，如果 <code>flow</code> 没有正常运行，请务必明确地指定 <code>flow</code> 注解。）</li><li>在 <code>overrides</code> 参数中标记为 <code>false</code> 的成员将不会被添加注解。例如，将其用于像标识符这样的只读字段。</li></ul><h4 id="observable"><a href="#observable" class="headerlink" title="observable"></a>observable</h4><p>用法：<code>observable(source, overrides?, options?)</code></p><p><code>observable</code> 注解可以作为一个函数进行调用，从而一次性将整个对象变成可观察的，之后被添加到这个对象中的属性也将被侦测并使其转化为可观察对象。</p><h3 id="使用-actions-更新-state"><a href="#使用-actions-更新-state" class="headerlink" title="使用 actions 更新 state"></a>使用 actions 更新 state</h3><h4 id="action"><a href="#action" class="headerlink" title="action"></a>action</h4><p>用法：</p><ul><li><code>action</code> （注解）</li><li><code>action(fn)</code></li><li><code>action(name, fn)</code></li></ul><p>action 注解表示了一段修改 state 的代码。<br>Actions 可以帮助你更好的组织你的代码并提供以下性能优势：</p><ol><li>它们在 <code>transactions</code> 内部运行。任何可观察对象在最外层的 action 完成之前都不会被更新，这一点保证了在 action 完成之前，action 执行期间生成的中间值或不完整的值对应用程序的其余部分都是不可见的。</li><li>默认情况下，不允许在 actions 之外改变 state。这有助于在代码中清楚地对状态更新发生的位置进行定位。</li></ol><p>action 注解应该仅用于会修改 state 的函数。带有 action 注解的成员是不可枚举的。</p><h4 id="action-bound"><a href="#action-bound" class="headerlink" title="action.bound"></a>action.bound</h4><p>用法： <code>action.bound</code> （注解）</p><p><code>action.bound</code> 注解可用于将方法自动绑定到正确的实例，这样 <code>this</code> 会始终被正确绑定在函数内部。</p><h4 id="runInAction"><a href="#runInAction" class="headerlink" title="runInAction"></a>runInAction</h4><p>用法：<code>runInAction(fn)</code></p><p>使用这个工具函数来创建一个会被立即调用的临时 action。</p><h4 id="flow"><a href="#flow" class="headerlink" title="flow"></a>flow</h4><p>用法：</p><ul><li><code>flow</code> （注解）</li><li><code>flow(function* (args) &#123; &#125;)</code></li></ul><p><code>flow</code> 包装器是一个可选的 <code>async</code> / <code>await</code> 替代方案，它让 MobX action 使用起来更加容易。</p><p><code>flow</code> 将一个 generator 函数 作为唯一输入。 在 generator 内部，你可以使用 yield 串联 Promise（使用 <code>yield somePromise</code> 代替 <code>await somePromise</code>）。 <code>flow</code> 机制将会确保 generator 在 Promise resolve 之后继续运行或者抛出错误。</p><p>带有 flow 注解的成员是不可枚举的。 <code>flow</code> 的返回值是一个 Promise，在 generator 函数运行完成时它将会被 resolve。 返回的 Promise 中还有一个 <code>cancel()</code> 方法，该方法可以打断正在运行的 generator 并取消它。 所有 <code>try</code> / <code>finally</code> 语句仍然会被运行。</p><h4 id="flow-bound"><a href="#flow-bound" class="headerlink" title="flow.bound"></a>flow.bound</h4><p>用法： <code>flow.bound</code> （注解）</p><p><code>flow.bound</code> 注解可用于将方法自动绑定到正确的实例，这样 <code>this</code> 会始终被正确绑定在函数内部。</p><h3 id="通过-computeds-派生信息"><a href="#通过-computeds-派生信息" class="headerlink" title="通过 computeds 派生信息"></a>通过 computeds 派生信息</h3><h4 id="computed"><a href="#computed" class="headerlink" title="computed"></a>computed</h4><p>用法：</p><ul><li><code>computed</code> （注解）</li><li><code>computed(options)</code> （注解）</li><li><code>computed(fn, options?)</code></li></ul><p>computed 可以用来从其他可观察对象中派生信息。</p><p>使用 computed value 时，需遵循以下规则：</p><ol><li>它们不应该有副作用或者更新其他可观察对象</li><li>避免创建和返回新的可观察对象</li><li>它们不应该依赖非可观察对象的值</li></ol><h3 id="使用-reactions-处理副作用"><a href="#使用-reactions-处理副作用" class="headerlink" title="使用 reactions 处理副作用"></a>使用 reactions 处理副作用</h3><h4 id="autorun"><a href="#autorun" class="headerlink" title="autorun"></a>autorun</h4><p><code>autorun</code> 函数接受一个函数作为参数，每当该函数所观察的值发生变化时，它都应该运行。<br><code>autorun</code> 通过在响应式上下文运行 <code>effect</code> 来工作。在给定的函数执行期间，MobX 会持续跟踪被 effect 直接或间接读取过的所有可观察对象和计算值。 一旦函数执行完毕，MobX 将收集并订阅所有被读取过的可观察对象，并等待其中任意一个再次发生改变。 一旦有改变发生，<code>autorun</code> 将会再次触发，重复整个过程。</p><p><img src="/blog/static/imgs/mobx/autorun.png" alt="mobx_autorun_inner"></p><h4 id="reaction"><a href="#reaction" class="headerlink" title="reaction"></a>reaction</h4><p><code>reaction</code> 类似于 autorun，但可以让你更加精细地控制要跟踪的可观察对象。 它接受两个函数作为参数：第一个，data 函数，其是被跟踪的函数并且其返回值将会作为第二个函数，effect 函数，的输入。 重要的是要注意，副作用只会对 data 函数中被访问过的数据做出反应，这些数据可能少于 effect 函数中实际使用的数据。<br>一般的模式是在 <em>data</em> 函数中返回你在副作用中需要的所有数据， 并以这种方式更精确地控制副作用触发的时机。 与 <code>autorun</code> 不同，副作用在初始化时不会自动运行，而只会在 data 表达式首次返回新值之后运行。</p><h4 id="when"><a href="#when" class="headerlink" title="when"></a>when</h4><p><code>when</code> 会观察并运行给定的 <em>predicate</em> 函数，直到其返回 <code>true</code>。 一旦 predicate 返回了 <code>true</code>，给定的 effect 函数就会执行并且自动执行器函数将会被清理掉。<br>如果你没有传入 <code>effect</code> 函数，<code>when</code> 函数返回一个 <code>Promise</code> 类型的 disposer，并允许你手动取消。</p><p>使用 reactive context 需要遵守一些规则：</p><ol><li>默认情况下，如果可观察对象发生了改变，受其影响的 reactions 会立即（同步）运行。然而，它们直到当前最外层的 (trans)action 执行结束后才会运行。</li><li>autorun 只会跟踪给定函数在同步执行过程中所读取的可观察对象，不会跟踪异步发生的变化。</li><li>autorun 不会跟踪被其调用的 action 所读取的可观察对象，因为 action 始终不会被追踪。</li><li>reactions 总是会返回一个 disposer 函数，一旦不再需要这些方法中的副作用时，需要调用它们所返回的 disposer 函数。 否则可能导致内存泄漏。</li></ol><p>使用 <code>mobx-react</code> 等库时，绑定中的 observer 等方式会间接创建 reaction，无需手动创建。在手动创建 reaction 之前，需要检查是否符合以下原则：</p><ol><li>只有在引起副作用的一方与副作用之间没有直接关系的情况下才使用 reaction</li><li>reactions 不应该更新其他可观察对象</li><li>reactions 应该是独立的</li></ol><h2 id="MobX-和-Redux-的区别"><a href="#MobX-和-Redux-的区别" class="headerlink" title="MobX 和 Redux 的区别"></a>MobX 和 Redux 的区别</h2><p>参见 <a href="/blog/2022/11/25/React-Redux小抄/#Redux-和-MobX-的区别">Redux 和 MobX 的区别</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;MobX 是一款简单可扩展的状态管理库。它通过运用透明的函数式响应编程（Transparent Functional Reactive Programming，TFRP）使状态管理变得简单和可扩展。&lt;/p&gt;
&lt;h2 id=&quot;MobX-应用示例&quot;&gt;&lt;a href=&quot;#MobX</summary>
      
    
    
    
    
    <category term="react" scheme="https://mangon.cn/blog/tags/react/"/>
    
    <category term="MobX" scheme="https://mangon.cn/blog/tags/MobX/"/>
    
  </entry>
  
  <entry>
    <title>tsconfig.json是什么</title>
    <link href="https://mangon.cn/blog/2023/09/13/FE-tsconfig-json%E6%98%AF%E4%BB%80%E4%B9%88/"/>
    <id>https://mangon.cn/blog/2023/09/13/FE-tsconfig-json%E6%98%AF%E4%BB%80%E4%B9%88/</id>
    <published>2023-09-13T08:26:21.000Z</published>
    <updated>2026-01-21T03:29:14.784Z</updated>
    
    <content type="html"><![CDATA[<h2 id="概览"><a href="#概览" class="headerlink" title="概览"></a>概览</h2><p>当目录中出现了 <code>tsconfig.json</code> 文件，则说明该目录是 TypeScript 项目的根目录。<code>tsconfig.json</code> 文件指定了编译项目所需的根目录下的文件以及编译选项。</p><p>JavaScript 项目可以使用 <code>jsconfig.json</code> 文件，它的作用与 <code>tsconfig.json</code> 基本相同，只是默认启用了一些 JavaScript 相关的编译选项。</p><p>一个项目将以下列之一的方式使用 <code>tsconfig.json</code> 或者 <code>jsconfig.json</code> 进行编译：</p><ul><li><p>在调用 tsc 命令并且没有其它输入文件参数时，编译器将由当前目录开始向父级目录寻找包含 tsconfig 文件的目录。</p></li><li><p>调用 tsc 命令并且没有其他输入文件参数，可以使用 <code>--project</code> （或者只是 <code>-p</code>）的命令行选项来指定包含了 <code>tsconfig.json</code> 的目录，或者包含有效配置的 .json 文件路径。</p></li></ul><p>当在命令行上指定输入文件时，<code>tsconfig.json</code> 文件将被忽略。</p><p>一个 <code>tsconfig.json</code> 的示例如下所示：</p><figure class="highlight json"><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="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;compilerOptions&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;module&quot;</span><span class="punctuation">:</span> <span class="string">&quot;system&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;noImplicitAny&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;removeComments&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;preserveConstEnums&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;outFile&quot;</span><span class="punctuation">:</span> <span class="string">&quot;../../built/local/tsc.js&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;sourceMap&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;include&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;src/**/*&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;exclude&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;node_modules&quot;</span><span class="punctuation">,</span> <span class="string">&quot;**/*.spec.ts&quot;</span><span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h2 id="基本的-tsconfig"><a href="#基本的-tsconfig" class="headerlink" title="基本的 tsconfig"></a>基本的 tsconfig</h2><p>根据你要在其中运行代码的不同的 JavaScript 运行时环境，你可以在 <a href="https://github.com/tsconfig/bases/">github.com/tsconfig/bases</a> 上寻找一个合适的基本配置。 你可以通过扩展（extends）这些已经处理过不同的 JavaScript 运行时环境的 <code>tsconfig.json</code> 文件来简化你项目中的 <code>tsconfig.json</code> 。</p><p>可选的基本 tsconfig 如下所示：</p><table><thead><tr><th>名称</th><th>包</th><th>说明</th></tr></thead><tbody><tr><td>Recommended</td><td><code>@tsconfig/recommended</code></td></tr><tr><td>Bun</td><td><code>@tsconfig/bun</code></td></tr><tr><td>Create React App</td><td><code>@tsconfig/create-react-app</code></td></tr><tr><td>Cypress</td><td><code>@tsconfig/cypress</code></td></tr><tr><td>Deno</td><td><code>@tsconfig/deno</code></td></tr><tr><td>Docusaurus v2</td><td><code>@tsconfig/docusaurus</code></td></tr><tr><td>Ember</td><td><code>@tsconfig/ember</code></td></tr><tr><td>Next.js</td><td><code>@tsconfig/next</code></td></tr><tr><td>Node LTS</td><td><code>@tsconfig/node-lts</code></td></tr><tr><td>Node 10</td><td><code>@tsconfig/node10</code></td><td>Node也有 12 14 16 17 18 19 20 版本，写法类似</td></tr><tr><td>Nuxt</td><td><code>@tsconfig/nuxt</code></td></tr><tr><td>React Native</td><td><code>@tsconfig/react-native</code></td></tr><tr><td>Remix</td><td><code>@tsconfig/remix</code></td></tr><tr><td>Strictest</td><td><code>@tsconfig/strictest</code></td></tr><tr><td>Svelte</td><td><code>@tsconfig/svelte</code></td></tr><tr><td>Taro</td><td><code>@tsconfig/taro</code></td></tr><tr><td>Vite React</td><td><code>@tsconfig/vite-react</code></td></tr></tbody></table><h2 id="tsconfig-配置参考"><a href="#tsconfig-配置参考" class="headerlink" title="tsconfig 配置参考"></a>tsconfig 配置参考</h2><p>详细参考见 https://www.typescriptlang.org/tsconfig</p><h3 id="compilerOptions"><a href="#compilerOptions" class="headerlink" title="compilerOptions"></a>compilerOptions</h3><p><code>compilerOptions</code> 构成了 TypeScript 配置的大部分内容，它涵盖了语言应该如何工作。</p><p>大致包括以下部分：</p><ol><li>类型检查 Type Checking</li><li>模块 Modules</li><li>发布 Emit</li><li>JavaScript 支持 JavaScript Support</li><li>编辑器支持 Editor Support</li><li>交互限制 Interop Constraints</li><li>向后兼容性 Backwards Compatibility</li><li>语言与环境 Language and Environment</li><li>编译器诊断 Compiler Diagnostics</li><li>项目 Projects</li><li>输出格式化 Output Formatting</li><li>完整性 Completeness</li><li>命令行 Command Line</li><li>监视选项 Watch Options</li></ol><p>详见 <a href="/blog/2023/09/13/FE-tsconfig-json是什么/#编译选项-compilerOptions">编译选项</a></p><h3 id="files"><a href="#files" class="headerlink" title="files"></a>files</h3><p>类型：<code>array&lt;string&gt;</code><br>默认值： <code>false</code><br>指定要包含在程序中的文件的允许列表。如果找不到任何文件，就会发生错误。<br>当只有少量文件并且不需要使用 glob 模式来引用多个文件时，可以使用 <code>files</code>。其他情况使用 <code>include</code>。</p><h3 id="extends"><a href="#extends" class="headerlink" title="extends"></a>extends</h3><p>类型： <code>string</code><br>默认值： <code>false</code><br>指定包含要从中继承的另一个配置文件的路径。路径可能使用 Node.js 样式的解析。<br>首先加载基本文件中的配置，然后由继承配置文件中的那些配置覆盖。在配置文件中找到的所有相对路径都将相对于它们源自的配置文件进行解析。配置之间不允许循环继承。<code>references</code> 无法被继承。</p><h3 id="include"><a href="#include" class="headerlink" title="include"></a>include</h3><p>类型：<code>array</code><br>默认值：如果有 <code>file</code> 则默认为 <code>[]</code> 否则默认为 <code>**/*</code><br>指定要包含在程序中的文件名或模式的数组。这些文件名是相对于包含 <code>tsconfig.json</code> 文件的目录解析的。</p><p><code>include</code> 和 <code>exclude</code> 支持通配符以生成 glob 模式：</p><ul><li><code>*</code> 匹配零个或多个字符（不包括目录分隔符）</li><li><code>?</code> 匹配任何一个字符（不包括目录分隔符）</li><li><code>**/</code> 匹配嵌套到任何级别的任何目录</li></ul><p>如果模式中的最后一个路径段不包含文件扩展名或通配符，则将其视为一个目录，并包括该目录中具有支持扩展名的文件（例如，默认情况下为 .ts 、.tsx 和 .d.ts ，如果 <code>allowJs</code> 设置为 true ，则使用 .js 和 .jsx ）。</p><h3 id="exclude"><a href="#exclude" class="headerlink" title="exclude"></a>exclude</h3><p>类型：<code>array</code><br>默认值：<code>[&#39;node_modules&#39;, &#39;bower_components&#39;, &#39;jspm_packages&#39;, &#39;%outDir%&#39;]</code><br>指定在解析include时应跳过的文件名或模式的数组。</p><p><strong>重要提示</strong>：<code>exclude</code> 仅排除由于 <code>include</code> 设置而包含的文件。<code>exclude</code> 指定的文件仍然可以成为代码库的一部分，这是由于代码中的 <code>import</code> 语句、<code>types</code> 包含、<code>///&lt;reference</code> 指令或在 <code>files</code> 列表中指定。</p><h3 id="references"><a href="#references" class="headerlink" title="references"></a>references</h3><p>项目引用是一种将 TypeScript 程序解构成更小部分的方法。使用项目引用可以极大地缩短构建和编辑器交互时间，强制组件之间的逻辑分离，并以新的和改进的方式组织代码。详见 <a href="https://www.typescriptlang.org/docs/handbook/project-references.html">Project References</a>。</p><h2 id="编译选项-compilerOptions"><a href="#编译选项-compilerOptions" class="headerlink" title="编译选项 compilerOptions"></a>编译选项 compilerOptions</h2><h3 id="类型检查-Type-Checking"><a href="#类型检查-Type-Checking" class="headerlink" title="类型检查 Type Checking"></a>类型检查 Type Checking</h3><h4 id="allowUnreachableCode"><a href="#allowUnreachableCode" class="headerlink" title="allowUnreachableCode"></a>allowUnreachableCode</h4><p>允许无法访问的代码</p><ul><li><p><code>undefined</code>（默认）将建议作为警告提供给编辑器</p></li><li><p><code>true</code> 忽略无法访问的代码</p></li><li><p><code>false</code> 引发关于无法访问代码的编译器错误</p></li></ul><h4 id="allowUnusedLabels"><a href="#allowUnusedLabels" class="headerlink" title="allowUnusedLabels"></a>allowUnusedLabels</h4><p>允许未使用的标签（label）</p><ul><li><p><code>undefined</code>（默认）将建议作为警告提供给编辑器</p></li><li><p><code>true</code> 忽略未使用的标签</p></li><li><p><code>false</code> 引发关于未使用标签的编译器错误</p></li></ul><h4 id="alwaysStrict"><a href="#alwaysStrict" class="headerlink" title="alwaysStrict"></a>alwaysStrict</h4><p>确保在 ECMAScript 严格模式下解析文件，并为每个源文件添加 <code>use strict</code> 。</p><p>默认值：如果有 <code>strict</code> 则默认为 <code>true</code> 否则为 <code>false</code> 。</p><h4 id="exactOptionalPropertyTypes"><a href="#exactOptionalPropertyTypes" class="headerlink" title="exactOptionalPropertyTypes"></a>exactOptionalPropertyTypes</h4><p>启用 exactOptionalPropertyTypes 后，TypeScript 对具有 <code>?</code> 前缀的类型或接口的属性启用更加精确的规则。</p><h4 id="noFallthroughCasesInSwitch"><a href="#noFallthroughCasesInSwitch" class="headerlink" title="noFallthroughCasesInSwitch"></a>noFallthroughCasesInSwitch</h4><p>在 switch 语句中进入穿透分支时报告错误。确保 switch 语句中的任何非空分支都包括 break、return 或 throw 。这意味着你不会意外地遇到穿透分支的bug。</p><h4 id="noImplicitAny"><a href="#noImplicitAny" class="headerlink" title="noImplicitAny"></a>noImplicitAny</h4><p>在某些不存在类型注释的情况下，当 TypeScript 无法推断变量的类型时，它将回退到 any 类型。</p><p>默认值：如果有 <code>strict</code> 则默认为 <code>true</code> 否则为 <code>false</code> 。</p><h4 id="noImplicitOverride"><a href="#noImplicitOverride" class="headerlink" title="noImplicitOverride"></a>noImplicitOverride</h4><p>当处理使用继承的类时，子类可能会与在基类中重命名时重载的函数“不同步”（隐式重载）。<br>使用 noImplicitOverride 可以确保重载的函数必需包含关键字 override ，从而确保子类永远不会失去同步。</p><h4 id="noImplicitReturns"><a href="#noImplicitReturns" class="headerlink" title="noImplicitReturns"></a>noImplicitReturns</h4><p>启用后，TypeScript 将检查函数中的所有代码路径，以确保它们返回值。</p><h4 id="noImplicitThis"><a href="#noImplicitThis" class="headerlink" title="noImplicitThis"></a>noImplicitThis</h4><p>在具有隐含 “any” 类型的 “this” 表达式上引发错误。</p><h4 id="noPropertyAccessFromIndexSignature"><a href="#noPropertyAccessFromIndexSignature" class="headerlink" title="noPropertyAccessFromIndexSignature"></a>noPropertyAccessFromIndexSignature</h4><p>此设置可确保通过点（<code>obj.key</code>）语法和索引（<code>obj[&quot;key&quot;]</code>）访问字段以及在类型中声明属性的方式之间的一致性。如果没有此标志，TypeScript 将允许你使用点语法访问未定义的字段。</p><h4 id="noUncheckedIndexedAccess"><a href="#noUncheckedIndexedAccess" class="headerlink" title="noUncheckedIndexedAccess"></a>noUncheckedIndexedAccess</h4><p>TypeScript 有一种方法可以通过索引签名来描述对象上具有未知键但已知值的对象。<br>启用 noUncheckedIndexedAccess 将向类型中任何未声明的字段添加 undefined 类型。</p><h4 id="noUnusedLocals"><a href="#noUnusedLocals" class="headerlink" title="noUnusedLocals"></a>noUnusedLocals</h4><p>对未使用的局部变量报告错误。</p><h4 id="noUnusedParameters"><a href="#noUnusedParameters" class="headerlink" title="noUnusedParameters"></a>noUnusedParameters</h4><p>对函数中未使用的参数报告错误。</p><h4 id="strict"><a href="#strict" class="headerlink" title="strict"></a>strict</h4><p>严格标志可以实现广泛的类型检查行为，从而为程序的正确性提供更强的保证。启用此选项相当于启用以下列出的所有严格模式族选项（以 strict 开头的选项）。然后，你可以根据需要关闭单独的严格模式族检查。</p><h4 id="strictBindCallApply"><a href="#strictBindCallApply" class="headerlink" title="strictBindCallApply"></a>strictBindCallApply</h4><p>设置后，TypeScript 将检查函数 call、bind 和 apply 的内置方法是否使用基础函数的正确参数调用。</p><h4 id="strictFunctionTypes"><a href="#strictFunctionTypes" class="headerlink" title="strictFunctionTypes"></a>strictFunctionTypes</h4><p>启用时，此标志会使函数参数得到更正确的检查。</p><h4 id="strictNullChecks"><a href="#strictNullChecks" class="headerlink" title="strictNullChecks"></a>strictNullChecks</h4><p>当 strictNullChecks 为 false 时，语言会有效地忽略 null 和 undefined 。这可能会导致运行时出现意外错误。<br>当 strictNullChecks 为 true 时， null 和 undefined 有各自不同的类型，如果你试图在需要具体值的地方使用它们，则会出现类型错误。</p><h4 id="strictPropertyInitialization"><a href="#strictPropertyInitialization" class="headerlink" title="strictPropertyInitialization"></a>strictPropertyInitialization</h4><p>当设置为 true 时，当类属性已声明但未在构造函数中设置时，TypeScript 将引发错误。</p><h4 id="useUnknownInCatchVariables"><a href="#useUnknownInCatchVariables" class="headerlink" title="useUnknownInCatchVariables"></a>useUnknownInCatchVariables</h4><p>在 TypeScript 4.0 中添加了新的功能，允许将 catch 子句中变量的类型从 any 更改为 unknown 。<br>这种模式确保错误处理代码变得更加全面，因为你不能提前保证抛出的对象是 error 子类。<br>启用了 useUnknownCatchVariables 标志后，就不需要额外的语法（<code>:unknown</code>）或 linter 规则来强制执行此行为。</p><h3 id="Modules-模块"><a href="#Modules-模块" class="headerlink" title="Modules 模块"></a>Modules 模块</h3><h4 id="allowArbitraryExtensions"><a href="#allowArbitraryExtensions" class="headerlink" title="allowArbitraryExtensions"></a>allowArbitraryExtensions</h4><p>在 TypeScript 5.0 中，当导入路径的扩展名不是已知的 JavaScript 或 TypeScript 文件扩展名时，编译器将为该路径查找一个形式为 <code>&#123;file-basename&#125;.d.&#123;extension&#125;.ts</code> 的声明文件。<br>默认情况下，此导入会引发一个错误，让你知道 TypeScript 不理解此文件类型，并且你的运行时可能不支持导入它。但是，如果你已将运行时或打包器配置为可以处理它，则可以使用新的 <code>--allowArbitraryExtensions</code> 编译器选项来抑制该错误。</p><h4 id="allowImportingTsExtensions"><a href="#allowImportingTsExtensions" class="headerlink" title="allowImportingTsExtensions"></a>allowImportingTsExtensions</h4><p><code>--allowImportingTsExtensions</code> 允许 TypeScript 文件使用 TypeScript 特定的扩展名（如 .ts、.mts 或 .tsx）相互导入。<br>只有启用 <code>--noEmit</code> 或 <code>--emitDeclarationOnly</code> 时才允许使用此标志，因为这些导入路径在运行时无法在 JavaScript 输出文件中解析。这里的期望是，你的解析器（例如，你的打包器、运行时或其他工具）将会做这些在 .ts 文件之间的导入工作。</p><h4 id="allowUmdGlobalAccess"><a href="#allowUmdGlobalAccess" class="headerlink" title="allowUmdGlobalAccess"></a>allowUmdGlobalAccess</h4><p>当设置为 true 时， allowUmdGlobalAccess 允许你从模块文件内部访问作为全局变量的 UMD 导出。模块文件是具有导入和/或导出功能的文件。如果没有此标志，使用 UMD 模块的导出需要导入声明。</p><h4 id="baseUrl"><a href="#baseUrl" class="headerlink" title="baseUrl"></a>baseUrl</h4><p>设置要从中解析非相对模块名称的基本目录。<br>使用 <code>&quot;baseUrl&quot;：&quot;./&quot;</code> 时，TypeScript 将查找与 tsconfig.json 位于同一文件夹的文件。</p><h4 id="customConditions"><a href="#customConditions" class="headerlink" title="customConditions"></a>customConditions</h4><p><code>--customConditions</code> 获取 TypeScript 从 package.json 的导出或导入字段解析时应成功的附加条件列表。这些条件将添加到解析程序默认使用的任何现有条件中。<br>该字段仅在 <code>--moduleSolution</code> 为 <code>node16</code> 、<code>nodenext</code> 或 <code>bundler</code> 时有效。</p><h4 id="module"><a href="#module" class="headerlink" title="module"></a>module</h4><p>设置应用程序的模块系统。改变 <code>module</code> 会影响 <code>moduleResolution</code>。</p><p>默认值：如果 <code>target</code> 为 <code>ES3</code> 或者 <code>ES5</code> 那么 <code>module</code> 默认为 <code>CommonJS</code>，否则默认为 <code>ES6</code>/<code>ES2015</code> 。</p><p>以下为该文件的一些例子输出：</p><figure class="highlight js"><figcaption><span>index.ts</span></figcaption><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">import</span> &#123; valueOfPi &#125; <span class="keyword">from</span> <span class="string">&#x27;./constants&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> twoPi = valueOfPi * <span class="number">2</span>;</span><br></pre></td></tr></table></figure><figure class="highlight js"><figcaption><span>CommonJS</span></figcaption><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="meta">&#x27;use strict&#x27;</span>;</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(<span class="built_in">exports</span>, <span class="string">&#x27;__esModule&#x27;</span>, &#123; <span class="attr">value</span>: <span class="literal">true</span> &#125;);</span><br><span class="line"><span class="built_in">exports</span>.<span class="property">twoPi</span> = <span class="keyword">void</span> <span class="number">0</span>;</span><br><span class="line"><span class="keyword">const</span> constants_1 = <span class="built_in">require</span>(<span class="string">&#x27;./constants&#x27;</span>);</span><br><span class="line"><span class="built_in">exports</span>.<span class="property">twoPi</span> = constants_1.<span class="property">valueOfPi</span> * <span class="number">2</span>;</span><br></pre></td></tr></table></figure><figure class="highlight js"><figcaption><span>UMD</span></figcaption><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="keyword">function</span> (<span class="params">factory</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="variable language_">module</span> === <span class="string">&#x27;object&#x27;</span> &amp;&amp; <span class="keyword">typeof</span> <span class="variable language_">module</span>.<span class="property">exports</span> === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> v = <span class="title function_">factory</span>(<span class="built_in">require</span>, <span class="built_in">exports</span>);</span><br><span class="line">    <span class="keyword">if</span> (v !== <span class="literal">undefined</span>) <span class="variable language_">module</span>.<span class="property">exports</span> = v;</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> define === <span class="string">&#x27;function&#x27;</span> &amp;&amp; define.<span class="property">amd</span>) &#123;</span><br><span class="line">    <span class="title function_">define</span>([<span class="string">&#x27;require&#x27;</span>, <span class="string">&#x27;exports&#x27;</span>, <span class="string">&#x27;./constants&#x27;</span>], factory);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)(<span class="keyword">function</span> (<span class="params"><span class="built_in">require</span>, <span class="built_in">exports</span></span>) &#123;</span><br><span class="line">  <span class="string">&#x27;use strict&#x27;</span>;</span><br><span class="line">  <span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(<span class="built_in">exports</span>, <span class="string">&#x27;__esModule&#x27;</span>, &#123; <span class="attr">value</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">  <span class="built_in">exports</span>.<span class="property">twoPi</span> = <span class="keyword">void</span> <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">const</span> constants_1 = <span class="built_in">require</span>(<span class="string">&#x27;./constants&#x27;</span>);</span><br><span class="line">  <span class="built_in">exports</span>.<span class="property">twoPi</span> = constants_1.<span class="property">valueOfPi</span> * <span class="number">2</span>;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><figure class="highlight js"><figcaption><span>AMD</span></figcaption><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 function_">define</span>([<span class="string">&#x27;require&#x27;</span>, <span class="string">&#x27;exports&#x27;</span>, <span class="string">&#x27;./constants&#x27;</span>], <span class="keyword">function</span> (<span class="params"><span class="built_in">require</span>, <span class="built_in">exports</span>, constants_1</span>) &#123;</span><br><span class="line">  <span class="string">&#x27;use strict&#x27;</span>;</span><br><span class="line">  <span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(<span class="built_in">exports</span>, <span class="string">&#x27;__esModule&#x27;</span>, &#123; <span class="attr">value</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">  <span class="built_in">exports</span>.<span class="property">twoPi</span> = <span class="keyword">void</span> <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">exports</span>.<span class="property">twoPi</span> = constants_1.<span class="property">valueOfPi</span> * <span class="number">2</span>;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><figure class="highlight js"><figcaption><span>System</span></figcaption><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="title class_">System</span>.<span class="title function_">register</span>([<span class="string">&#x27;./constants&#x27;</span>], <span class="keyword">function</span> (<span class="params">exports_1, context_1</span>) &#123;</span><br><span class="line">  <span class="string">&#x27;use strict&#x27;</span>;</span><br><span class="line">  <span class="keyword">var</span> constants_1, twoPi;</span><br><span class="line">  <span class="keyword">var</span> __moduleName = context_1 &amp;&amp; context_1.<span class="property">id</span>;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    <span class="attr">setters</span>: [</span><br><span class="line">      <span class="keyword">function</span> (<span class="params">constants_1_1</span>) &#123;</span><br><span class="line">        constants_1 = constants_1_1;</span><br><span class="line">      &#125;</span><br><span class="line">    ],</span><br><span class="line">    <span class="attr">execute</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      exports_1(<span class="string">&#x27;twoPi&#x27;</span>, (twoPi = constants_1.<span class="property">valueOfPi</span> * <span class="number">2</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><figure class="highlight js"><figcaption><span>ESNext</span></figcaption><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="keyword">import</span> &#123; valueOfPi &#125; <span class="keyword">from</span> <span class="string">&#x27;./constants&#x27;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> twoPi = valueOfPi * <span class="number">2</span>;</span><br></pre></td></tr></table></figure><figure class="highlight js"><figcaption><span>ES2015/ES6/ES2020/ES2022</span></figcaption><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="keyword">import</span> &#123; valueOfPi &#125; <span class="keyword">from</span> <span class="string">&#x27;./constants&#x27;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> twoPi = valueOfPi * <span class="number">2</span>;</span><br></pre></td></tr></table></figure><p>除了 <code>ES2015</code>/<code>ES6</code> 的基本功能外，<code>ES2020</code> 还增加了对动态导入和 <code>import.meta</code> 的支持，而 <code>ES2022</code> 则进一步增加了对 top await 的支持。</p><figure class="highlight js"><figcaption><span>None</span></figcaption><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="meta">&#x27;use strict&#x27;</span>;</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(<span class="built_in">exports</span>, <span class="string">&#x27;__esModule&#x27;</span>, &#123; <span class="attr">value</span>: <span class="literal">true</span> &#125;);</span><br><span class="line"><span class="built_in">exports</span>.<span class="property">twoPi</span> = <span class="keyword">void</span> <span class="number">0</span>;</span><br><span class="line"><span class="keyword">const</span> constants_1 = <span class="built_in">require</span>(<span class="string">&#x27;./constants&#x27;</span>);</span><br><span class="line"><span class="built_in">exports</span>.<span class="property">twoPi</span> = constants_1.<span class="property">valueOfPi</span> * <span class="number">2</span>;</span><br></pre></td></tr></table></figure><h4 id="moduleResolution"><a href="#moduleResolution" class="headerlink" title="moduleResolution"></a>moduleResolution</h4><p>指定模块解析策略：</p><ul><li><code>node16</code> 或者 <code>nodenext</code> 表示使用 Node.js 的现代版本。Node.js v12及更高版本同时支持 ECMAScript import 和 CommonJS require</li><li><code>node10</code>（以前称为 <code>node</code> ）适用于 v10 以内的 Node.js 版本，仅支持 CommonJS require。</li><li>用于打包器的 <code>bundler</code>。与 node16 和 nodenext 一样，该模式支持 package.json 的 “imports” 和 “exports” ，但与 Node.js 解析模式不同，bundler 在导入中不需要相对路径上的文件扩展名。</li><li>在 1.6 版本之前，TypeScript 中使用了 <code>classic</code>。</li></ul><p>默认值：如果 <code>module</code> 是 <code>AMD</code>,<code>UMD</code>,<code>System</code> 或者 <code>ES6</code>/<code>ES2015</code> 则默认值是 <code>Calssic</code>；如果 <code>module</code> 是 <code>node16</code> 或者 <code>nodenext</code>，则与之相匹配; 否则默认值为 <code>Node</code> 。</p><h4 id="moduleSuffixes"><a href="#moduleSuffixes" class="headerlink" title="moduleSuffixes"></a>moduleSuffixes</h4><p>类型：<code>array&lt;string&gt;</code><br>提供一种在解析模块时覆盖要搜索的文件名后缀的默认列表的方法。</p><h4 id="noResolve"><a href="#noResolve" class="headerlink" title="noResolve"></a>noResolve</h4><p>默认情况下，TypeScript 将检查 import 和 <code>reference</code> 指令的初始文件集，并将这些解析的文件添加到程序中。<br>如果设置了 <code>noResolve</code> ，则不会发生此过程。但是，import 语句仍然会被检查，以查看它们是否解析为有效的模块，因此你需要确保通过其他方式满足这一要求。</p><h4 id="paths"><a href="#paths" class="headerlink" title="paths"></a>paths</h4><p>将 paths 中所列出的一系列条目的 import 重新映射，如果设置了 baseUrl，则相对于 baseUrl 进行查找，否则相对于 tsconfig 文件本身的位置进行查找。通过设置 paths，TypeScript 文件解析器可以支持自定义前缀来查找代码引入路径。</p><h4 id="resolveJsonModule"><a href="#resolveJsonModule" class="headerlink" title="resolveJsonModule"></a>resolveJsonModule</h4><p>允许导入带有 .json 扩展名的模块，这是 node 项目中的常见做法。这包括基于静态 JSON 形状为 import 生成一个类型。</p><h4 id="resolvePackageJsonExports"><a href="#resolvePackageJsonExports" class="headerlink" title="resolvePackageJsonExports"></a>resolvePackageJsonExports</h4><p><code>--resolvePackageJsonExports</code> 强制 TypeScript 在读取 node_modules 中的包时，查阅 package.json 文件的 exports 字段。</p><p>默认值：当 <code>moduleResolution</code> 是 <code>node16</code> , <code>nodenext</code> 或者 <code>bundler</code> 时，默认值为 <code>true</code>, 否则为 <code>false</code>。</p><h4 id="resolvePackageJsonImports"><a href="#resolvePackageJsonImports" class="headerlink" title="resolvePackageJsonImports"></a>resolvePackageJsonImports</h4><p><code>--resolvePackageJsonImports</code> 强制 TypeScript 在从祖先目录包含 package.json 的文件执行以 # 开头的查找时，查阅 package.json 文件的 imports 字段。</p><p>默认值：当 <code>moduleResolution</code> 是 <code>node16</code> , <code>nodenext</code> 或者 <code>bundler</code> 时，默认值为 <code>true</code>, 否则为 <code>false</code>。</p><h4 id="rootDir"><a href="#rootDir" class="headerlink" title="rootDir"></a>rootDir</h4><p>根节点。</p><p>默认值：所有非声明输入文件的最长公共路径。如果设置了 <code>composite</code>，则默认为包含 tsconfig.json 文件的目录。</p><h4 id="rootDirs"><a href="#rootDirs" class="headerlink" title="rootDirs"></a>rootDirs</h4><p>使用 rootDirs ，你可以通知编译器有许多“虚拟”目录充当单个根目录。这允许编译器解析这些“虚拟”目录中的相对模块导入，就好像它们被合并到一个目录中一样。</p><h4 id="typeRoots"><a href="#typeRoots" class="headerlink" title="typeRoots"></a>typeRoots</h4><p>默认情况下，所有可见的 <code>@types</code> 包都包含在编译中。如果指定了 <code>typeRoots</code> ，则只包括 <code>typeRoots</code> 下的包。所有路径都是相对于 <code>tsconfig.json</code> 的。</p><h4 id="types"><a href="#types" class="headerlink" title="types"></a>types</h4><p>默认情况下，所有可见的 <code>@types</code> 包都包含在编译中。如果指定了 <code>types</code>，则只有列出的包才会包含在全局作用域中。</p><h3 id="Emit-生成"><a href="#Emit-生成" class="headerlink" title="Emit 生成"></a>Emit 生成</h3><h4 id="declaration"><a href="#declaration" class="headerlink" title="declaration"></a>declaration</h4><p>为项目中的每个 TypeScript 或 JavaScript 文件生成 <code>.d.ts</code> 文件。这些 <code>.d.ts</code> 文件是描述模块的外部API的类型定义文件。有了 <code>.d.ts</code> 文件，像 TypeScript 这样的工具可以为正在键入的代码提供智能提示和准确的类型。</p><p>默认值：如果 <code>composite</code> 则默认值为 <code>true</code> ，否则为 <code>false</code> 。</p><h4 id="declarationDir"><a href="#declarationDir" class="headerlink" title="declarationDir"></a>declarationDir</h4><p>提供了一种配置根目录的方法，该根目录用于生成类型描述文件( <code>.d.ts</code> )。</p><h4 id="declarationMap"><a href="#declarationMap" class="headerlink" title="declarationMap"></a>declarationMap</h4><p>为映射回原始 .ts 源文件的 .d.ts 文件生成源映射。这将允许 VS Code 等编辑器在使用 go to Definition 等功能时转到原始 .ts 文件。</p><h4 id="downlevelIteration"><a href="#downlevelIteration" class="headerlink" title="downlevelIteration"></a>downlevelIteration</h4><p>如果存在 Symbol.iterator 的实现，那么 downlevelIteration 允许在 ES5 环境中更准确地使用这些迭代方法的原始语法。</p><h4 id="emitBOM"><a href="#emitBOM" class="headerlink" title="emitBOM"></a>emitBOM</h4><p>控制 TypeScript 在写入输出文件时是否会生成字节顺序标记（BOM）。一些运行时环境需要 BOM 来正确解释 JavaScript 文件；其他人则要求它不存在。默认值 false 通常是最好的，除非你有理由更改它。</p><h4 id="emitDeclarationOnly"><a href="#emitDeclarationOnly" class="headerlink" title="emitDeclarationOnly"></a>emitDeclarationOnly</h4><p>仅生成 <code>.d.ts</code> 文件；不生成 <code>.js</code> 文件。</p><h4 id="importHelpers"><a href="#importHelpers" class="headerlink" title="importHelpers"></a>importHelpers</h4><p>对于某些降级操作，TypeScript 使用一些辅助代码来执行诸如继承类、扩展数组或对象以及异步操作等。默认情况下，这些辅助代码会插入到使用它们的文件中。如果在许多不同的模块中使用相同的辅助代码，这可能会导致代码重复。如果 importHelpers 标志处于启用状态，则这些辅助函数将改为从 tslib 模块导入。你需要确保 tslib 模块能够在运行时导入。这只会影响模块；全局脚本文件将不会尝试导入模块。</p><h4 id="importsNotUsedAsValues"><a href="#importsNotUsedAsValues" class="headerlink" title="importsNotUsedAsValues"></a>importsNotUsedAsValues</h4><p>此标志控制 <code>import</code> 的工作方式，有三个不同的选项：</p><ul><li>remove：删除仅引用类型的 <code>import</code> 语句。</li><li>preserve：保留其值或类型从未使用过的所有 <code>import</code> 语句。这可能会导致保留 引入/副作用。</li><li>error：这将保留所有 <code>import</code>（与 preserve 选项相同），但当 <code>import</code> 仅用作类型时会出错。如果你希望确保没有意外导入值，但仍然显式导入副作用，那么这可能会很有用。</li></ul><p>这个标志之所以有效，是因为你可以使用 <code>import type</code> 显式地创建一个 <code>import</code> 语句，而该语句永远不应该被生成到 JavaScript 中。</p><h4 id="inlineSourceMap"><a href="#inlineSourceMap" class="headerlink" title="inlineSourceMap"></a>inlineSourceMap</h4><p>设置后，TypeScript 将把源映射内容嵌入 <code>.js</code> 文件中，而不是生成 <code>.js.map</code> 文件来提供源映射。</p><h4 id="inlineSources"><a href="#inlineSources" class="headerlink" title="inlineSources"></a>inlineSources</h4><p>设置后，TypeScript 将把 <code>.ts</code> 文件的原始内容作为嵌入字符串包含在源映射中（使用源映射的 sourcesContent 属性）。</p><h4 id="mapRoot"><a href="#mapRoot" class="headerlink" title="mapRoot"></a>mapRoot</h4><p>指定调试器应该定位映射文件的位置，而不是生成的位置。</p><h4 id="newLine"><a href="#newLine" class="headerlink" title="newLine"></a>newLine</h4><p>指定在生成文件时使用的行尾序列:’ CRLF ‘ (dos)或’ LF ‘ (unix)。</p><h4 id="noEmit"><a href="#noEmit" class="headerlink" title="noEmit"></a>noEmit</h4><p>不要生成编译器输出文件，如 JavaScript 源代码、源映射或声明。<br>这为 Babel 或 swc 等其他工具腾出了空间来处理将 TypeScript 文件转换为可以在 JavaScript 环境中运行的文件。</p><h4 id="noEmitHelpers"><a href="#noEmitHelpers" class="headerlink" title="noEmitHelpers"></a>noEmitHelpers</h4><p>你可以在全局作用域中为你使用的帮助程序提供一种实现，而不是使用 importthelpers 导入帮助程序，并完全关闭生成或帮助函数。</p><h4 id="noEmitOnError"><a href="#noEmitOnError" class="headerlink" title="noEmitOnError"></a>noEmitOnError</h4><p>如果报告了任何错误，不要生成编译器输出文件，如 JavaScript 源代码、源映射或声明。</p><p>默认值：false</p><h4 id="outDir"><a href="#outDir" class="headerlink" title="outDir"></a>outDir</h4><p>如果指定，<code>.js</code> （以及 <code>.d.ts</code> <code>.js.Map</code> 等）文件将被生成到该目录。</p><h4 id="outFile"><a href="#outFile" class="headerlink" title="outFile"></a>outFile</h4><p>如果指定，所有全局（非模块）文件将被连接到指定的单个输出文件中。</p><h4 id="preserveConstEnums"><a href="#preserveConstEnums" class="headerlink" title="preserveConstEnums"></a>preserveConstEnums</h4><p>不要在生成的代码中删除 <code>const enum</code> 声明。<code>const enum</code> 提供了一种在运行时通过生成枚举值而不是引用来减少应用程序总体内存占用的方法。</p><h4 id="preserveValueImports"><a href="#preserveValueImports" class="headerlink" title="preserveValueImports"></a>preserveValueImports</h4><p><code>preserveValueImports</code> 会阻止 TypeScript 移除 import，即使它看起来没有被使用。</p><h4 id="removeComments"><a href="#removeComments" class="headerlink" title="removeComments"></a>removeComments</h4><p>当转换为 JavaScript 时，从 TypeScript 文件中删除所有注释。</p><p>默认值：false</p><h4 id="sourceMap"><a href="#sourceMap" class="headerlink" title="sourceMap"></a>sourceMap</h4><p>允许生成源映射文件。</p><h4 id="sourceRoot"><a href="#sourceRoot" class="headerlink" title="sourceRoot"></a>sourceRoot</h4><p>指定调试器应该定位 TypeScript 文件的位置，而不是相对源位置。</p><h4 id="stripInternal"><a href="#stripInternal" class="headerlink" title="stripInternal"></a>stripInternal</h4><p>不要为 JSDoc 注释中有 <code>@internal</code> 注释的代码生成声明文件。</p><h3 id="Javascript-支持"><a href="#Javascript-支持" class="headerlink" title="Javascript 支持"></a>Javascript 支持</h3><h4 id="allowJs"><a href="#allowJs" class="headerlink" title="allowJs"></a>allowJs</h4><p>允许在项目中导入 JavaScript 文件，而不仅仅是 <code>.ts</code> 和 <code>.tsx</code> 文件。</p><h4 id="checkJs"><a href="#checkJs" class="headerlink" title="checkJs"></a>checkJs</h4><p>与 <code>allowJs</code> 协同工作。当 checkJs 被启用时，会在 JavaScript 文件中报告错误。这相当于在项目中包含的所有 JavaScript 文件的顶部包含 <code>// @ts-check</code> 。</p><h4 id="maxNodeModuleJsDepth"><a href="#maxNodeModuleJsDepth" class="headerlink" title="maxNodeModuleJsDepth"></a>maxNodeModuleJsDepth</h4><p>在 node_modules 下搜索和加载 JavaScript 文件的最大依赖深度。仅 <code>allowJs</code> 开启时有效。</p><h3 id="编辑器支持"><a href="#编辑器支持" class="headerlink" title="编辑器支持"></a>编辑器支持</h3><h4 id="disableSizeLimit"><a href="#disableSizeLimit" class="headerlink" title="disableSizeLimit"></a>disableSizeLimit</h4><p>为了避免在处理非常大的 JavaScript 项目时可能出现的内存膨胀问题，TypeScript 会分配一个内存上限。打开此标志将取消限制。</p><h4 id="plugins"><a href="#plugins" class="headerlink" title="plugins"></a>plugins</h4><p>要在编辑器中运行的语言服务插件列表。</p><h3 id="交互限制"><a href="#交互限制" class="headerlink" title="交互限制"></a>交互限制</h3><h4 id="allowSyntheticDefaultImports"><a href="#allowSyntheticDefaultImports" class="headerlink" title="allowSyntheticDefaultImports"></a>allowSyntheticDefaultImports</h4><p>当设置为true时，allowsyntheticdefaulultimports允许你编写这样的导入:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">&#x27;react&#x27;</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">&#x27;react&#x27;</span>;</span><br></pre></td></tr></table></figure><p>当模块未显式指定默认导出时。</p><h4 id="esModuleInterop"><a href="#esModuleInterop" class="headerlink" title="esModuleInterop"></a>esModuleInterop</h4><p>默认情况下（esModuleInterop 为 false 或未设置），TypeScript 对待 CommonJS/AMD/UMD 模块的方式与对待 ES6 模块类似。在此过程中，有两个部分被证明是有缺陷的：</p><ul><li><p>像 <code>import * as moment from &quot;moment&quot;</code> 这样的命名空间导入与 <code>const moment = require(&quot;moment&quot;)</code> 的作用相同</p></li><li><p>像 <code>import moment from &quot;moment&quot;</code> 这样的默认导入与 <code>const moment = require(&quot;moment&quot;).default</code> 的作用相同</p></li></ul><p>这种不匹配导致了以下两个问题:</p><p>ES6 模块规范规定，命名空间导入 <code>import * as x</code> 只能是一个对象，通过让 TypeScript 像对待 <code>= require(&quot;x&quot;)</code> 一样对待它，那么 TypeScript 就允许将导入作为一个函数来对待，并且可以被调用。根据 Javascript 说明书，这是无效的。</p><p>虽然符合 ES6 模块规范，但大多数带有 CommonJS/AMD/UMD 模块的库并不像 TypeScript 的实现那样严格遵守规范。</p><p>打开 esModuleInterop 会在 TypeScript 编译的代码中修复这两个问题。第一个改变了编译器中的行为，第二个通过两个新的帮助函数修复，这两个帮助函数提供了一个机制，以确保所生成的 JavaScript 可以兼容。</p><h4 id="forceConsistentCasingInFileNames"><a href="#forceConsistentCasingInFileNames" class="headerlink" title="forceConsistentCasingInFileNames"></a>forceConsistentCasingInFileNames</h4><p>当设置了这个选项后，如果一个程序试图用不同于磁盘上的大小写来引入一个文件，TypeScript 会提示一个错误。</p><h4 id="isolatedModules"><a href="#isolatedModules" class="headerlink" title="isolatedModules"></a>isolatedModules</h4><p>设置 <code>isolatedModules</code> 标志告诉 TypeScript，如果你写的某些代码不能被单文件编译过程正确解释，它会警告你。</p><h4 id="preserveSymlinks"><a href="#preserveSymlinks" class="headerlink" title="preserveSymlinks"></a>preserveSymlinks</h4><p>该配置与 Node.js 中相同的标志含义相同;不解析符号链接的实际路径。</p><h4 id="verbatimModuleSyntax"><a href="#verbatimModuleSyntax" class="headerlink" title="verbatimModuleSyntax"></a>verbatimModuleSyntax</h4><p>任何没有 <code>type</code> 修饰符的导入或导出都将保留。任何使用 <code>type</code> 修饰符的内容都将被完全删除。</p><h3 id="向后兼容性"><a href="#向后兼容性" class="headerlink" title="向后兼容性"></a>向后兼容性</h3><p>以下为废弃的或向后兼容配置：</p><p><code>charset</code> <code>keyofStringsOnly</code> <code>noImplicitUseStrict</code> <code>noStrictGenericChecks</code> <code>out</code> <code>suppressExcessPropertyErrors</code> <code>suppressImplicitAnyIndexErrors</code> <code>reactNamespace</code> <code>skipDefaultLibCheck</code></p><h3 id="语言与环境"><a href="#语言与环境" class="headerlink" title="语言与环境"></a>语言与环境</h3><h4 id="emitDecoratorMetadata"><a href="#emitDecoratorMetadata" class="headerlink" title="emitDecoratorMetadata"></a>emitDecoratorMetadata</h4><p>与模块 <code>reflect-metadata</code> 共同使用，启用对装饰器（decorator）生成类型元数据（metadata）的实现性支持。</p><h4 id="experimentalDecorators"><a href="#experimentalDecorators" class="headerlink" title="experimentalDecorators"></a>experimentalDecorators</h4><p>启用对 decorator 的实验性支持。</p><h4 id="jsx"><a href="#jsx" class="headerlink" title="jsx"></a>jsx</h4><p>控制文件中 JSX 结构如何生成 JavaScript。只影响 .tsx 文件。</p><table><thead><tr><th>可选项</th><th>含义</th></tr></thead><tbody><tr><td><code>react</code></td><td>带 JSX 的 js 文件会被转换成等效的 <code>React.createElement</code> 调用</td></tr><tr><td><code>react-jsx</code></td><td>带 JSX 的 js 文件会被转换成 <code>_jsx</code> 调用</td></tr><tr><td><code>react-jsxdev</code></td><td>带 JSX 的 js 文件会被转换成 <code>_jsx</code> 调用</td></tr><tr><td><code>preserve</code></td><td>带 JSX 的 js 文件中的 JSX 不会被转换</td></tr><tr><td><code>react-native</code></td><td>带 JSX 的 js 文件中的 JSX 不会被转换</td></tr></tbody></table><h4 id="jsxFactory"><a href="#jsxFactory" class="headerlink" title="jsxFactory"></a>jsxFactory</h4><p>使用 JSX 运行时编译 JSX 元素时，更改 <code>.js</code> 文件中调用的函数。最常见的更改是使用 <code>h</code> 或 <code>preact.h</code>，而不是默认的 <code>React.createElement</code>（如果使用 preact）。</p><h4 id="jsxFragmentFactory"><a href="#jsxFragmentFactory" class="headerlink" title="jsxFragmentFactory"></a>jsxFragmentFactory</h4><p>指定在带有 <code>jsxFactory</code> 编译器选项的目标 react JSX 生成时要使用的 JSX fragment 工厂函数，例如 <code>Fragment</code>。</p><h4 id="jsxImportSource"><a href="#jsxImportSource" class="headerlink" title="jsxImportSource"></a>jsxImportSource</h4><p>当 <code>jsx</code> 属性为为 “react jsx” 或 “react jsonxdev” 时，声明用于导入 <code>jsx</code> 和 <code>jsxs</code> 工厂函数的模块说明符。</p><p>默认值： <code>react</code></p><h4 id="lib"><a href="#lib" class="headerlink" title="lib"></a>lib</h4><p>用于使 TypeScript 包括与你指定的目标匹配的 JS 新功能的 API 的类型声明。</p><h4 id="moduleDetection"><a href="#moduleDetection" class="headerlink" title="moduleDetection"></a>moduleDetection</h4><p>此设置控制 TypeScript 如何确定文件是脚本还是模块。</p><table><thead><tr><th>可选项</th><th>含义</th></tr></thead><tbody><tr><td><code>auto</code></td><td>默认值，TypeScript 不仅会查找导入和导出语句，而且当使用 <code>module</code>:<code>nodenext</code> 或 <code>node16</code> 运行时，它还会检查 <code>package.json</code> 中的 <code>“type”</code> 字段是否设置为 “module”，当 <code>jsx</code> 配置项为 <code>react-jsx</code> 时，还会检查当前文件是否为 JSX 文件。</td></tr><tr><td><code>legacy</code></td><td>使用导入和导出语句来确定文件是否为模块。</td></tr><tr><td><code>force</code></td><td>确保每个非声明文件都被视为一个模块。</td></tr></tbody></table><h4 id="noLib"><a href="#noLib" class="headerlink" title="noLib"></a>noLib</h4><p>禁用自动包含任何库文件。如果设置了此选项，则会忽略 <code>lib</code> 配置项。</p><h4 id="target"><a href="#target" class="headerlink" title="target"></a>target</h4><p>target 配置项决定了哪些 JS 特性降级了，哪些保持不变。</p><h4 id="useDefineForClassFields"><a href="#useDefineForClassFields" class="headerlink" title="useDefineForClassFields"></a>useDefineForClassFields</h4><p>这个标志被用作迁移到即将到来的 class 字段标准版本的一部分。</p><p>默认值：如果 <code>target</code> 是 <code>ES2022</code> 或者更高版本（包括 <code>ESNext</code>） 则为 <code>true</code>，否则为 <code>false</code></p><h3 id="编译诊断"><a href="#编译诊断" class="headerlink" title="编译诊断"></a>编译诊断</h3><h4 id="diagnostics"><a href="#diagnostics" class="headerlink" title="diagnostics"></a>diagnostics</h4><p>输出诊断信息，用于调试。</p><h4 id="explainFiles"><a href="#explainFiles" class="headerlink" title="explainFiles"></a>explainFiles</h4><p>打印 TypeScript 认为是你项目一部分的文件名，以及它们成为编译一部分的原因。</p><h4 id="extendedDiagnostics"><a href="#extendedDiagnostics" class="headerlink" title="extendedDiagnostics"></a>extendedDiagnostics</h4><p>你可以使用这个标志来发现 TypeScript 在编译时把时间花在了哪里。这是一个用于全面了解代码库性能特征的工具。</p><h4 id="generateCpuProfile"><a href="#generateCpuProfile" class="headerlink" title="generateCpuProfile"></a>generateCpuProfile</h4><p>这个选项让你有机会让 TypeScript 在编译器运行期间输出 v8 CPU 配置文件。CPU 配置文件可以深入了解构建可能缓慢的原因。</p><p>默认值： <code>profile.cpuprofile</code></p><h4 id="listEmittedFiles"><a href="#listEmittedFiles" class="headerlink" title="listEmittedFiles"></a>listEmittedFiles</h4><p>将编译过程中生成的文件的名称打印到终端。</p><h4 id="listFiles"><a href="#listFiles" class="headerlink" title="listFiles"></a>listFiles</h4><p>打印编译过程中文件的名称。</p><h4 id="traceResolution"><a href="#traceResolution" class="headerlink" title="traceResolution"></a>traceResolution</h4><p>让 TypeScript 为每个处理过的文件打印有关它的解析过程的信息。</p><h3 id="项目"><a href="#项目" class="headerlink" title="项目"></a>项目</h3><h4 id="composite"><a href="#composite" class="headerlink" title="composite"></a>composite</h4><p><code>composite</code> 选项强制了某些约束，使得构建工具（包括 TypeScript 本身，在 <code>-—build</code> 模式下）能够快速确定项目是否已经构建完成。</p><h4 id="disableReferencedProjectLoad"><a href="#disableReferencedProjectLoad" class="headerlink" title="disableReferencedProjectLoad"></a>disableReferencedProjectLoad</h4><p>如果你的项目很大，你可以使用 disableReferencedProjectLoad 标志来禁用所有项目的自动加载。相反，当你通过编辑器打开文件时，会动态加载项目。</p><h4 id="disableSolutionSearching"><a href="#disableSolutionSearching" class="headerlink" title="disableSolutionSearching"></a>disableSolutionSearching</h4><p>当使用复合 TypeScript 项目时，该选项提供了一种方式来声明，当使用诸如 <em>查找所有引用</em> 或在编辑器中 <em>跳转到定义</em> 之类的特性时，你不希望包含某个项目。</p><h4 id="disableSourceOfProjectReferenceRedirect"><a href="#disableSourceOfProjectReferenceRedirect" class="headerlink" title="disableSourceOfProjectReferenceRedirect"></a>disableSourceOfProjectReferenceRedirect</h4><p>当使用复合 TypeScript 项目时，该选项提供了一种回到 Typescript 3.7 之前的行为的方法，在 Typescript 3.7 之前，<code>d.ts</code> 文件被用作模块之间的边界。</p><h4 id="incremental"><a href="#incremental" class="headerlink" title="incremental"></a>incremental</h4><p>告诉 TypeScript 将上次编译时的项目图信息保存到存储在磁盘上的文件 <code>.tsbuildinfo</code> 中。</p><p>默认值：如果 <code>composite</code> 配置项为 <code>true</code> 则为 <code>true</code>，否则为 <code>false</code>。</p><h4 id="tsBuildInfoFile"><a href="#tsBuildInfoFile" class="headerlink" title="tsBuildInfoFile"></a>tsBuildInfoFile</h4><p>这个设置允许你指定一个文件来存储增量编译信息，作为复合项目的一部分，这样可以更快地构建更大的 TypeScript 代码库。</p><p>默认值：<code>.tsbuildinfo</code></p><h3 id="输出格式化"><a href="#输出格式化" class="headerlink" title="输出格式化"></a>输出格式化</h3><h4 id="noErrorTruncation"><a href="#noErrorTruncation" class="headerlink" title="noErrorTruncation"></a>noErrorTruncation</h4><p>不要截断错误消息。</p><h4 id="preserveWatchOutput"><a href="#preserveWatchOutput" class="headerlink" title="preserveWatchOutput"></a>preserveWatchOutput</h4><p>是否将过时的控制台输出保持在监视模式，而不是每次发生更改时清除屏幕。</p><h4 id="pretty"><a href="#pretty" class="headerlink" title="pretty"></a>pretty</h4><p>使用颜色和上下文对错误和消息进行风格化，默认开启。</p><h3 id="完整性"><a href="#完整性" class="headerlink" title="完整性"></a>完整性</h3><h4 id="skipLibCheck"><a href="#skipLibCheck" class="headerlink" title="skipLibCheck"></a>skipLibCheck</h4><p>跳过声明文件的类型检查。</p><h3 id="监视选项"><a href="#监视选项" class="headerlink" title="监视选项"></a>监视选项</h3><h4 id="assumeChangesOnlyAffectDirectDependencies"><a href="#assumeChangesOnlyAffectDirectDependencies" class="headerlink" title="assumeChangesOnlyAffectDirectDependencies"></a>assumeChangesOnlyAffectDirectDependencies</h4><p>当启用这个选项时，TypeScript 将避免重新检查/重建所有真正可能受到影响的文件，只重新检查/重建那些已经改变的文件，以及那些直接导入它们的文件。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;概览&quot;&gt;&lt;a href=&quot;#概览&quot; class=&quot;headerlink&quot; title=&quot;概览&quot;&gt;&lt;/a&gt;概览&lt;/h2&gt;&lt;p&gt;当目录中出现了 &lt;code&gt;tsconfig.json&lt;/code&gt; 文件，则说明该目录是 TypeScript 项目的根目录。&lt;code&gt;</summary>
      
    
    
    
    
    <category term="typescript" scheme="https://mangon.cn/blog/tags/typescript/"/>
    
    <category term="tsconfig" scheme="https://mangon.cn/blog/tags/tsconfig/"/>
    
  </entry>
  
  <entry>
    <title>EventSource API</title>
    <link href="https://mangon.cn/blog/2023/08/04/FE-EventSource/"/>
    <id>https://mangon.cn/blog/2023/08/04/FE-EventSource/</id>
    <published>2023-08-04T07:22:51.000Z</published>
    <updated>2023-08-04T08:43:17.313Z</updated>
    
    <content type="html"><![CDATA[<p>EventSource 接口是 web 内容与服务器发送事件通信的接口。</p><p>一个 EventSource 实例会对 HTTP 服务器开启一个持久化的连接，以 <code>text/event-stream</code> 格式发送事件，此连接会一直保持开启直到通过调用 <code>EventSource.close()</code> 关闭。一旦连接开启，来自服务端传入的消息会以事件的形式分发至客户端中，如果接收消息中有一个 event 字段，触发的事件与 event 字段的值相同。如果不存在 event 字段，则将触发通用的 message 事件。</p><p>与 WebSocket 不同的是，服务器发送事件是单向的。数据消息只能从服务端发送到客户端（如用户的浏览器）。这使其成为不需要从客户端往服务器发送消息的情况下的最佳选择。</p><h2 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h2><p><code>EventSource()</code></p><p>创建一个新的 EventSource，用于从指定的 URL 接收服务器发送事件，可以选择开启凭据模式。</p><p>用法： <code>cosnt pc = new EventSource(url, configuration);</code></p><p>url 表示远程资源的位置，configuration 为配置新连接提供选项，目前只有一个可选项 withCredentials，默认为 false，指示 CORS 是否应包含凭据。</p><h2 id="实例属性"><a href="#实例属性" class="headerlink" title="实例属性"></a>实例属性</h2><p>此接口从其父接口 EventTarget 继承属性。</p><ul><li><p>EventSource.readyState 只读<br>一个代表连接状态的数字。可能值是 CONNECTING（0）、OPEN（1）或 CLOSED（2）。</p></li><li><p>EventSource.url 只读<br>一个表示事件源的 URL 字符串。</p></li><li><p>EventSource.withCredentials 只读<br>一个布尔值，表示 EventSource 对象是否使用跨域资源共享（CORS）凭据来实例化（true），或者不使用（false，即默认值）。</p></li></ul><h2 id="实例方法"><a href="#实例方法" class="headerlink" title="实例方法"></a>实例方法</h2><p>此接口从其父接口 EventTarget 继承方法。</p><ul><li>EventSource.close()<br>关闭连接（如果有），并将 readyState 属性设置为 CLOSED。如果连接已经关闭，则该方法不执行任何操作。</li></ul><h2 id="事件"><a href="#事件" class="headerlink" title="事件"></a>事件</h2><ul><li><p>error<br>在事件源连接未能打开时触发。</p></li><li><p>message<br>在从事件源接收到数据时触发。</p></li><li><p>open<br>在与事件源的连接打开时触发。</p></li></ul><p>此外，事件源本身可以发送具有 event 字段的消息，这将创建一个以该值为键的特定事件。</p><h2 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h2><p>在这个基本的例子中，创建了一个 EventSource 来从服务器接收未命名的事件；一个名为 sse.php 的页面负责生成这些事件。</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">const</span> evtSource = <span class="keyword">new</span> <span class="title class_">EventSource</span>(<span class="string">&quot;sse.php?message=hello&quot;</span>);</span><br><span class="line"><span class="keyword">const</span> eventList = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;ul&quot;</span>);</span><br><span class="line"></span><br><span class="line">evtSource.<span class="property">onmessage</span> = <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> newElement = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;li&quot;</span>);</span><br><span class="line"></span><br><span class="line">  newElement.<span class="property">textContent</span> = <span class="string">`message: <span class="subst">$&#123;e.data&#125;</span>`</span>;</span><br><span class="line">  eventList.<span class="title function_">appendChild</span>(newElement);</span><br><span class="line">  evtSource.<span class="title function_">close</span>();</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>每个接收到的事件都会导致我们的 EventSource 对象的 onmessage 事件处理程序运行。它会创建一个新的 <code>&lt;li&gt;</code> 元素，并将消息的数据写入其中，然后将新元素附加到文档中已有的列表元素中。</p><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> sse = <span class="keyword">new</span> <span class="title class_">EventSource</span>(<span class="string">&quot;/api/v1/sse&quot;</span>);</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="comment"> *</span></span><br><span class="line"><span class="comment"> * event: notice</span></span><br><span class="line"><span class="comment"> * data: useful data</span></span><br><span class="line"><span class="comment"> * id: someid</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">sse.<span class="title function_">addEventListener</span>(<span class="string">&quot;notice&quot;</span>, <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(e.<span class="property">data</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="comment"> * 同理，以下代码将监听具有字段 `event: update` 的事件</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">sse.<span class="title function_">addEventListener</span>(<span class="string">&quot;update&quot;</span>, <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(e.<span class="property">data</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="comment"> * “message”事件是一个特例，因为它可以捕获没有 event 字段的事件，</span></span><br><span class="line"><span class="comment"> * 以及具有特定类型 `event：message` 的事件。</span></span><br><span class="line"><span class="comment"> * 它不会触发任何其他类型的事件。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">sse.<span class="title function_">addEventListener</span>(<span class="string">&quot;message&quot;</span>, <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(e.<span class="property">data</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h2><ol><li><p>浏览器同域名下的HTTP请求数量是有限制的（例如Chrome浏览器的限制为6个），所以如果打开多个选项卡，这种长连接可能会因为占满限制名额而导致无法发送新的HTTP请求。</p></li><li><p>EventSource API 发送的HTTP请求为GET类型的，如果想要发送POST类型的HTTP请求，或者修改HTTP请求的headers，可以使用 <code>@microsoft/fetch-event-source</code> 库，该库对这种情况进行了polyfill，使用方法如下：</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">import</span> &#123; fetchEventSource &#125; <span class="keyword">from</span> <span class="string">&#x27;@microsoft/fetch-event-source&#x27;</span>;</span><br><span class="line"><span class="title function_">fetchEventSource</span>(url, &#123;</span><br><span class="line">  <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">  <span class="attr">headers</span>: &#123;</span><br><span class="line">    <span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;application/json&#x27;</span>,</span><br><span class="line">    <span class="title class_">Accept</span>: <span class="string">&#x27;*/*&#x27;</span>,</span><br><span class="line">    <span class="title class_">Connection</span>: <span class="string">&#x27;keep-alive&#x27;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">body</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(&#123;</span><br><span class="line">    <span class="attr">messages</span>: [&#123;</span><br><span class="line">      <span class="attr">content</span>: <span class="string">&#x27;Hello.&#x27;</span>,</span><br><span class="line">      <span class="attr">role</span>: <span class="string">&#x27;user&#x27;</span>,</span><br><span class="line">    &#125;],</span><br><span class="line">  &#125;),</span><br><span class="line">  <span class="title function_">onmessage</span>(<span class="params">event</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`EventSource onmessage <span class="subst">$&#123;<span class="built_in">Date</span>.now()&#125;</span>: <span class="subst">$&#123;event.data&#125;</span>`</span>);</span><br><span class="line">  &#125;，</span><br><span class="line">  <span class="title function_">onerror</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;EventSource onerror&#x27;</span>);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>类似的库还有 <code>event-source-polyfill</code> 库。</p></li><li><p>针对问答式的请求，服务器端返回的文本数据为流式时，EventSource API 相比 WebSocket 更加简单便捷，chatGPT 类问答服务多采用 EventSource API 来实现。</p></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;EventSource 接口是 web 内容与服务器发送事件通信的接口。&lt;/p&gt;
&lt;p&gt;一个 EventSource 实例会对 HTTP 服务器开启一个持久化的连接，以 &lt;code&gt;text/event-stream&lt;/code&gt; 格式发送事件，此连接会一直保持开启直到通过</summary>
      
    
    
    
    
    <category term="performance" scheme="https://mangon.cn/blog/tags/performance/"/>
    
    <category term="Web API" scheme="https://mangon.cn/blog/tags/Web-API/"/>
    
  </entry>
  
  <entry>
    <title>高级编程语言</title>
    <link href="https://mangon.cn/blog/2023/08/04/CS-%E9%AB%98%E7%BA%A7%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/"/>
    <id>https://mangon.cn/blog/2023/08/04/CS-%E9%AB%98%E7%BA%A7%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/</id>
    <published>2023-08-04T01:25:20.000Z</published>
    <updated>2023-08-04T07:13:12.718Z</updated>
    
    <content type="html"><![CDATA[<table><thead><tr><th>语言名称</th><th>发布时间</th><th>作者</th><th>特点</th></tr></thead><tbody><tr><td>Fortran</td><td>1957年</td><td>John Backus</td><td>Fortran是第一种高级编程语言，由IBM的John Backus和他的团队开发。它主要用于科学和工程计算，并在数值计算领域取得了巨大成功。</td></tr><tr><td>Lisp</td><td>1958年</td><td>John McCarthy</td><td>Lisp是第一种函数式编程语言，由John McCarthy开发。它在人工智能和符号处理领域得到广泛应用，并成为函数式编程的重要基础。</td></tr><tr><td>COBOL</td><td>1959年</td><td>Grace Hopper</td><td>COBOL是一种商业计算语言，由美国国家标准局（NBS）的Grace Hopper领导的团队开发。它被广泛用于商业和金融领域，并成为最早的通用商业计算语言之一。</td></tr><tr><td>Basic</td><td>1964年</td><td>John G. Kemeny</td><td>Basic语言于1964年由John G. Kemeny和Thomas E. Kurtz在达特茅斯学院开发。它是一种易学易用的高级编程语言，主要用于教育和初学者的编程。它具有简单的语法和交互式编程特性，适合用于学习编程基础和算法思维。</td></tr><tr><td>C</td><td>1972年</td><td>Dennis Ritchie</td><td>C语言由Dennis Ritchie在贝尔实验室开发。它是一种通用的高级编程语言，被广泛用于系统软件开发和操作系统编写。C语言也成为后来许多其他编程语言的基础。</td></tr><tr><td>C++</td><td>1983年</td><td>Bjarne Stroustrup</td><td>C++是由Bjarne Stroustrup在C语言基础上扩展而来的编程语言。它引入了面向对象编程的概念，并成为许多应用程序和系统软件的首选语言之一。</td></tr><tr><td>Python</td><td>1991年</td><td>Guido van Rossum</td><td>Python是由Guido van Rossum开发的一种高级编程语言。它以简洁和易读的语法而闻名，并在数据科学、人工智能和Web开发等领域得到广泛应用。</td></tr><tr><td>PHP</td><td>1994年</td><td>Rasmus Lerdorf</td><td>PHP于1994年由Rasmus Lerdorf创建，最初被称为”Personal Home Page”（个人主页）的缩写。它是一种功能强大、易学易用的服务器端脚本语言，适用于Web开发，并且拥有广泛的应用领域和活跃的开发者社区。</td></tr><tr><td>Ruby</td><td>1995年</td><td>松本行弘（Yukihiro Matsumoto）</td><td>Ruby是一种简洁而优雅的动态类型编程语言，注重开发人员的幸福感。它具有简单易读的语法和强大的元编程能力，被广泛应用于Web开发和脚本编程。</td></tr><tr><td>Java</td><td>1995年</td><td>James Gosling</td><td>Java是由Sun Microsystems（现在是Oracle）的James Gosling和他的团队开发的。它是一种跨平台的编程语言，被广泛应用于企业级应用程序和移动应用开发。</td></tr><tr><td>JavaScript</td><td>1995年</td><td>Brendan Eich</td><td>JavaScript于1995年由Brendan Eich在Netscape公司开发。JavaScript主要用于Web前端开发，包括网页交互、表单验证、动态内容更新、动画效果等。它也被广泛应用于移动应用开发（使用框架如React Native）、服务器端开发（使用Node.js）以及游戏开发（使用HTML5游戏引擎）等领域。</td></tr><tr><td>C#</td><td>2000年</td><td>Anders Hejlsberg</td><td>C#是一种由Microsoft开发的通用编程语言，用于开发Windows应用程序、Web应用程序和游戏等。它具有类似于Java的语法和面向对象编程的特性，被广泛应用于Microsoft生态系统中。</td></tr><tr><td>Scala</td><td>2003年</td><td>Martin Odersky</td><td>Scala是一种运行在Java虚拟机上的多范式编程语言，结合了面向对象编程和函数式编程的特性。它具有强大的静态类型系统和丰富的函数式编程库，被广泛应用于大数据处理和分布式系统开发。</td></tr><tr><td>Go</td><td>2009年</td><td>Robert Griesemer</td><td>Go语言于2009年由Google的Robert Griesemer、Rob Pike和Ken Thompson共同设计和开发。它是一种注重高效性能、简洁易学的编程语言，适用于并发编程和构建高性能的应用程序。它具有丰富的标准库和跨平台性，被广泛应用于各种领域的软件开发。</td></tr><tr><td>Rust</td><td>2010年</td><td>Graydon Hoare</td><td>Rust于2010年由Mozilla的Graydon Hoare开始开发，2015年首次发布。Rust主要用于系统级编程，如操作系统、嵌入式设备、网络服务和游戏引擎等领域。由于其内存安全和并发性能，Rust也逐渐在Web后端开发和网络安全领域得到应用。</td></tr><tr><td>Kotlin</td><td>2011年</td><td>Andrey Breslav</td><td>Kotlin是一种基于Java虚拟机的静态类型编程语言，由JetBrains开发。它具有与Java互操作性、简洁的语法和空安全等特性。Kotlin被广泛应用于Android应用程序开发，并逐渐成为替代Java的首选语言。</td></tr><tr><td>TypeScript</td><td>2012年</td><td>Microsoft</td><td>TypeScript于2012年由Microsoft推出。它主要用于Web前端开发，特别是大型项目和团队协作。通过引入静态类型检查，TypeScript可以提高代码的可维护性和可读性，减少潜在的错误。它也可以与现有的JavaScript代码无缝集成，逐步迁移项目到TypeScript。</td></tr><tr><td>Swift</td><td>2014年</td><td>Chris Lattner</td><td>Swift是由Apple开发的一种多用途编程语言，用于iOS、macOS、watchOS和tvOS应用程序开发。它具有现代化的语法、强大的类型推断和丰富的标准库，使得开发iOS应用变得更加高效和安全。</td></tr></tbody></table>]]></content>
    
    
      
      
    <summary type="html">&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;语言名称&lt;/th&gt;
&lt;th&gt;发布时间&lt;/th&gt;
&lt;th&gt;作者&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fortran&lt;/td&gt;
&lt;td&gt;1957年&lt;/td&gt;
&lt;td&gt;Joh</summary>
      
    
    
    
    
    <category term="language" scheme="https://mangon.cn/blog/tags/language/"/>
    
    <category term="programmer" scheme="https://mangon.cn/blog/tags/programmer/"/>
    
  </entry>
  
  <entry>
    <title>数据可视化平台调研</title>
    <link href="https://mangon.cn/blog/2023/02/27/CS-%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96%E5%B9%B3%E5%8F%B0%E8%B0%83%E7%A0%94/"/>
    <id>https://mangon.cn/blog/2023/02/27/CS-%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96%E5%B9%B3%E5%8F%B0%E8%B0%83%E7%A0%94/</id>
    <published>2023-02-27T14:54:37.000Z</published>
    <updated>2023-06-05T02:49:34.227Z</updated>
    
    <content type="html"><![CDATA[<h2 id="数据可视化（Data-Visualization）"><a href="#数据可视化（Data-Visualization）" class="headerlink" title="数据可视化（Data Visualization）"></a>数据可视化（Data Visualization）</h2><p>数据可视化是关于数据视觉表现形式的科学技术研究，主要旨在借助于图形化手段，清晰有效地传达与沟通信息。简单来说，数据可视化就是将数据转换成图或表等，以一种更直观的方式展现和呈现数据，让读者能“一眼看懂”你想表达的信息。通过“可视化”的方式，复杂的数据通过图形化的手段进行有效表达，准确高效、简洁全面地传递某种信息，甚至我们帮助发现某种规律和特征，挖掘数据背后的价值。<br>数据可视化主要应用在一些 <strong>报表类软件</strong> 、 <strong>商业智能（Business Intelligence,BI）分析工具</strong> 或 <strong>系统监控类应用</strong> 中。</p><h2 id="数据分析关键字"><a href="#数据分析关键字" class="headerlink" title="数据分析关键字"></a>数据分析关键字</h2><p><strong>维度</strong>：数据的维数一般是指数据不相干的几种特性，可以理解为数据分类的字段，比如地区、名称、日期等。<br><strong>钻取/下钻</strong>：钻取是改变维度的层次，变换分析的粒度。它包括向上钻取和向下钻取。通过向导的方式，用户可以定义分析因素的汇总行，例如对于各地区各年度的销售情况，可以生成地区与年度的合计行，也可以生成地区或者年度的合计行。<br><strong>联动</strong>：一张可视化图表可以用来对另一张可视化图表中已经录入的数据，进行直接或有条件地调用称为联动。</p><h2 id="可视化平台基础架构"><a href="#可视化平台基础架构" class="headerlink" title="可视化平台基础架构"></a>可视化平台基础架构</h2><p>数据可视化平台基础架构如下：</p><p><img src="/blog/static/imgs/datavisual/data-visual.svg" alt="data-visual_inner"></p><p>绿色代表重要的功能，红色代表可选功能，灰色代表不重要功能。</p><p>一般分为四层，从下到上依次为 <strong>数据源</strong>、<strong>数据集</strong>、<strong>视图层</strong>、<strong>仪表板</strong>，根据规模和实际应用情况，还会有 <strong>系统管理层</strong> 用来承接系统层面的公共功能。</p><p><strong>数据源</strong>为系统获取数据的来源，根据类型可以分为 数据库类（例如从 MySQL、SQLServer、Oracel等类型数据库中获取数据）、文件类（例如 Excel表格）、API。配置好数据源后，平台从数据源获取数据并进行导入。如果数据量过大，会有任务管理模块用来控制数据导入任务。一些系统会支持定时同步或实时获取（常见于系统监控类应用），另一些则是线下分析（常见于报表类软件）。<br>从数据源获取到的数据会被存放在平台的<strong>数据集</strong>中，支持查询与数据联动。一些平台支持根据规则进行计算，例如通过企业历史财务物料数据进行计划预算。<br><strong>视图层</strong>是指可视化图表可显示的模块与组件，视图层一般以图标库（例如Echarts）为基础，支持多种视图组件（例如柱状图、折线图等），用户需要设置组件的属性（例如宽、高、位置、颜色、背景等）、数据来源（从数据集中选择，X轴、Y轴的维度以及示例等）。一些可视化平台支持多图表联动及数据钻取，还有一些平台会支持对维度进行过滤。<br><strong>仪表盘</strong>是用户可见的可视化图表UI层。用户可以通过拖拽的方式进行图表的布局，一般平台也会支持多端查看（即在PC、移动端、大屏等多种终端上查看效果）。</p><h2 id="数据可视化工具"><a href="#数据可视化工具" class="headerlink" title="数据可视化工具"></a>数据可视化工具</h2><p>以下将列举出一些开源的数据可视化工具及平台：</p><table><thead><tr><th>工具</th><th>热度</th><th>开源协议</th><th>体验</th></tr></thead><tbody><tr><td>Grafana</td><td>54.1k</td><td>AGPL-3.0</td><td><a href="https://play.grafana.org/">在线体验</a></td></tr><tr><td>Apache Superset</td><td>50.7k</td><td>Apache-2.0</td></tr><tr><td>DataEase</td><td>9k</td><td>GPL-3.0</td><td><a href="https://dataease.fit2cloud.com/">在线体验</a> 用户名：demo 密码：dataease</td></tr><tr><td>DataV</td><td>7.5k</td><td>MIT</td><td>在线体验：<br><a href="http://datav.jiaminghi.com/demo/construction-data/index.html">施工养护综合数据</a><br><a href="http://datav.jiaminghi.com/demo/manage-desk/index.html">机电运维管理台</a><br><a href="http://datav.jiaminghi.com/demo/electronic-file/index.html">机电设备电子档案</a></td></tr><tr><td>big_screen</td><td>1.3k</td><td>MIT</td><td><a href="bigscreen.turboway.top/corp">在线体验</a></td></tr><tr><td>datart</td><td>1.2k</td><td>Apache-2.0</td><td><a href="http://datart-demo.retech.cc">在线体验</a> 用户名：demo 密码：123456</td></tr></tbody></table><h3 id="Grafana"><a href="#Grafana" class="headerlink" title="Grafana"></a>Grafana</h3><p><a href="https://github.com/grafana/grafana">Grafana</a> 是一款用于实时监控的开源平台。Grafana 支持对数据进行查询、可视化、提醒与维度分析，支持多种数据源。同时，通过 Grafana，团队成员可以共同创建、探索和分享仪表盘，并通过数据驱动业务成长。</p><p>Grafana效果预览：<br><img src="/blog/static/imgs/datavisual/grafana.png" alt="grafana_inner"></p><h3 id="Apache-Superset"><a href="#Apache-Superset" class="headerlink" title="Apache Superset"></a>Apache Superset</h3><p><a href="https://github.com/apache/superset">Apache Superset</a> 是一个面向企业的现代商业智能 web 应用和数据可视化平台。它与各种数据源集成良好，也可以与各种商业BI进行集成。</p><p>Superset效果预览：<br><img src="/blog/static/imgs/datavisual/superset.jpg" alt="superset_inner"></p><h3 id="DataEase"><a href="#DataEase" class="headerlink" title="DataEase"></a>DataEase</h3><p><a href="https://github.com/dataease/dataease">DataEase</a> 是一款开源的数据可视化分析工具，由 fit2cloud 飞致云开发。它支持 Excel、MySQL、ORACEL、SQLServer、MariaDB、达梦、人大金仓 等多种数据源，能够通过拖拽方式快速制作图表，并且支持PC端、移动端、大屏等多种表现形式。</p><p>DataEase效果图预览：<br><img src="/blog/static/imgs/datavisual/dataease.gif" alt="dataease_inner"></p><!--DataEase技术栈：    前端：[Vue.js](https://vuejs.org/)、[Element](https://element.eleme.cn/#/)    图库：[Apache ECharts](https://github.com/apache/echarts)、[AntV](https://antv.vision/zh/)    后端：[Spring Boot](https://spring.io/projects/spring-boot/)    中间件：[MySQL](https://www.mysql.com/)    数据处理：[Kettle](https://github.com/pentaho/pentaho-kettle)、[Apache Doris](https://github.com/apache/doris)    基础设施：[Docker](https://www.docker.com/)DataEase架构：![dataease_inner](/blog/static/imgs/datavisual/dataease_struc.jpg)--><h3 id="DataV"><a href="#DataV" class="headerlink" title="DataV"></a>DataV</h3><p><a href="https://github.com/DataV-Team/DataV">DataV</a> 是一个基于 Vue 的数据可视化组件库，提供用于提升页面视觉效果的 SVG 边框和装饰，提供常用的图表如折线图等，也提供了飞线图/轮播表等其他组件。</p><p>DataV效果图预览：<br><img src="/blog/static/imgs/datavisual/datav.jpg" alt="datav_inner"></p><h3 id="big-screen"><a href="#big-screen" class="headerlink" title="big_screen"></a>big_screen</h3><p><a href="https://github.com/TurboWay/big_screen">big_screen</a> 是一款数据大屏可视化工具,由 TurboWay 开发，通过 Python 工具获取数据并进行可视化展示。</p><p>big_screen效果图预览：<br><img src="/blog/static/imgs/datavisual/big_screen.jpg" alt="big_screen_inner"></p><!--big_screen 技术栈：前端 HTML后端 Python--><h3 id="datart"><a href="#datart" class="headerlink" title="datart"></a>datart</h3><p><a href="https://github.com/running-elephant/datart">datart</a> 是一款数据可视化开放平台，支持报表、仪表板、大屏、分析和可视化数据应用的敏捷构建。</p><p>datart效果图预览：<br><img src="/blog/static/imgs/datavisual/datart.jpg" alt="datart_inner"></p><!--datart架构：![datart_inner](/blog/static/imgs/datavisual/datart_struc.png)-->]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;数据可视化（Data-Visualization）&quot;&gt;&lt;a href=&quot;#数据可视化（Data-Visualization）&quot; class=&quot;headerlink&quot; title=&quot;数据可视化（Data Visualization）&quot;&gt;&lt;/a&gt;数据可视化（Data </summary>
      
    
    
    
    
    <category term="BI" scheme="https://mangon.cn/blog/tags/BI/"/>
    
    <category term="data-visualization" scheme="https://mangon.cn/blog/tags/data-visualization/"/>
    
  </entry>
  
  <entry>
    <title>限制并发数量的多请求执行</title>
    <link href="https://mangon.cn/blog/2023/02/09/FE-%E9%99%90%E5%88%B6%E5%B9%B6%E5%8F%91%E6%95%B0%E9%87%8F%E7%9A%84%E5%A4%9A%E8%AF%B7%E6%B1%82%E6%89%A7%E8%A1%8C/"/>
    <id>https://mangon.cn/blog/2023/02/09/FE-%E9%99%90%E5%88%B6%E5%B9%B6%E5%8F%91%E6%95%B0%E9%87%8F%E7%9A%84%E5%A4%9A%E8%AF%B7%E6%B1%82%E6%89%A7%E8%A1%8C/</id>
    <published>2023-02-09T09:19:03.000Z</published>
    <updated>2023-06-05T02:49:34.289Z</updated>
    
    <content type="html"><![CDATA[<p>在项目中，我们经常会遇到同时发送多个HTTP请求的情况，对于同域名的请求，浏览器会限制同时发起的请求数量，当超过浏览器并发请求限制时，超过的请求将会等待，直到有请求返回时才会进行下一次请求。这是浏览器的一种保护机制，为了防止通过浏览器发起过量的请求，耗尽资源。在小程序中也会有同样的机制，例如，微信小程序中说明 <code>wx.request</code> 的最大并发限制是 10 个，<code>wx.connectSocket</code> 的最大并发限制是 5 个（参见 <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html">微信小程序官方文档-基础能力/网络/使用说明-网络-3.网络请求-使用限制</a> ），但是这里有个BUG，在小程序中如果并发请求超过10个，并不会等待而是直接失败，所以实际上需要用户自己处理并发请求数，在超过10个时，请求需要在队列中等待而不是直接失败。</p><span id="more"></span><p>假如我们的请求方法 <code>request</code> 形如：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">request</span>(<span class="params">options</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="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`<span class="subst">$&#123;options&#125;</span> is start`</span>)</span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`<span class="subst">$&#123;options&#125;</span> is finished`</span>)</span><br><span class="line">            <span class="title function_">resolve</span>(&#123; <span class="attr">data</span>: options &#125;);</span><br><span class="line">        &#125;, <span class="number">3000</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>request</code> 是一个通用的请求方法，它接受请求的参数，返回请求的 Promise，其中 options 是形如 <code>&#123;url: &#39;&#39;, method: &#39;GET&#39;, params: &#123;&#125;&#125;</code> 的请求相关参数对象。</p><p>在业务中，我们会通过 <code>fetch</code> 方法获取请求内容并处理请求结果：</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">function</span> <span class="title function_">fetch</span>(<span class="params">options</span>) =&gt; &#123;</span><br><span class="line">    <span class="title function_">request</span>(options).<span class="title function_">then</span>(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="comment">// do something</span></span><br><span class="line">    &#125;).<span class="title function_">catch</span>(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="comment">// do something</span></span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>fetch</code> 是一个和业务相关的请求方法，它接受请求的参数，对请求的结果进行处理。</p><p>当发起多个并行请求时，最简单直接的方法就是使用 <code>Promise.all</code>:</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 多请求并行执行</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">parallelRequest</span>(<span class="params">optionsList</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">all</span>(optionsList.<span class="title function_">map</span>(<span class="function"><span class="params">options</span> =&gt;</span> <span class="title function_">request</span>(options)));</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">parallelRequest</span>([<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]).<span class="title function_">then</span>(<span class="variable language_">console</span>.<span class="property">log</span>);</span><br></pre></td></tr></table></figure><p>如果需要请求串行发送，可以通过 <code>async/await</code> 的方式等待前一个请求返回后再发起下一个请求:</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="comment">// 多请求串行执行</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">serialRequest</span>(<span class="params">optionsList</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> res = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; optionsList.<span class="property">length</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">let</span> result = <span class="keyword">await</span> <span class="title function_">request</span>(optionsList[i]);</span><br><span class="line">        res.<span class="title function_">push</span>(result);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">resolve</span>(res);</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">serialRequest</span>([<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]).<span class="title function_">then</span>(<span class="variable language_">console</span>.<span class="property">log</span>);</span><br></pre></td></tr></table></figure><p>串行是可以避免超过10个请求后，再次发送请求失败的问题，但是没有充分利用并行发送的数量，更好的方式是通过参数限制并发请求数：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 限制并发数量的多请求执行</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">multiRequest</span>(<span class="params">optionsList = [], maxNum</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> len = optionsList.<span class="property">length</span>;</span><br><span class="line">    <span class="keyword">const</span> result = <span class="keyword">new</span> <span class="title class_">Array</span>(len).<span class="title function_">fill</span>(<span class="literal">false</span>);</span><br><span class="line">    <span class="keyword">let</span> count = <span class="number">0</span>;</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">while</span> (count &lt; maxNum) &#123;</span><br><span class="line">            <span class="title function_">next</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">next</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">let</span> current = count++;</span><br><span class="line">            <span class="keyword">if</span> (current &gt;= len) &#123;</span><br><span class="line">                !result.<span class="title function_">includes</span>(<span class="literal">false</span>) &amp;&amp; <span class="title function_">resolve</span>(result);</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">const</span> options = optionsList[current];</span><br><span class="line">            <span class="title function_">request</span>(options)</span><br><span class="line">                .<span class="title function_">then</span>(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">                    result[current] = res;</span><br><span class="line">                    <span class="keyword">if</span> (current &lt; len) &#123;</span><br><span class="line">                        <span class="title function_">next</span>();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;).<span class="title function_">catch</span>(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">                    result[current] = err;</span><br><span class="line">                    <span class="keyword">if</span> (current &lt; len) &#123;</span><br><span class="line">                        <span class="title function_">next</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">&#125;</span><br><span class="line"><span class="title function_">multiRequest</span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>, <span class="number">10</span>], <span class="number">3</span>).<span class="title function_">then</span>(<span class="variable language_">console</span>.<span class="property">log</span>);</span><br></pre></td></tr></table></figure><p>实际业务场景中，我们并不会在一个地方同时发起多个请求，而是在不同的地方发起请求，所以限制并发数量的的 request 方法应该是一个工具函数：</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">// 提供给第三方使用的 request 方法，内部实现支持限制并发数量的请求</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">LimitRequest</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">limit</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">limit</span> = limit; <span class="comment">// 并发请求限制数量</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">tasks</span> = []; <span class="comment">// 请求等待队列</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">current</span> = <span class="number">0</span>; <span class="comment">// 当前并发请求数量</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">addRequest</span>(<span class="params">reqFn</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!reqFn || !(reqFn <span class="keyword">instanceof</span> <span class="title class_">Function</span>)) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;当前请求不是一个Function&#x27;</span>);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">push</span>(reqFn);</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">current</span> &lt; <span class="variable language_">this</span>.<span class="property">limit</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">run</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">async</span> <span class="title function_">run</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">current</span>++;</span><br><span class="line">            <span class="keyword">const</span> fn = <span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">shift</span>();</span><br><span class="line">            <span class="keyword">await</span> <span class="title function_">fn</span>();</span><br><span class="line">        &#125; <span class="keyword">catch</span>(err) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(err);</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">current</span>--;</span><br><span class="line">            <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">run</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="keyword">let</span> limitRequest = <span class="keyword">new</span> <span class="title class_">LimitRequest</span>(<span class="number">3</span>);</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">    limitRequest.<span class="title function_">addRequest</span>(fetch.<span class="title function_">bind</span>(<span class="literal">null</span>, i));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意上面用的是 fetch 方法，当需要发送请求时，需要确定请求返回后的处理逻辑，将整体的方法写成 fetch 方法，并通过 <code>addRequest</code> 添加到并行的队列中去。</p><p>我们也可以优化一下，使用 request 方法，这样可以在请求时不必确定返回后的逻辑，将 <em>请求</em> 这个动作与业务分离：</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><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">LimitRequest</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">limit</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">limit</span> = limit; <span class="comment">// 并发限制数量</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">tasks</span> = []; <span class="comment">// 等待的请求队列</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">current</span> = <span class="number">0</span>;  <span class="comment">// 当前进行中的请求数量</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">request</span>(<span class="params">options</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">let</span> reqFn = request.<span class="title function_">bind</span>(<span class="literal">null</span>, options);</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">push</span>([reqFn, resolve, reject]);</span><br><span class="line">            <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">current</span> &lt; <span class="variable language_">this</span>.<span class="property">limit</span>) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">run</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="keyword">async</span> <span class="title function_">run</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">current</span>++;</span><br><span class="line">            <span class="keyword">const</span> [fn, resolve, reject] = <span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">shift</span>();</span><br><span class="line">            <span class="keyword">await</span> <span class="title function_">fn</span>().<span class="title function_">then</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">                <span class="title function_">resolve</span>(res);</span><br><span class="line">            &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">                <span class="title function_">reject</span>(err);</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125; <span class="keyword">catch</span>(err) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(err);</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">current</span>--;</span><br><span class="line">            <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">run</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><br><span class="line"><span class="keyword">let</span> limitRequest = <span class="keyword">new</span> <span class="title class_">LimitRequest</span>(<span class="number">3</span>);</span><br><span class="line"><span class="keyword">let</span> newRequest = limitRequest.<span class="property">request</span>.<span class="title function_">bind</span>(limitRequest);</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">    <span class="title function_">newRequest</span>(i).<span class="title function_">then</span>(<span class="variable language_">console</span>.<span class="property">log</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>作为 utils 方法，可以这样写：</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><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> limit = <span class="number">3</span>; <span class="comment">// 并发限制数量</span></span><br><span class="line"><span class="keyword">let</span> tasks = []; <span class="comment">// 等待的请求队列</span></span><br><span class="line"><span class="keyword">let</span> current = <span class="number">0</span>;  <span class="comment">// 当前进行中的请求数量</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">limitRequest</span>(<span class="params">options</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">let</span> reqFn = request.<span class="title function_">bind</span>(<span class="literal">null</span>, options);</span><br><span class="line">        tasks.<span class="title function_">push</span>([reqFn, resolve, reject]);</span><br><span class="line">        <span class="keyword">if</span> (current &lt; limit) &#123;</span><br><span class="line">            <span class="title function_">run</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="keyword">export</span> <span class="keyword">function</span> <span class="title function_">setLimit</span>(<span class="params">num</span>) &#123;</span><br><span class="line">    limit = num;</span><br><span class="line">&#125;</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">try</span> &#123;</span><br><span class="line">        current++;</span><br><span class="line">        <span class="keyword">const</span> [fn, resolve, reject] = <span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">shift</span>();</span><br><span class="line">        <span class="keyword">await</span> <span class="title function_">fn</span>().<span class="title function_">then</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="title function_">resolve</span>(res);</span><br><span class="line">        &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="title function_">reject</span>(err);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125; <span class="keyword">catch</span>(err) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(err);</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        current--;</span><br><span class="line">        <span class="keyword">if</span> (tasks.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="title function_">run</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">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">    <span class="title function_">limitRequest</span>(i).<span class="title function_">then</span>(<span class="variable language_">console</span>.<span class="property">log</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;在项目中，我们经常会遇到同时发送多个HTTP请求的情况，对于同域名的请求，浏览器会限制同时发起的请求数量，当超过浏览器并发请求限制时，超过的请求将会等待，直到有请求返回时才会进行下一次请求。这是浏览器的一种保护机制，为了防止通过浏览器发起过量的请求，耗尽资源。在小程序中也会有同样的机制，例如，微信小程序中说明 &lt;code&gt;wx.request&lt;/code&gt; 的最大并发限制是 10 个，&lt;code&gt;wx.connectSocket&lt;/code&gt; 的最大并发限制是 5 个（参见 &lt;a href=&quot;https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html&quot;&gt;微信小程序官方文档-基础能力/网络/使用说明-网络-3.网络请求-使用限制&lt;/a&gt; ），但是这里有个BUG，在小程序中如果并发请求超过10个，并不会等待而是直接失败，所以实际上需要用户自己处理并发请求数，在超过10个时，请求需要在队列中等待而不是直接失败。&lt;/p&gt;</summary>
    
    
    
    
    <category term="interview" scheme="https://mangon.cn/blog/tags/interview/"/>
    
    <category term="front-end" scheme="https://mangon.cn/blog/tags/front-end/"/>
    
  </entry>
  
  <entry>
    <title>前端性能优化</title>
    <link href="https://mangon.cn/blog/2023/01/31/FE-%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
    <id>https://mangon.cn/blog/2023/01/31/FE-%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/</id>
    <published>2023-01-31T14:16:40.000Z</published>
    <updated>2023-06-05T02:49:34.279Z</updated>
    
    <content type="html"><![CDATA[<h2 id="目的"><a href="#目的" class="headerlink" title="目的"></a>目的</h2><p>对比两款功能相似的产品，我们如何才能说一个产品的性能优于另外一个产品呢，无外乎以下几种情况</p><ol><li>页面打开的速度快，用户可以很快的看到期望的内容</li><li>页面流转流畅，不会出现卡顿的情况</li><li>页面不会出现非预期的错误，例如白屏</li></ol><p>性能优化也即从技术的角度提升产品的用户体验。</p><span id="more"></span><h2 id="原则"><a href="#原则" class="headerlink" title="原则"></a>原则</h2><ol><li>建立性能监控机制<ol><li>打点记录pv/uv，首页进入占比</li><li>错误监控机制，记录JSError、http请求错误</li><li>记录白屏时间、首屏加载时间、用户可操作时间</li></ol></li><li>进行性能分析<ol><li>从性能数据进行分析</li><li>针对项目类型进行分析</li><li>从项目代码进行分析</li></ol></li><li>采用性能优化手段<ol><li>采用控制变量法评判性能优化的有效性</li><li>多次实验取平均值，减少误差</li></ol></li><li>建立常态化的性能准入机制</li></ol><h2 id="方向"><a href="#方向" class="headerlink" title="方向"></a>方向</h2><ol><li>减少请求次数</li><li>减小请求体积</li><li>加快请求速度</li><li>缩短渲染时间</li></ol><h2 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h2><h3 id="减少请求次数"><a href="#减少请求次数" class="headerlink" title="减少请求次数"></a>减少请求次数</h3><ol><li><p>静态资源用单独域名，与后端数据请求域名隔离</p></li><li><p>合并请求，合理利用浏览器同域名并发请求限制</p></li><li><p>使用 css sprite，减少图片请求次数</p></li><li><p>避免空 image src</p></li><li><p>避免 301 重定向</p></li><li><p>缓存 ajax 数据</p></li></ol><h3 id="减小请求体积"><a href="#减小请求体积" class="headerlink" title="减小请求体积"></a>减小请求体积</h3><ol><li><p>减少HTTP请求内容，例如列表进行分页</p></li><li><p>外部引用 js &amp; css 等静态资源而不是直接嵌入到 html 中</p></li><li><p>使用 gzip 压缩</p></li><li><p>对 JS,CSS 进行压缩混淆</p></li><li><p>Tree shaking，删除未使用的代码</p></li><li><p>减少cookie大小</p></li><li><p>压缩图片，优化图片大小，减少缩放，采用渐进式jpeg</p></li><li><p>减少组件的复杂度，减小组件体积</p></li><li><p>减少 favicon.icon 体积</p></li></ol><h3 id="加快请求速度"><a href="#加快请求速度" class="headerlink" title="加快请求速度"></a>加快请求速度</h3><ol><li><p>使用cdn，减少资源物理上与用户的距离</p></li><li><p>添加 expires/cache-control/etag header 字段，利用浏览器的缓存策略</p></li><li><p>预加载组件</p></li></ol><h3 id="缩短渲染时间"><a href="#缩短渲染时间" class="headerlink" title="缩短渲染时间"></a>缩短渲染时间</h3><ol><li><p>将 css 放到 html 顶部加载，将 js 放到底部加载</p></li><li><p>减少 dom 元素个数</p></li><li><p>减少 dom 操作</p></li><li><p>减少 iframes</p></li><li><p>采用事件委托</p></li></ol>]]></content>
    
    
    <summary type="html">&lt;h2 id=&quot;目的&quot;&gt;&lt;a href=&quot;#目的&quot; class=&quot;headerlink&quot; title=&quot;目的&quot;&gt;&lt;/a&gt;目的&lt;/h2&gt;&lt;p&gt;对比两款功能相似的产品，我们如何才能说一个产品的性能优于另外一个产品呢，无外乎以下几种情况&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;页面打开的速度快，用户可以很快的看到期望的内容&lt;/li&gt;
&lt;li&gt;页面流转流畅，不会出现卡顿的情况&lt;/li&gt;
&lt;li&gt;页面不会出现非预期的错误，例如白屏&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;性能优化也即从技术的角度提升产品的用户体验。&lt;/p&gt;</summary>
    
    
    
    
    <category term="front-end" scheme="https://mangon.cn/blog/tags/front-end/"/>
    
  </entry>
  
  <entry>
    <title>React-diff算法原理及优化</title>
    <link href="https://mangon.cn/blog/2023/01/30/React-diff%E7%AE%97%E6%B3%95%E5%8E%9F%E7%90%86%E5%8F%8A%E4%BC%98%E5%8C%96/"/>
    <id>https://mangon.cn/blog/2023/01/30/React-diff%E7%AE%97%E6%B3%95%E5%8E%9F%E7%90%86%E5%8F%8A%E4%BC%98%E5%8C%96/</id>
    <published>2023-01-30T07:01:56.000Z</published>
    <updated>2023-06-05T02:49:34.353Z</updated>
    
    <content type="html"><![CDATA[<h2 id="React的渲染过程"><a href="#React的渲染过程" class="headerlink" title="React的渲染过程"></a>React的渲染过程</h2><ul><li>如果是HTML标签则直接渲染真实DOM</li><li>如果是JSX，则按以下流程进行<ol><li>将JSX转换成 <code>createElement</code> 的代码</li><li>执行 <code>createElement</code> 创建虚拟DOM, 得到虚拟DOM树</li><li>根据虚拟DOM树在界面上生成真实DOM</li></ol></li></ul><p>JSX<br><figure class="highlight jsx"><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">&lt;div&gt;</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="tag">&lt;<span class="name">p</span>&gt;</span>我是段落<span class="tag">&lt;/<span class="name">p</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="tag">&lt;<span class="name">span</span>&gt;</span>我是span<span class="tag">&lt;/<span class="name">span</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure></p><p>转换为 <code>createElement</code> 代码</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></pre></td><td class="code"><pre><span class="line"><span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">&quot;div&quot;</span>, <span class="literal">null</span>,</span><br><span class="line">    <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">&quot;div&quot;</span>, <span class="literal">null</span>,</span><br><span class="line">        <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">&quot;p&quot;</span>, <span class="literal">null</span>, <span class="string">&quot;我是段落&quot;</span>)),</span><br><span class="line">    <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">&quot;div&quot;</span>, <span class="literal">null</span>,</span><br><span class="line">        <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">&quot;span&quot;</span>, <span class="literal">null</span>, <span class="string">&quot;我是span&quot;</span>))</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>生成虚拟DOM<br><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">&#123;</span><br><span class="line"> <span class="attr">targetName</span>: <span class="string">&#x27;div&#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">targetName</span>: <span class="string">&#x27;div&#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">targetName</span>: <span class="string">&#x27;p&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line">     ]</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">     <span class="attr">targetName</span>: <span class="string">&#x27;div&#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">targetName</span>: <span class="string">&#x27;span&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line">     ]</span><br><span class="line">    &#125;</span><br><span class="line"> ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><h2 id="Diff算法的原理"><a href="#Diff算法的原理" class="headerlink" title="Diff算法的原理"></a>Diff算法的原理</h2><p>更新时为了避免，为了计算出 Virtual DOM 中真正变化的部分，并只针对该部分进行原生 DOM 操作，而非重新渲染整个页面。React 使用了 Diff 算法对虚拟 DOM 的变化进行比较，基本原则为：</p><ul><li>进行同层同位置的比较</li><li>如果是相同类型的元素，记录变化</li><li>如果是不同类型的元素，删除以前的，使用新的</li></ul><h2 id="Diff算法的优化"><a href="#Diff算法的优化" class="headerlink" title="Diff算法的优化"></a>Diff算法的优化</h2><p>Diff算法虽然只进行同层同位置的比较，但也有一些优化：</p><ol><li>同层节点之间相互比较，不会跨节点比较(tree diff)；</li><li>拥有相同类的两个组件将会生成相似的树形结构，拥有不同类的两个组件将会生成不同的树形结构。(component diff)；</li><li>可以通过唯一 key 来指定哪些节点在不同的渲染下保持稳定(element diff）；</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;React的渲染过程&quot;&gt;&lt;a href=&quot;#React的渲染过程&quot; class=&quot;headerlink&quot; title=&quot;React的渲染过程&quot;&gt;&lt;/a&gt;React的渲染过程&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;如果是HTML标签则直接渲染真实DOM&lt;/li&gt;
&lt;li&gt;如果是</summary>
      
    
    
    
    
    <category term="react" scheme="https://mangon.cn/blog/tags/react/"/>
    
  </entry>
  
</feed>
