<?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>2025-02-24T12:00:48.888Z</updated>
  <id>https://mangon.cn/blog/</id>
  
  <author>
    <name>Mangon</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <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>前端常用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>2023-09-22T03:13:31.655Z</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>Babel: 版本&gt;7.12 使用 <code>@babel/plugin-proposal-class-properties</code> 插件，配置 <code>[&quot;@babel/plugin-proposal-class-properties&quot;, &#123; &quot;loose&quot;: false &#125;]</code></li><li>Typescript: 在 tsconfig.json 中启用编译器选项 <code>&quot;useDefineForClassFields&quot;: true</code></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 改变时自动且原子化地更新。因此不能观察中间值。</li><li>所有的 derivations 默认将会同步更新，这意味着 action 可以在 state 改变之后安全的直接获得 computed value。</li><li>computed value 的更新是惰性的，任何 computed value 在需要他们的副作用发生之前都是不激活的。</li><li>所有的 computed value 都应是纯函数，他们不应该修改 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>2023-09-19T08:25:19.670Z</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">&quot;./constants&quot;</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">&quot;use strict&quot;</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">&quot;__esModule&quot;</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">&quot;./constants&quot;</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><span class="line">15</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">&quot;object&quot;</span> &amp;&amp; <span class="keyword">typeof</span> <span class="variable language_">module</span>.<span class="property">exports</span> === <span class="string">&quot;object&quot;</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><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> define === <span class="string">&quot;function&quot;</span> &amp;&amp; define.<span class="property">amd</span>) &#123;</span><br><span class="line">        <span class="title function_">define</span>([<span class="string">&quot;require&quot;</span>, <span class="string">&quot;exports&quot;</span>, <span class="string">&quot;./constants&quot;</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">&quot;use strict&quot;</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">&quot;__esModule&quot;</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">&quot;./constants&quot;</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">&quot;require&quot;</span>, <span class="string">&quot;exports&quot;</span>, <span class="string">&quot;./constants&quot;</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">&quot;use strict&quot;</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">&quot;__esModule&quot;</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">&quot;./constants&quot;</span>], <span class="keyword">function</span> (<span class="params">exports_1, context_1</span>) &#123;</span><br><span class="line">    <span class="string">&quot;use strict&quot;</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">&quot;twoPi&quot;</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">&quot;./constants&quot;</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">&quot;./constants&quot;</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">&quot;use strict&quot;</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">&quot;__esModule&quot;</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">&quot;./constants&quot;</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">&quot;react&quot;</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">&quot;react&quot;</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 或未设置）d，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 (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>
  
  <entry>
    <title>前端常见面试题索引</title>
    <link href="https://mangon.cn/blog/2023/01/30/FE-%E9%9D%A2%E8%AF%95%E7%B4%A2%E5%BC%95/"/>
    <id>https://mangon.cn/blog/2023/01/30/FE-%E9%9D%A2%E8%AF%95%E7%B4%A2%E5%BC%95/</id>
    <published>2023-01-30T05:23:30.000Z</published>
    <updated>2023-06-05T02:49:34.289Z</updated>
    
    <content type="html"><![CDATA[<style>.article-body>.article-item {    display: flex;    flex-wrap: wrap;}.article-body>.article-item>a {    margin: 20px;}</style><h2 id="网络"><a href="#网络" class="headerlink" title="网络"></a>网络</h2><div class="article-item"><br><br><a href="/blog/2021/04/22/HTTP小抄/#HTTPS">HTTPS相对HTTP的区别</a><br><a href="/blog/2021/12/29/HTTP-Cookie/">HTTP Cookie的作用</a><br><a href="/blog/2021/04/23/HTTP-缓存/">HTTP 强缓存与协商缓存</a><br><a href="/blog/2021/12/30/HTTP-同源策略与跨域/">浏览器同源策略与跨域</a><br><a href="/blog/2022/01/04/FE-浏览器架构与基本原理/#浏览器工作流程（页面加载过程）">浏览器中从输入URL到页面加载的流程</a><br><a href="/blog/2021/03/19/HTML-cookie、sessionStorage、localStorage区别与作用/">Cookie与sessionStorage、localStorage的区别</a><br><br></div><h2 id="安全"><a href="#安全" class="headerlink" title="安全"></a>安全</h2><div class="article-item"><br><br><a href="/blog/2018/09/10/HACK-CSRF攻击/#CSRF防范">如何防范CSRF攻击</a><br><a href="/blog/2018/09/09/HACK-XSS攻击/#XSS防御">如何防范XSS攻击</a><br><br></div><h2 id="性能"><a href="#性能" class="headerlink" title="性能"></a>性能</h2><div class="article-item"><br><br><a href="/blog/2023/01/31/FE-前端性能优化/#方法">性能优化的方法</a><br><br></div><h2 id="工程化"><a href="#工程化" class="headerlink" title="工程化"></a>工程化</h2><div class="article-item"><br><br><a href="/blog/2021/03/22/FE-前端工程化/">谈谈你对前端工程化的理解</a><br><a href="/blog/2020/05/22/FE-Javascript模块化/">模块化</a><br><a href="/blog/2022/12/26/FE-前端异常监控/">前端异常监控</a><br><br></div><h2 id="前端趋势"><a href="#前端趋势" class="headerlink" title="前端趋势"></a>前端趋势</h2><div class="article-item"><br><br><a href="/blog/2021/03/25/HTML-HTML5特性/">HTML5特性</a><br><a href="/blog/2020/08/28/JS-ES6特性/">ES6特性</a><br><a href="/blog/2021/03/26/CSS-CSS3特性/">CSS3特性</a><br><a href="/blog/2023/01/06/React-React18新功能和作用/">React18新特性</a><br><a href="/blog/2021/03/30/Vue-Vue3新功能和作用/">Vue3新特性</a><br><a href="/blog/2021/04/22/HTTP小抄/#HTTP2-特性">HTTP2新特性</a><br><br></div><h2 id="JS"><a href="#JS" class="headerlink" title="JS"></a>JS</h2><div class="article-item"><br><br><a href="/blog/2021/03/20/JS-数据类型/">数据类型</a><br><a href="/blog/2021/03/24/JS-原型链/">原型链</a><br><a href="/blog/2021/04/26/JS-继承/">继承</a><br><a href="/blog/2021/03/19/JS-闭包/">闭包</a><br><a href="/blog/2018/08/31/JS-防抖与截流/">防抖与截流的区别</a><br><a href="/blog/2021/03/19/JS-js的异步运行机制/">任务队列与事件循环</a><br><a href="/blog/2021/04/20/JS-js内存回收机制/">内存回收机制gc</a><br><a href="/blog/2021/03/23/JS-Promise/">Promise</a><br><a href="/blog/2022/11/23/JS-Object-对象/">Object</a><br><a href="/blog/2021/03/21/JS-Array-数组/">Array</a><br><a href="/blog/2022/11/22/JS-Function-函数/">Function</a><br><a href="/blog/2022/11/22/JS-String-字符串/">String</a><br><br></div><h2 id="HTML"><a href="#HTML" class="headerlink" title="HTML"></a>HTML</h2><div class="article-item"><br><br><a href="/blog/2021/03/19/HTML-事件绑定-事件委托/">事件绑定与事件委托</a><br><a href="/blog/2021/03/19/HTML-页面渲染html的过程/">页面渲染HTML的过程</a><br><br></div><h2 id="CSS"><a href="#CSS" class="headerlink" title="CSS"></a>CSS</h2><div class="article-item"><br><br><a href="/blog/2018/12/06/CSS-Flex布局/">Flex布局</a><br><a href="/blog/2018/09/18/CSS-长度单位/">CSS长度单位有哪些</a><br><a href="/blog/2021/03/19/CSS-水平-垂直居中/">CSS水平居中与垂直居中</a><br><a href="/blog/2021/03/16/CSS-transform-transition-animation/">CSS属性transition、transform、animation</a><br><br></div><h2 id="Vue"><a href="#Vue" class="headerlink" title="Vue"></a>Vue</h2><div class="article-item"><br><br><a href="/blog/2021/04/24/Vue-Vue生命周期/">Vue生命周期有哪些</a><br><a href="/blog/2018/10/12/Vue-组件间通信/">Vue如何实现组件间通信</a><br><a href="/blog/2022/11/29/Vue-Vue面试手册/#Vue-2-0-响应式数据的原理">Vue响应式数据的原理</a><br><a href="/blog/2019/02/12/Vue-读Vue源码所能想到的面试问题/#哪些数据变化情况无法被-Vue-的响应式系统观测到，应该如何处理？">Vue中哪些数据类型变化时无法被Vue的响应式系统观测到，应该如何处理</a><br><a href="/blog/2021/04/21/Vue-keep-alive实现原理/">Vue keep-alive实现原理</a><br><a href="/blog/2021/04/24/Vue-Vue最佳实践/">Vue有哪些最佳实践</a><br><br></div><h2 id="React"><a href="#React" class="headerlink" title="React"></a>React</h2><div class="article-item"><br><br><a href="/blog/2022/11/24/React-React组件/">React 组件</a><br><a href="/blog/2022/11/25/React-React-Hook/">React Hook</a><br><a href="/blog/2022/11/24/React-React组件的状态state与属性props/">React组件的状态state与属性props</a><br><a href="/blog/2018/09/06/React-React父子组件数据传递/">React父子组件数据传递</a><br><a href="/blog/2022/11/25/React-Virtual-DOM/">React Virtual DOM</a><br><a href="/blog/2023/01/30/React-diff算法原理及优化/">React Diff 算法原理及优化</a><br><a href="/blog/2021/11/29/React-router速读速懂/">React Router</a><br><a href="/blog/2022/11/25/React-Redux小抄/">Redux</a><br><a href="/blog/2022/11/24/React-对比Vue和React/">React与Vue区别</a><br><br></div><h2 id="小程序"><a href="#小程序" class="headerlink" title="小程序"></a>小程序</h2><div class="article-item"><br><br><a href="/blog/2021/04/20/FE-jsBridge/">JS Bridge原理</a><br><br></div><h2 id="Webpack"><a href="#Webpack" class="headerlink" title="Webpack"></a>Webpack</h2><div class="article-item"><br><br><a href="/blog/2021/01/19/FE-webpack小抄/">Webpack</a><br><a href="/blog/2021/01/19/FE-webpack小抄/#loader-和-plugin-的区别">Webpack loader 和 plugin 的区别</a><br><a href="/blog/2021/01/19/FE-webpack小抄/#webpack-Tree-shaking原理">Webpack Tree-shaking原理</a><br><br></div>]]></content>
    
    
      
      
    <summary type="html">&lt;style&gt;
.article-body&gt;.article-item {
    display: flex;
    flex-wrap: wrap;
}
.article-body&gt;.article-item&gt;a {
    margin: 20px;
}
&lt;/style&gt;</summary>
      
    
    
    
    
    <category term="interview" scheme="https://mangon.cn/blog/tags/interview/"/>
    
  </entry>
  
  <entry>
    <title>React18新功能和作用</title>
    <link href="https://mangon.cn/blog/2023/01/06/React-React18%E6%96%B0%E5%8A%9F%E8%83%BD%E5%92%8C%E4%BD%9C%E7%94%A8/"/>
    <id>https://mangon.cn/blog/2023/01/06/React-React18%E6%96%B0%E5%8A%9F%E8%83%BD%E5%92%8C%E4%BD%9C%E7%94%A8/</id>
    <published>2023-01-06T08:13:04.000Z</published>
    <updated>2023-06-05T02:49:34.347Z</updated>
    
    <content type="html"><![CDATA[<p>2022 年 3 月 29 日 React18 正式发布。</p><p>React18 放弃了对 IE11 的支持。</p><h2 id="新增-createRoot-API-并支持并发模式渲染"><a href="#新增-createRoot-API-并支持并发模式渲染" class="headerlink" title="新增 createRoot API 并支持并发模式渲染"></a>新增 createRoot API 并支持并发模式渲染</h2><p>为了更好的管理 root 节点，React18 引入了一个新的 root API，新的 root API 还支持并发模式的渲染（new concurrent renderer），允许进入并发模式（concurrent mode）。</p><p>React18 从 <em>同步不可中断的更新</em> 变成了 <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></pre></td><td class="code"><pre><span class="line"><span class="comment">// React 17</span></span><br><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> <span class="title class_">App</span> <span class="keyword">from</span> <span class="string">&#x27;./App&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> root = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;root&#x27;</span>)!;</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">App</span> /&gt;</span></span>, root);</span><br><span class="line"></span><br><span class="line"><span class="comment">// React 18</span></span><br><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/client&#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&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> root = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;root&#x27;</span>)!;</span><br><span class="line"></span><br><span class="line"><span class="title class_">ReactDOM</span>.<span class="title function_">createRoot</span>(root).<span class="title function_">render</span>(<span class="language-xml"><span class="tag">&lt;<span class="name">App</span> /&gt;</span></span>);</span><br></pre></td></tr></table></figure><p>同时，在卸载组件时，我们也需要将 <code>unmountComponentAtNode</code> 升级为 <code>root.unmount</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">// React 17</span></span><br><span class="line"><span class="title class_">ReactDOM</span>.<span class="title function_">unmountComponentAtNode</span>(root);</span><br><span class="line"></span><br><span class="line"><span class="comment">// React 18</span></span><br><span class="line">root.<span class="title function_">unmount</span>();</span><br></pre></td></tr></table></figure><p>除此之外，React18 还从 render 方法中删除了回调函数，因为当使用 Suspense 时，它通常不会有预期的结果。</p><p>在新版本中，如果需要在 render 方法中使用回调函数，我们可以在组件中通过 useEffect 实现：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// React 17</span></span><br><span class="line"><span class="keyword">const</span> root = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;root&#x27;</span>)!;</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">App</span> /&gt;</span></span>, root, <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">&#x27;渲染完成&#x27;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// React 18</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">AppWithCallback</span>: <span class="title class_">React</span>.<span class="property">FC</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="title function_">useEffect</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">&#x27;渲染完成&#x27;</span>);</span><br><span class="line">  &#125;, []);</span><br><span class="line">  <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">App</span> /&gt;</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">const</span> root = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;root&#x27;</span>)!;</span><br><span class="line"><span class="title class_">ReactDOM</span>.<span class="title function_">createRoot</span>(root).<span class="title function_">render</span>(<span class="language-xml"><span class="tag">&lt;<span class="name">AppWithCallback</span> /&gt;</span></span>);</span><br></pre></td></tr></table></figure><p>最后，如果项目使用了服务端渲染（SSR），需要把 <code>ReactDOM.hydration</code> 升级为 <code>ReactDOM.hydrateRoot</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="comment">// React 17</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">const</span> root = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;root&#x27;</span>);</span><br><span class="line"><span class="title class_">ReactDOM</span>.<span class="title function_">hydrate</span>(<span class="language-xml"><span class="tag">&lt;<span class="name">App</span> /&gt;</span></span>, root);</span><br><span class="line"></span><br><span class="line"><span class="comment">// React 18</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/client&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> root = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;root&#x27;</span>)!;</span><br><span class="line"><span class="title class_">ReactDOM</span>.<span class="title function_">hydrateRoot</span>(root, <span class="language-xml"><span class="tag">&lt;<span class="name">App</span> /&gt;</span></span>);</span><br></pre></td></tr></table></figure><p>另外，还需要更新 TypeScript 类型定义，如果项目使用了 TypeScript，最值得注意的变化是，现在在定义 props 类型时，如果需要获取子组件 children ，那么需要显式的定义它，例如这样：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// React 17</span></span><br><span class="line">interface <span class="title class_">MyButtonProps</span> &#123;</span><br><span class="line">  <span class="attr">color</span>: string;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">MyButton</span>: <span class="title class_">React</span>.<span class="property">FC</span>&lt;<span class="title class_">MyButtonProps</span>&gt; = <span class="function">(<span class="params">&#123; children &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 在 React 17 的 FC 中，默认携带了 children 属性</span></span><br><span class="line">  <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;children&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></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 class_">MyButton</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// React 18</span></span><br><span class="line">interface <span class="title class_">MyButtonProps</span> &#123;</span><br><span class="line">  <span class="attr">color</span>: string;</span><br><span class="line">  children?: <span class="title class_">React</span>.<span class="property">ReactNode</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">MyButton</span>: <span class="title class_">React</span>.<span class="property">FC</span>&lt;<span class="title class_">MyButtonProps</span>&gt; = <span class="function">(<span class="params">&#123; children &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 在 React 18 的 FC 中，不存在 children 属性，需要手动申明</span></span><br><span class="line">  <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;children&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></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 class_">MyButton</span>;</span><br></pre></td></tr></table></figure><h2 id="setState-自动批量处理更新"><a href="#setState-自动批量处理更新" class="headerlink" title="setState 自动批量处理更新"></a>setState 自动批量处理更新</h2><p>批处理是指为了获得更好的性能，在数据层，将多个状态更新批量处理，合并成一次更新（在视图层，将多个渲染合并成一次渲染）。</p><p>在 React18 之前，只有在 react 事件处理函数中，才会自动执行批处理，其它情况会多次更新；在 React18 之后，任何情况都会自动执行批处理，多次更新始终合并为一次。</p><p>React18 通过在默认情况下执行批处理来实现了开箱即用的性能改进。</p><h2 id="新增-flushSync-手动退出批量更新"><a href="#新增-flushSync-手动退出批量更新" class="headerlink" title="新增 flushSync 手动退出批量更新"></a>新增 flushSync 手动退出批量更新</h2><p>批处理是一个破坏性改动，如果想退出批量更新，可以使用 <code>flushSync</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><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>, &#123; useState &#125; <span class="keyword">from</span> <span class="string">&#x27;react&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; flushSync &#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">const</span> <span class="title class_">App</span>: <span class="title class_">React</span>.<span class="property">FC</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> [count1, setCount1] = <span class="title function_">useState</span>(<span class="number">0</span>);</span><br><span class="line">  <span class="keyword">const</span> [count2, setCount2] = <span class="title function_">useState</span>(<span class="number">0</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></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">      <span class="attr">onClick</span>=<span class="string">&#123;()</span> =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-xml">        flushSync(() =&gt; &#123;</span></span><br><span class="line"><span class="language-xml">          setCount1(count =&gt; count + 1);</span></span><br><span class="line"><span class="language-xml">        &#125;);</span></span><br><span class="line"><span class="language-xml">        // 第一次更新</span></span><br><span class="line"><span class="language-xml">        flushSync(() =&gt; &#123;</span></span><br><span class="line"><span class="language-xml">          setCount2(count =&gt; count + 1);</span></span><br><span class="line"><span class="language-xml">        &#125;);</span></span><br><span class="line"><span class="language-xml">        // 第二次更新</span></span><br><span class="line"><span class="language-xml">      &#125;&#125;</span></span><br><span class="line"><span class="language-xml">    &gt;</span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">div</span>&gt;</span>count1： &#123;count1&#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>count2： &#123;count2&#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></span></span><br><span class="line">  );</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 class_">App</span>;</span><br></pre></td></tr></table></figure><p>注意：<code>flushSync</code> 函数内部的多个 <code>setState</code> 仍然为批量更新，这样可以精准控制哪些不需要的批量更新。</p><h2 id="删除了卸载组件后再更新组件状态时的警告"><a href="#删除了卸载组件后再更新组件状态时的警告" class="headerlink" title="删除了卸载组件后再更新组件状态时的警告"></a>删除了卸载组件后再更新组件状态时的警告</h2><p>删除了以下警告：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Warining: Can&#x27;t perfform a React state update on an unmounted component...</span><br></pre></td></tr></table></figure><p>这个错误的初衷，原本旨在针对一些特殊场景，譬如 在 <code>useEffect</code> 里面设置了定时器，或者订阅了某个事件，从而在组件内部产生了副作用，而且忘记 <code>return</code> 一个函数清除副作用，则会发生内存泄漏之类的场景<br>但是在实际开发中，更多的场景是，我们在 <code>useEffect</code> 里面发送了一个异步请求，在异步函数还没有被 <code>resolve</code> 或者被 <code>reject</code> 的时候，我们就卸载了组件。 在这种场景中，警告同样会触发。但是，在这种情况下，组件内部并没有内存泄漏，因为这个异步函数已经被垃圾回收了，此时，警告具有误导性。</p><h2 id="React-组件的返回值可以为-undefined"><a href="#React-组件的返回值可以为-undefined" class="headerlink" title="React 组件的返回值可以为 undefined"></a>React 组件的返回值可以为 undefined</h2><p>在 React17 中，如果需要返回一个空组件，React 只允许返回 null 。如果显式的返回了 undefined，控制台则会在运行时抛出一个错误。在 React18 中，不再检查因返回 undefined 而导致崩溃。既能返回 null，也能返回 undefined。</p><h2 id="严格模式（Strict-Mode）取消了第二次渲染的控制台日志"><a href="#严格模式（Strict-Mode）取消了第二次渲染的控制台日志" class="headerlink" title="严格模式（Strict Mode）取消了第二次渲染的控制台日志"></a>严格模式（Strict Mode）取消了第二次渲染的控制台日志</h2><p>当使用严格模式时，React 会对每个组件进行两次渲染，以便观察一些意想不到的结果。在 React17 中，取消了其中一次渲染的控制台日志，以便让日志更容易阅读。如果安装了 React DevTools，第二次渲染的日志信息将显示为灰色，以柔和的方式显式在控制台。</p><h2 id="Suspense-不再需要-fallback-来捕获"><a href="#Suspense-不再需要-fallback-来捕获" class="headerlink" title="Suspense 不再需要 fallback 来捕获"></a>Suspense 不再需要 fallback 来捕获</h2><p>在 React18 的 Suspense 组件中，官方对空的 fallback 属性的处理方式做了改变：不再跳过缺失值或值为 null 的 fallback 的 Suspense 边界。相反，会捕获边界并且向外层查找，如果查找不到，将会把 fallback 呈现为 null。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// React 17</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">App</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    &lt;Suspense fallback=&#123;&lt;Loading /&gt;&#125;&gt; // &lt;--- 这个边界被使用，显示 Loading 组件</span><br><span class="line">      &lt;Suspense&gt;                      // &lt;--- 这个边界被跳过，没有 fallback 属性</span><br><span class="line">        &lt;Page /&gt;</span><br><span class="line">      &lt;/Suspense&gt;</span><br><span class="line">    &lt;/Suspense&gt;</span><br><span class="line">  );</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">export default App;</span><br><span class="line"></span><br><span class="line">// React 18</span><br><span class="line">const App = () =&gt; &#123;</span><br><span class="line">  return (</span><br><span class="line">    &lt;Suspense fallback=&#123;&lt;Loading /&gt;&#125;&gt; // &lt;--- 不使用</span><br><span class="line">      &lt;Suspense&gt;                      // &lt;--- 这个边界被使用，将 fallback 渲染为 null</span><br><span class="line">        &lt;Page /&gt;</span><br><span class="line">      &lt;/Suspense&gt;</span><br><span class="line">    &lt;/Suspense&gt;</span><br><span class="line">  );</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">export default App;</span><br></pre></td></tr></table></figure><h2 id="新增-userId-API"><a href="#新增-userId-API" class="headerlink" title="新增 userId API"></a>新增 userId API</h2><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> id = <span class="title function_">useId</span>();</span><br></pre></td></tr></table></figure><p>支持同一个组件在客户端和服务端生成相同的唯一的 ID，避免 <code>hydration</code> 的不兼容，这解决了在 React17 及 17 以下版本中已经存在的问题。因为我们的服务器渲染时提供的 HTML 是无序的，useId 的原理就是每个 id 代表该组件在组件树中的层级结构。</p><h2 id="新增-useSyncExternalStore-API"><a href="#新增-useSyncExternalStore-API" class="headerlink" title="新增 useSyncExternalStore API"></a>新增 useSyncExternalStore API</h2><p><code>useSyncExternalStore</code> 能够通过强制同步更新数据让 React 组件在并发模式下安全地有效地读取外接数据源。 在并发模式下，React 一次渲染会分片执行（以 fiber 为单位），中间可能穿插优先级更高的更新。假如在高优先级的更新中改变了公共数据（比如 Redux 中的数据），那之前低优先的渲染必须要重新开始执行，否则就会出现前后状态不一致的情况。<code>useSyncExternalStore</code> 一般是三方状态管理库使用。React 自身的 useState 已经原生的解决了并发特性下 state 更新问题。目前 React-Redux 8.0 已经基于 <code>useSyncExternalStore</code> 实现。</p><h2 id="新增-useInsertionEffect-API"><a href="#新增-useInsertionEffect-API" class="headerlink" title="新增 useInsertionEffect API"></a>新增 useInsertionEffect API</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">useCSS</span> = rule =&gt; &#123;</span><br><span class="line">  <span class="title function_">useInsertionEffect</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (!isInserted.<span class="title function_">has</span>(rule)) &#123;</span><br><span class="line">      isInserted.<span class="title function_">add</span>(rule);</span><br><span class="line">      <span class="variable language_">document</span>.<span class="property">head</span>.<span class="title function_">appendChild</span>(<span class="title function_">getStyleForRule</span>(rule));</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="keyword">return</span> rule;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">App</span>: <span class="title class_">React</span>.<span class="property">FC</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> className = <span class="title function_">useCSS</span>(rule);</span><br><span class="line">  <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">className</span>=<span class="string">&#123;className&#125;</span> /&gt;</span></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 class_">App</span>;</span><br></pre></td></tr></table></figure><p>这个 Hook 只建议 css-in-js 库来使用。 这个 Hooks 执行时机在 DOM 生成之后，<code>useLayoutEffect</code> 之前，它的工作原理大致和 <code>useLayoutEffect</code> 相同，只是此时无法访问 DOM 节点的引用，一般用于提前注入 <code>&lt;style&gt;</code> 脚本。</p><h2 id="新增-startTransition-API"><a href="#新增-startTransition-API" class="headerlink" title="新增 startTransition API"></a>新增 startTransition API</h2><p><code>startTransition</code>，主要为了能在大量的任务下也能保持 UI 响应。这个新的 API 可以通过将特定更新标记为“过渡”来显著改善用户交互，简单来说，就是被 <code>startTransition</code> 回调包裹的 <code>setState</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><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> <span class="title class_">React</span>, &#123; useState, useEffect, useTransition &#125; <span class="keyword">from</span> <span class="string">&#x27;react&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">App</span>: <span class="title class_">React</span>.<span class="property">FC</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> [list, setList] = useState&lt;any[]&gt;([]);</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="title function_">useEffect</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 使用了并发特性，开启并发更新</span></span><br><span class="line">    <span class="title function_">startTransition</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="title function_">setList</span>(<span class="keyword">new</span> <span class="title class_">Array</span>(<span class="number">10000</span>).<span class="title function_">fill</span>(<span class="literal">null</span>));</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;, []);</span><br><span class="line">  <span class="keyword">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">      &#123;list.map((_, i) =&gt; (</span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">&#123;i&#125;</span>&gt;</span>&#123;i&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      ))&#125;</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><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></table></figure><p>由于 <code>setList</code> 在 <code>startTransition</code> 的回调函数中执行（使用了并发特性），所以 <code>setList</code> 会触发 <em>并发更新</em>。</p><h2 id="新增-useDeferredValue-API"><a href="#新增-useDeferredValue-API" class="headerlink" title="新增 useDeferredValue API"></a>新增 useDeferredValue API</h2><p><code>useDeferredValue</code> 返回一个延迟响应的值，可以让一个 state 延迟生效，只有当前没有紧急更新时，该值才会变为最新值。<code>useDeferredValue</code> 和 <code>startTransition</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><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> <span class="title class_">React</span>, &#123; useState, useEffect, useDeferredValue &#125; <span class="keyword">from</span> <span class="string">&#x27;react&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">App</span>: <span class="title class_">React</span>.<span class="property">FC</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> [list, setList] = useState&lt;any[]&gt;([]);</span><br><span class="line">  <span class="title function_">useEffect</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="title function_">setList</span>(<span class="keyword">new</span> <span class="title class_">Array</span>(<span class="number">10000</span>).<span class="title function_">fill</span>(<span class="literal">null</span>));</span><br><span class="line">  &#125;, []);</span><br><span class="line">  <span class="comment">// 使用了并发特性，开启并发更新</span></span><br><span class="line">  <span class="keyword">const</span> deferredList = <span class="title function_">useDeferredValue</span>(list);</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">      &#123;deferredList.map((_, i) =&gt; (</span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">&#123;i&#125;</span>&gt;</span>&#123;i&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      ))&#125;</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><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;2022 年 3 月 29 日 React18 正式发布。&lt;/p&gt;
&lt;p&gt;React18 放弃了对 IE11 的支持。&lt;/p&gt;
&lt;h2 id=&quot;新增-createRoot-API-并支持并发模式渲染&quot;&gt;&lt;a href=&quot;#新增-createRoot-API-并支持并发模式渲</summary>
      
    
    
    
    
    <category term="react" scheme="https://mangon.cn/blog/tags/react/"/>
    
  </entry>
  
  <entry>
    <title>前端异常监控</title>
    <link href="https://mangon.cn/blog/2022/12/26/FE-%E5%89%8D%E7%AB%AF%E5%BC%82%E5%B8%B8%E7%9B%91%E6%8E%A7/"/>
    <id>https://mangon.cn/blog/2022/12/26/FE-%E5%89%8D%E7%AB%AF%E5%BC%82%E5%B8%B8%E7%9B%91%E6%8E%A7/</id>
    <published>2022-12-26T08:27:14.000Z</published>
    <updated>2023-06-05T02:49:34.278Z</updated>
    
    <content type="html"><![CDATA[<p>前端异常监控是指在能够对前端项目运行过程中的错误和异常能够记录和上报从而可以对项目不断分析和优化的流程。从流程上来分，前端异常监控分为数据捕获和数据上报两个部分。</p><span id="more"></span><h2 id="数据捕获"><a href="#数据捕获" class="headerlink" title="数据捕获"></a>数据捕获</h2><p>前端异常数据捕获为全局捕获和单点捕获。全局捕获代码集中，易于管理；单点捕获作为补充，对某些特殊情况进行捕获，但较分散，不利于管理。</p><h3 id="全局捕获"><a href="#全局捕获" class="headerlink" title="全局捕获"></a>全局捕获</h3><ul><li>通过 web API 全局的接口，将捕获代码集中写在一个地方<ul><li><code>window.onerror</code> 可以捕获 JavaScript 运行时错误与语法错误</li><li><code>window.addEventListener(&#39;unhandledrejection&#39;)</code> 可以捕获 未被 catch 的 reject 状态的 Promise(Promise 异常)</li><li><code>document.addEventListener(&#39;click&#39;)</code> 全局的点击事件</li></ul></li><li>框架级别的全局监听<ul><li>aixos 中使用 interceptor 进行拦截</li><li>vue 中的 errorCaptured、errorHandler</li><li>react 中的 ErrorBoundary</li></ul></li><li>通过对全局函数进行封装包裹，实现在调用该函数时自动捕获异常<ul><li>例如对 xhr/Fetch 进行封装，在发送 Ajax 请求时进行记录</li></ul></li><li>对实例方法重写（Patch），在原有功能基础上包裹一层<ul><li>例如对 setTimeout、setInterval、requrestAnimationFrame、console 进行重写，在使用方法不变的情况下也可以异常捕获</li></ul></li></ul><h3 id="单点捕获"><a href="#单点捕获" class="headerlink" title="单点捕获"></a>单点捕获</h3><ul><li>在业务代码中对单个代码块进行包裹，或在逻辑流程中打点，实现有针对性的异常捕获</li><li><code>try catch</code> 语句块记录 JS Error 异常</li><li>专门写一个函数来收集异常信息，在异常发生时，调用该函数</li><li>专门写一个函数来包裹其他函数，得到一个新函数，该新函数运行结果和原函数一模一样，只是在发生异常时可以捕获异常</li></ul><h2 id="数据上报"><a href="#数据上报" class="headerlink" title="数据上报"></a>数据上报</h2><p>异常数据上报，即通过一定方式将收集到的参数上报到服务器的过程。</p><ul><li>异步请求，通过 xhr/fetch 上报</li><li><code>new Image()</code> 上报（1x1的透明gif）</li></ul><h2 id="sentry"><a href="#sentry" class="headerlink" title="sentry"></a>sentry</h2><p><a href="https://github.com/getsentry/sentry">Sentry</a> 是一款开源的错误捕获和性能监控系统。类似的商业化（非开源）前端错误与性能监控平台还有 Fundebug、FrontJS、rollbar.js 等。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;前端异常监控是指在能够对前端项目运行过程中的错误和异常能够记录和上报从而可以对项目不断分析和优化的流程。从流程上来分，前端异常监控分为数据捕获和数据上报两个部分。&lt;/p&gt;</summary>
    
    
    
    
    <category term="front-end" scheme="https://mangon.cn/blog/tags/front-end/"/>
    
  </entry>
  
  <entry>
    <title>Vue面试手册</title>
    <link href="https://mangon.cn/blog/2022/11/29/Vue-Vue%E9%9D%A2%E8%AF%95%E6%89%8B%E5%86%8C/"/>
    <id>https://mangon.cn/blog/2022/11/29/Vue-Vue%E9%9D%A2%E8%AF%95%E6%89%8B%E5%86%8C/</id>
    <published>2022-11-29T08:29:52.000Z</published>
    <updated>2023-06-05T02:49:34.369Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Vue-是什么"><a href="#Vue-是什么" class="headerlink" title="Vue 是什么"></a>Vue 是什么</h2><p>Vue是一个构建用户界面的渐进式 MVVM 框架。它的核心在于数据驱动和组件化的思想。</p><p>Vue的优点主要有：</p><ul><li>轻量级框架：只关注视图层，是一个构建数据的视图集合，大小只有几十 kb ；</li><li>简单易学：中文文档丰富，易于理解和学习；</li><li>双向数据绑定：保留了 Angular 的特点，在数据操作方面更为方便；</li><li>组件化：保留了 React 的优点，通过单页面组件实现了 html 的封装和重用，在构建单页面应用方面有着独特的优势；</li><li>视图，数据，结构分离：使数据的更改更为简单，不需要进行逻辑代码的修改，只需要操作数据就能完成相关操作；</li><li>虚拟DOM：dom 操作是非常耗费性能的，不再使用原生的 dom 操作节点，极大解放 dom 操作；</li><li>运行速度更快：相比较于 react 而言，同样是操作虚拟 dom，就性能而言， vue 存在很大的优势。</li></ul><h2 id="为什么说Vue是一个渐进式框架"><a href="#为什么说Vue是一个渐进式框架" class="headerlink" title="为什么说Vue是一个渐进式框架"></a>为什么说Vue是一个渐进式框架</h2><p>Vue 实现了构建 web 应用最核心的 mvvm 绑定部分，用户可以选择使用其他库（例如vuex、axios、vue-router）来搭配使用构建最适合自己的应用。</p><h2 id="v-model-双向绑定的原理是什么"><a href="#v-model-双向绑定的原理是什么" class="headerlink" title="v-model 双向绑定的原理是什么"></a>v-model 双向绑定的原理是什么</h2><p>v-model 实际上是语法糖，以 input 元素为例：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">v-model</span>=<span class="string">&quot;inputV&quot;</span> /&gt;</span></span><br><span class="line">// 等同于</span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">:value</span>=<span class="string">&quot;inputV&quot;</span> @<span class="attr">input</span>=<span class="string">&quot;inputV = $event.target.value&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure><ul><li>input 组件的 value 属性绑定于 inputV 变量上，也就是当 inputV 变化时，input 组件的 value 也会跟着变化；</li><li>监听 input 事件，该事件在 input 的值改变时触发，事件触发时给 inputV 重新赋值，所赋的值是 <code>$event.target.value</code>，也就是当前触发 input 事件时的 value 值，也就是该 input 组件的值。</li></ul><h2 id="Vue-2-0-响应式数据的原理"><a href="#Vue-2-0-响应式数据的原理" class="headerlink" title="Vue 2.0 响应式数据的原理"></a>Vue 2.0 响应式数据的原理</h2><p>Vue.js 是采用 <em>数据劫持</em> 结合 <em>发布者-订阅者模式</em> 的方式，通过 <code>Object.defineProperty()</code> 来劫持各个属性的 setter，getter，在数据变动时发布消息给订阅者，触发相应的监听回调。主要分为以下几个步骤：</p><ul><li>对需要 observe 的数据对象进行递归遍历，包括子属性对象的属性，都加上 setter 和 getter，这样的话，给这个对象的某个值赋值，就会触发 setter，那么就能监听到了数据变化；</li><li>Compile 负责解析模板指令，将模板中的变量替换成数据，然后初始化渲染页面视图，并将每个指令对应的节点绑定更新函数，添加监听数据的订阅者，一旦数据有变动，收到通知，更新视图；</li><li>Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁，主要做的事情是: <ul><li>在自身实例化时往属性订阅器(dep)里面添加自己 </li><li>自身必须有一个 <code>update()</code> 方法</li><li>待属性变动 <code>dep.notice()</code> 通知时，能调用自身的 <code>update()</code> 方法，并触发 Compile 中绑定的回调</li></ul></li><li>MVVM 作为数据绑定的入口，整合 Observer、Compile 和 Watcher 三者，通过 Observer 来监听自己的 model 数据变化，通过 Compile 来解析编译模板指令，最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁，达到 数据变化 -&gt; 视图更新；视图交互变化（input） -&gt; 数据（model）变更的双向绑定效果。</li></ul><p><img src="/blog/static/imgs/vue/vue2.png" alt="vue2_inner"></p><h2 id="Vue3-中为什么使用-Proxy-来替代-Object-defineProperty-实现数据劫持？"><a href="#Vue3-中为什么使用-Proxy-来替代-Object-defineProperty-实现数据劫持？" class="headerlink" title="Vue3 中为什么使用 Proxy 来替代 Object.defineProperty() 实现数据劫持？"></a>Vue3 中为什么使用 Proxy 来替代 <code>Object.defineProperty()</code> 实现数据劫持？</h2><p><code>Object.defineProperty</code> 无法监听 下标方式修改数组数据 或者 给对象新增属性 的操作，Proxy 可以监听。</p><h2 id="Vue-data-中某一个属性的值发生改变后，视图会立即同步执行重新渲染吗"><a href="#Vue-data-中某一个属性的值发生改变后，视图会立即同步执行重新渲染吗" class="headerlink" title="Vue data 中某一个属性的值发生改变后，视图会立即同步执行重新渲染吗"></a>Vue data 中某一个属性的值发生改变后，视图会立即同步执行重新渲染吗</h2><p>不会立即同步执行重新渲染。Vue 实现响应式并不是数据发生变化之后 DOM 立即变化，而是按一定的策略进行 DOM 的更新。Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化， Vue 将开启一个队列，并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发，只会被推入到队列中。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后，在下一个的事件循环 tick 中，Vue 刷新队列并执行实际（已去重的）工作。</p><h2 id="Vue2-监控不了数组类型-data-的变化，有什么解决办法"><a href="#Vue2-监控不了数组类型-data-的变化，有什么解决办法" class="headerlink" title="Vue2 监控不了数组类型 data 的变化，有什么解决办法"></a>Vue2 监控不了数组类型 data 的变化，有什么解决办法</h2><ul><li>使用 <code>this.$set(obj，key，value)</code> 更新数组</li><li>调用以下几个数组的方法 <code>splice()、 push()、pop()、shift()、unshift()、sort()、reverse()</code></li></ul><h2 id="Vue2-中何时使用-Vue-nextTick"><a href="#Vue2-中何时使用-Vue-nextTick" class="headerlink" title="Vue2 中何时使用 Vue.$nextTick()?"></a>Vue2 中何时使用 <code>Vue.$nextTick()</code>?</h2><ul><li>在数据变化后执行的某个操作，而这个操作需要使用随数据变化而变化的 DOM 结构的时候，这个操作就需要方法在 <code>nextTick()</code> 的回调函数中。</li><li>在 vue 生命周期中，如果在 <code>created()</code> 钩子进行DOM操作，也一定要放在 <code>nextTick()</code> 的回调函数中。因为在 <code>created()</code> 钩子函数中，页面的DOM还未渲染，这时候没办法操作DOM。</li></ul><h2 id="什么是-Vue-mixin？"><a href="#什么是-Vue-mixin？" class="headerlink" title="什么是 Vue.mixin？"></a>什么是 <code>Vue.mixin</code>？</h2><p>混入（mixin）是指当多个组件共享同样的功能（生命周期hook、方法等）时，将同样的功能剥离开来并在多个组件中引入该部分实现从而代码重用的目的。</p><h2 id="vue-router有多少种模式？"><a href="#vue-router有多少种模式？" class="headerlink" title="vue-router有多少种模式？"></a>vue-router有多少种模式？</h2><ul><li><p>hash模式：兼容所有浏览器，包括不支持 HTML5 History Api 的浏览器。例如 <code>https://example.com/#index</code> hash 的值为 <code>#index</code>， hash 的改变会触发 hashchange 事件，我们可以通过监听 hashchange 事件来完成操作实现前端路由。</p></li><li><p>history模式：能支持 HTML5 History Api 的浏览器，依赖 HTML5 History API 来实现前端路由。例如 <code>https://example.com/index</code> 。为防止服务器请求不到资源时返回 404，需要在服务器端设置，匹配不到资源时返回 index.html ，同时由前端来控制 404 页面的显示。例如，nginx 需配置</p></li></ul><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></pre></td><td class="code"><pre><span class="line">location / &#123;</span><br><span class="line">    try_files  $uri $uri/ @router index index.html;</span><br><span class="line">&#125;</span><br><span class="line">location @router &#123;</span><br><span class="line">    rewrite ^.*$ /index.html last;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>abstract模式：支持所有 JavaScript 运行环境，如 Node.js 服务器端。如果发现没有浏览器的 API，路由会自动强制进入这个模式。</li></ul><h2 id="hash和history模式实现vue-router跳转api的区别"><a href="#hash和history模式实现vue-router跳转api的区别" class="headerlink" title="hash和history模式实现vue-router跳转api的区别"></a>hash和history模式实现vue-router跳转api的区别</h2><table><thead><tr><th>api</th><th>hash</th><th>history</th></tr></thead><tbody><tr><td>push</td><td><code>window.location.assign</code></td><td><code>window.history.pushState</code></td></tr><tr><td>replace</td><td><code>window.location.replace</code></td><td>window.history.replaceState`</td></tr><tr><td>go</td><td><code>window.history.go</code></td><td><code>window.history.go</code></td></tr><tr><td>back</td><td><code>window.history.go(-1)</code></td><td><code>window.history.go(-1)</code></td></tr><tr><td>forward</td><td><code>window.history.go(1)</code></td><td><code>window.history.go(1)</code></td></tr></tbody></table><h2 id="vue-指令有哪些？"><a href="#vue-指令有哪些？" class="headerlink" title="vue 指令有哪些？"></a>vue 指令有哪些？</h2><p>v-show、v-if、v-else-if、v-else、v-for、v-on、v-bind、v-model、v-once、v-slot、v-html、v-text</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Vue-是什么&quot;&gt;&lt;a href=&quot;#Vue-是什么&quot; class=&quot;headerlink&quot; title=&quot;Vue 是什么&quot;&gt;&lt;/a&gt;Vue 是什么&lt;/h2&gt;&lt;p&gt;Vue是一个构建用户界面的渐进式 MVVM 框架。它的核心在于数据驱动和组件化的思想。&lt;/p&gt;
&lt;p</summary>
      
    
    
    
    
    <category term="vue" scheme="https://mangon.cn/blog/tags/vue/"/>
    
  </entry>
  
  <entry>
    <title>CSS编写规则</title>
    <link href="https://mangon.cn/blog/2022/11/29/CSS-%E7%BC%96%E5%86%99%E8%A7%84%E5%88%99/"/>
    <id>https://mangon.cn/blog/2022/11/29/CSS-%E7%BC%96%E5%86%99%E8%A7%84%E5%88%99/</id>
    <published>2022-11-29T06:58:38.000Z</published>
    <updated>2023-06-05T02:49:34.250Z</updated>
    
    <content type="html"><![CDATA[<p>OOCSS，SMACSS，BEM，ITCSS，Utility-First CSS，ACSS 都是 CSS 编写规则，是结构化编写和组织 CSS 的指南，在一个项目中采用一致的 CSS 编写规则，更利于他人理解你的代码和团队协作。</p><h2 id="面向对象的-CSS"><a href="#面向对象的-CSS" class="headerlink" title="面向对象的 CSS"></a>面向对象的 CSS</h2><p>面向对象的 CSS（Object Oriented CSS，OOCSS）是指把样式重复的代码片段，定义为 CSS 对象</p><ul><li>盒模型与皮肤无关：盒模型属性与颜色、背景等皮肤主题属性分选择器定义</li><li>样式与位置无关：避免使用标签、关系选择器，应用时，我们通常提取多个元素的公用属性，作为基本类 在其基础上，通过其它类扩展每个元素的个性属性 这是避免 CSS 代码冗余的常用方法</li></ul><figure class="highlight html"><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="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;box bg-red&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;box bg-green&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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="selector-class">.box</span> &#123;</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">20px</span>;</span><br><span class="line">    <span class="attribute">height</span>: <span class="number">20px</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.bg-red</span> &#123;</span><br><span class="line">    <span class="attribute">background-color</span>: red;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.bg-green</span> &#123;</span><br><span class="line">    <span class="attribute">background-color</span>: green;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="可扩展模块化-CSS-架构"><a href="#可扩展模块化-CSS-架构" class="headerlink" title="可扩展模块化 CSS 架构"></a>可扩展模块化 CSS 架构</h2><p>可扩展模块化 CSS 架构（Scalable and Modular Architecture for CSS，SMACSS）定义了 CSS 分类和命名规则，并对 CSS 书写提出优化建议</p><ul><li>Base：默认，基础，通用规则，包括重置浏览器样式的规则</li><li>Layout：布局规则，以 <code>l-</code> 或 <code>layout-</code>开头</li><li>Module：可复用模块规则</li><li>State：布局或模块的特殊状态规则，如隐藏，激活等，以 <code>is</code> 开头</li><li>Theme：皮肤或主题规则，可能包含另一种配色方案</li></ul><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* base */</span></span><br><span class="line"><span class="selector-tag">button</span> &#123;</span><br><span class="line">    <span class="attribute">color</span>: <span class="number">#ababab</span>;</span><br><span class="line">    <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#f2f2f2</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/* layout */</span></span><br><span class="line"><span class="selector-class">.l-header</span> &#123;&#125;</span><br><span class="line"><span class="selector-class">.l-primarynav</span> &#123;&#125;</span><br><span class="line"><span class="selector-class">.l-main-content</span> &#123;&#125;</span><br><span class="line"><span class="comment">/* module */</span></span><br><span class="line"><span class="selector-class">.article-title</span> &#123;&#125;</span><br><span class="line"><span class="selector-class">.article-content</span> &#123;&#125;</span><br><span class="line"><span class="comment">/* state */</span></span><br><span class="line"><span class="selector-class">.is-hidden</span> &#123;&#125;</span><br><span class="line"><span class="selector-class">.is-shown</span> &#123;&#125;</span><br><span class="line"><span class="comment">/* theme */</span></span><br><span class="line"><span class="selector-class">.button-large</span> &#123;</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">60px</span>;</span><br><span class="line">    <span class="attribute">height</span>: <span class="number">60px</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="块元素修饰符"><a href="#块元素修饰符" class="headerlink" title="块元素修饰符"></a>块元素修饰符</h2><p>块元素修饰符（Block Element Modifier，BEM）定义了一种 CSS 的命名规则，用于解决命名冲突</p><ul><li>Block：块，忽略结构和优先级，具有独立意义的实体</li><li>Element：元素，块内部没有独立意义的实体</li><li>Modifier：修饰符，标识块或元素的外观、行为、状态被修改，含有修饰符的类名不可独立出现，通常跟在不含修饰符的类名后</li></ul><p>BEM 在书写时需要遵循三个原则：</p><ul><li>使用 <code>__</code> 两个下划线将块名称与元素名称分开</li><li>使用 <code>--</code> 两个破折号分隔元素名称及其修饰符</li><li>一切样式都是一个类，不能嵌套</li></ul><figure class="highlight css"><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="selector-class">.block__elementOne--modifier</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="倒三角形CSS"><a href="#倒三角形CSS" class="headerlink" title="倒三角形CSS"></a>倒三角形CSS</h2><p>倒三角形CSS（Inverted Triangle CSS，ITCSS）主要用 SASS 实现 提供了一种 CSS 由通用到具体的分层（分类）方法，层次可以按需增删</p><ul><li>Settings：全局变量、方法，例如字体、颜色定义</li><li>Tools：结合预处理器使用，全局使用的函数（function）、混入器（mixin）</li><li>Generic：浏览器默认样式重置，例如 normalize.css、reset.css</li><li>Elements（Base）：仅可使用类型（标签）选择器，例如 <code>h1 &#123;&#125;</code></li><li>Objects：遵循 OOCSS 的对象的盒模型，无颜色、背景等</li><li>Components：可复用的 UI 组件</li><li>Trumps(Utilities)：对组件的微调和其他样式定义，可使用 <code>!important</code></li></ul><h2 id="实用类优先CSS"><a href="#实用类优先CSS" class="headerlink" title="实用类优先CSS"></a>实用类优先CSS</h2><p>实用类优先CSS（Utility-First CSS） 提供了一种外观组件的构建方法，以 tailwindcss 为代表</p><ul><li>按照一定规则，基于 CSS 实用类构建复杂外观组件</li><li>不用起类名</li><li>样式文件体积不会随项目无限增长</li><li>增删类名，比直接修改属性更安全，维护更容易</li></ul><h2 id="原子CSS"><a href="#原子CSS" class="headerlink" title="原子CSS"></a>原子CSS</h2><p>原子CSS（Atomic CSS），可以看成 Utility-First CSS 的极致抽象 提供了一种 CSS 类的定义方法，提升大型项目 CSS 复用度</p><ul><li>每个类选择器中只包含一条属性定义，一次编写，到处运行</li><li>属性名类似函数，属性值类似函数参数，像写内联样式一样写类名，适合 CSS-in-JS</li><li>提供工具，可按需编译</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;OOCSS，SMACSS，BEM，ITCSS，Utility-First CSS，ACSS 都是 CSS 编写规则，是结构化编写和组织 CSS 的指南，在一个项目中采用一致的 CSS 编写规则，更利于他人理解你的代码和团队协作。&lt;/p&gt;
&lt;h2 id=&quot;面向对象的-CSS&quot;</summary>
      
    
    
    
    
    <category term="CSS" scheme="https://mangon.cn/blog/tags/CSS/"/>
    
  </entry>
  
  <entry>
    <title>对比Less/Sass/Stylus/PostCSS</title>
    <link href="https://mangon.cn/blog/2022/11/29/CSS-%E5%AF%B9%E6%AF%94Less-Sass-Stylus-PostCSS/"/>
    <id>https://mangon.cn/blog/2022/11/29/CSS-%E5%AF%B9%E6%AF%94Less-Sass-Stylus-PostCSS/</id>
    <published>2022-11-29T06:50:18.000Z</published>
    <updated>2023-06-05T02:49:34.244Z</updated>
    
    <content type="html"><![CDATA[<p>Less、Sass 和 Stylus 是 CSS 预处理器，PostCSS 是转换 CSS 工具的平台</p><span id="more"></span><h2 id="Less"><a href="#Less" class="headerlink" title="Less"></a>Less</h2><ul><li>变量：<code>$</code> 标识符变量，使用 <code>&#123;&#125;</code> 插值</li><li>嵌套：支持 <code>&#123; &#125;</code> 大括号嵌套</li><li>混入器：支持 选择器 混入 或 使用 <code>.selector(@param)</code> 创建纯混入器</li><li>扩展 / 继承 / 运算符 / @import：支持</li><li>流程：支持 if 条件判断，支持 when 递归模拟循环</li><li>映射：支持 @ 声明和使用 Map</li><li>特有：提供 Less.js，直接在浏览器使用 Less</li></ul><h2 id="Sass"><a href="#Sass" class="headerlink" title="Sass"></a>Sass</h2><ul><li>变量：支持 <code>$</code> 标识符变量，使用 <code>#&#123;&#125;</code> 插值</li><li>嵌套：支持 <code>&#123; &#125;</code>大括号嵌套，支持缩进嵌套</li><li>混入器：<code>@mixin</code> 创建 <code>@include</code> 使用</li><li>扩展 / 继承 / 运算符 / @import：支持</li><li>流程：支持 if else 条件判断，支持 for while each 循环</li><li>映射：支持 <code>$()</code> 声明 Map，提供 map-get(map, key) map-keys(map) map-values(map) 等一系列方法操作 Map，支持遍历 Map</li><li>特有：支持 compass ，内含 自动私有前缀 等一系列有用 Sass 模块，支持压缩输出</li></ul><h2 id="Stylus"><a href="#Stylus" class="headerlink" title="Stylus"></a>Stylus</h2><ul><li>变量：支持 <code>$</code> 标识符变量 和 赋值表达式变量，使用 <code>&#123;&#125;</code> 插值</li><li>嵌套：支持 <code>&#123; &#125;</code> 大括号嵌套 和 缩进嵌套</li><li>混入器：像函数一样创建和使用</li><li>扩展 / 继承 / 运算符 / @import：支持</li><li>流程：支持 if else unless 三元 条件判断，支持 for 循环</li><li>映射：像 JS 一样创建和使用对象</li><li>特有：支持中间件，自动分配函数变量，提供 JS API。支持压缩输出</li></ul><h2 id="PostCSS"><a href="#PostCSS" class="headerlink" title="PostCSS"></a>PostCSS</h2><ul><li>接受 CSS 文件，把 CSS 规则转换为抽象语法树</li><li>提供 API 供插件调用，对 CSS 处理</li><li>插件：支持 Autoprefixer 自动添加私有前缀、css-modules CSS 模块 stylelint CSS 语法检查等插件，PostCSSS 是工具的工具</li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;Less、Sass 和 Stylus 是 CSS 预处理器，PostCSS 是转换 CSS 工具的平台&lt;/p&gt;</summary>
    
    
    
    
    <category term="less" scheme="https://mangon.cn/blog/tags/less/"/>
    
    <category term="sass" scheme="https://mangon.cn/blog/tags/sass/"/>
    
    <category term="stylus" scheme="https://mangon.cn/blog/tags/stylus/"/>
    
    <category term="postcss" scheme="https://mangon.cn/blog/tags/postcss/"/>
    
  </entry>
  
</feed>
