<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Pimi&#39;s Blog</title>
  
  <subtitle>A lazy youth, a lousy age.</subtitle>
  <link href="/blog/atom.xml" rel="self"/>
  
  <link href="http://pimichen.com/blog/"/>
  <updated>2024-07-31T16:00:00.000Z</updated>
  <id>http://pimichen.com/blog/</id>
  
  <author>
    <name>Pimi Chen</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>最后记录</title>
    <link href="http://pimichen.com/blog/other/%E6%9C%80%E5%90%8E%E8%AE%B0%E5%BD%95.html"/>
    <id>http://pimichen.com/blog/other/最后记录.html</id>
    <published>2024-07-31T16:00:00.000Z</published>
    <updated>2024-07-31T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>从 2024-08-01 开始，暂停 Hexo 的更新，转到<a href="https://juejin.cn/user/2102683723106855" target="_blank" rel="noopener">掘金平台</a>，部分历史文章也会同步过去。</p><p>感谢 Hexo 的陪伴。</p>]]></content>
    
    <summary type="html">
    
      后续不再更新，转到掘金平台记录
    
    </summary>
    
    
      <category term="Other" scheme="http://pimichen.com/blog/tags/other/"/>
    
  </entry>
  
  <entry>
    <title>移动端如何识别键盘弹出</title>
    <link href="http://pimichen.com/blog/javascript/%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%A6%82%E4%BD%95%E8%AF%86%E5%88%AB%E9%94%AE%E7%9B%98%E5%BC%B9%E5%87%BA.html"/>
    <id>http://pimichen.com/blog/javascript/移动端如何识别键盘弹出.html</id>
    <published>2022-04-14T16:00:00.000Z</published>
    <updated>2022-04-14T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>在开发移动端的时候，我们可能需要识别键盘是否弹窗，然后处理一些特殊逻辑，那么如何识别该状态呢？</p><p>我们可能很容易想到监听输入框的 <code>focus</code> 和 <code>blur</code> 事件，然后部分安卓键盘右上角有收起操作，收起的时候并不会执行 <code>blur</code> 事件，输入框光标仍然在，导致我们无法精准的识别。</p><p><img src="../images/javascript/js_keyboard_android1.jpg" title="Android点击收起键盘时" width="30%"></p><p>既然通过 <code>focus</code>、<code>blur</code> 无法识别，那么我们很容易想到监听 <code>resize</code> 的触发，分析 <code>iOS</code> 和 <code>Android</code> 激活时的样式<br>当页面没有设置100%高度时，可以看到 <code>iOS</code>、<code>Android</code> 激活键盘时，键盘会盖在页面的上方。</p><p><br></p><p>当页面设置100%高度，使用flex布局，header顶部固定，footer底部固定，中间区域滚动时，可以看到 <code>iOS</code> 键盘仍然时盖在上面，而 <code>Android</code> 激活键盘则会将页面往上顶。</p><p><br></p><p><code>Android</code> 激活键盘会会触发 <code>resize</code>，而 <code>iOS</code> 当输入框不在顶部时会触发 <code>scroll</code> 事件，在顶部时不会触发 <code>scroll</code> 事件，我们使用 <code>focusin</code> 和 <code>focusout</code> 来捕获。</p><p>使用Vue的方式如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;keyboard-view&quot;&gt;</span><br><span class="line">    &lt;header&gt;header&lt;/header&gt;</span><br><span class="line"></span><br><span class="line">    &lt;main&gt;</span><br><span class="line">      &lt;div class=&quot;empty-box&quot;&gt;&lt;/div&gt;</span><br><span class="line">      &lt;br&gt;</span><br><span class="line">      &lt;div&gt;</span><br><span class="line">        &lt;input type=&quot;text&quot; placeholder=&quot;请输入&quot;&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">      &lt;br&gt;</span><br><span class="line">      &lt;div class=&quot;empty-box&quot;&gt;&lt;/div&gt;</span><br><span class="line">    &lt;/main&gt;</span><br><span class="line"></span><br><span class="line">    &lt;footer&gt;footer&lt;/footer&gt;</span><br><span class="line"></span><br><span class="line">    &lt;div class=&quot;fixed-mask&quot;&gt;</span><br><span class="line">      键盘state: &#123;&#123; state &#125;&#125;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &apos;KeyboardVisible&apos;,</span><br><span class="line">  data () &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      state: &apos;失焦&apos;,</span><br><span class="line">      docHeight: document.documentElement.clientHeight</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  mounted () &#123;</span><br><span class="line">    this.keyboardShowListener()</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    keyboardShowListener () &#123;</span><br><span class="line">      let self = this</span><br><span class="line">      // 全局监听激活</span><br><span class="line">      function focusInFn () &#123;</span><br><span class="line">        self.state = &apos;激活&apos;</span><br><span class="line">        self.keyboardShowFn()</span><br><span class="line">      &#125;</span><br><span class="line">      // 全局监听失焦</span><br><span class="line">      function focusOutFn () &#123;</span><br><span class="line">        self.state = &apos;失焦&apos;</span><br><span class="line">        self.keyboardHideFn()</span><br><span class="line">      &#125;</span><br><span class="line">      // 监听iOS（当输入框在页面非顶部区域时都会触发）</span><br><span class="line">      function scrollFn () &#123;</span><br><span class="line">        let scrollTop = document.documentElement.scrollTop || document.body.scrollTop</span><br><span class="line">        if (scrollTop == 0) &#123;</span><br><span class="line">          self.state = &apos;失焦&apos;</span><br><span class="line">          self.keyboardHideFn()</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">          self.state = &apos;激活&apos;</span><br><span class="line">          self.keyboardShowFn()</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      // 监听安卓</span><br><span class="line">      function resizeFn () &#123;</span><br><span class="line">        let docHeight = document.documentElement.clientHeight</span><br><span class="line">        if (docHeight == self.docHeight) &#123;</span><br><span class="line">          self.state = &apos;失焦&apos;</span><br><span class="line">          self.keyboardHideFn()</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">          self.state = &apos;激活&apos;</span><br><span class="line">          self.keyboardShowFn()</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      document.body.addEventListener(&apos;focusin&apos;, focusInFn, false)</span><br><span class="line">      document.body.addEventListener(&apos;focusout&apos;, focusOutFn, false)</span><br><span class="line">      document.addEventListener(&apos;scroll&apos;, scrollFn, false)</span><br><span class="line">      window.addEventListener(&apos;resize&apos;, resizeFn, false)</span><br><span class="line">      this.$once(&apos;hook:beforeDestroy&apos;, function () &#123;</span><br><span class="line">        document.body.removeEventListener(&apos;focusin&apos;, focusInFn, false)</span><br><span class="line">        document.body.removeEventListener(&apos;focusout&apos;, focusOutFn, false)</span><br><span class="line">        document.removeEventListener(&apos;scroll&apos;, scrollFn, false)</span><br><span class="line">        window.removeEventListener(&apos;resize&apos;, resizeFn, false)</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;,</span><br><span class="line">    keyboardShowFn () &#123;</span><br><span class="line">      // alert(&apos;keyboardShowFn&apos;)</span><br><span class="line">    &#125;,</span><br><span class="line">    keyboardHideFn () &#123;</span><br><span class="line">      // alert(&apos;keyboardHideFn&apos;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;scss&quot; scoped&gt;</span><br><span class="line">.keyboard-view&#123;</span><br><span class="line">  height: 100%;</span><br><span class="line">  display: flex;</span><br><span class="line">  flex-direction: column;</span><br><span class="line">  header&#123;</span><br><span class="line">    height: 40px;</span><br><span class="line">    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);</span><br><span class="line">    display: flex;</span><br><span class="line">    justify-content: center;</span><br><span class="line">    align-items: center;</span><br><span class="line">  &#125;</span><br><span class="line">  footer&#123;</span><br><span class="line">    height: 40px;</span><br><span class="line">    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);</span><br><span class="line">    display: flex;</span><br><span class="line">    justify-content: center;</span><br><span class="line">    align-items: center;</span><br><span class="line">  &#125;</span><br><span class="line">  main&#123;</span><br><span class="line">    padding: 16px;</span><br><span class="line">    flex: 1;</span><br><span class="line">    overflow-y: auto;</span><br><span class="line">    -webkit-overflow-scrolling: touch;</span><br><span class="line">  &#125;</span><br><span class="line">  input&#123;</span><br><span class="line">    width: 100%;</span><br><span class="line">    height: 40px;</span><br><span class="line">    border: 1px solid #ccc;</span><br><span class="line">    padding: 10px;</span><br><span class="line">    box-sizing: border-box;</span><br><span class="line">  &#125;</span><br><span class="line">  .empty-box&#123;</span><br><span class="line">    height: 500px;</span><br><span class="line">    background-color:#ccc;</span><br><span class="line">  &#125;</span><br><span class="line">  .fixed-mask&#123;</span><br><span class="line">    width: 100px;</span><br><span class="line">    background-color: rgba(0, 0, 0, 0.5);</span><br><span class="line">    position: fixed;</span><br><span class="line">    right: 0;</span><br><span class="line">    top: 300px;</span><br><span class="line">    color: #fff;</span><br><span class="line">    padding: 5px;</span><br><span class="line">    font-size: 12px;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      移动端如何识别键盘弹出状态，处理特殊逻辑
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
      <category term="Vue" scheme="http://pimichen.com/blog/tags/vue/"/>
    
  </entry>
  
  <entry>
    <title>promise多个then、catch、finally情况</title>
    <link href="http://pimichen.com/blog/es6/promise%E5%A4%9A%E4%B8%AAthen%E3%80%81catch%E3%80%81finally%E6%83%85%E5%86%B5.html"/>
    <id>http://pimichen.com/blog/es6/promise多个then、catch、finally情况.html</id>
    <published>2022-03-01T16:00:00.000Z</published>
    <updated>2023-03-21T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><p>先抛出结论，如下：</p><ol><li>一个promise中，resolve、reject只会执行最先触发的那个，执行完就停止了</li><li>根据 resolve|reject 输出 then|catch、finally<br><br></li><li>多个resolve或多个reject只会执行第一个</li><li>Promise立即执行函数里面的其他语句不会受到resolve、reject影响<br><br></li><li>第一次then|catch、finally执行的是promise内部的结果</li><li>第一次then|catch的参数来自promise内部的resolve、reject，finally始终无参数</li><li>第二次及以后的then一定会执行，参数来自上一个then的返回值，无返回值时参数为undefined</li><li>第二次及以后的finally一定会执行，无参数，为undefined<br><br></li><li>第二次及以后的then中如果return Error，会被下一个then作为参数输出，finally始终无参数。只会影响下一个，不会影响下下个。</li><li>第二次如果是throw Error，则会被当前紧挨着的catch语句所捕获</li><li>即：return Error只是作为一个常规的返回值（值为Error），而throw则是直接抛出异常<br><br></li><li>在then中连续写两个回调，第一个参数为then，第二个参数为catch，在then后面再写一个catch。<br>如果promise是resolve，在then的第一个参数中throw Error，会被下一个catch所捕获<br>如果promise是reject，在then的第二个参数中throw Error，会被下一个catch所捕获</li><li>即：then…catch可以将两个回调都写在then里面，直接写两个参数，then后面的catch会被当前其他语句的catch，只有前面的then内部抛出异常才会执行。</li></ol><h2 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h2><h3 id="case1-resovle"><a href="#case1-resovle" class="headerlink" title="case1_resovle"></a>case1_resovle</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise1</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    resolve(<span class="string">'成功！'</span>)</span><br><span class="line">    reject(<span class="string">'失败！'</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First catch:'</span>, err)</span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First finally'</span>, res)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">testPromise1()</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * testPromise1 执行结果：</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * First then: 成功！</span></span><br><span class="line"><span class="comment"> * First finally: undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><h3 id="case2-reject"><a href="#case2-reject" class="headerlink" title="case2_reject"></a>case2_reject</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise2</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    reject(<span class="string">'失败！'</span>)</span><br><span class="line">    resolve(<span class="string">'成功！'</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First catch:'</span>, err)</span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First finally:'</span>, res)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">testPromise2()</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * testPromise2 执行结果：</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * First catch: 失败！</span></span><br><span class="line"><span class="comment"> * First finally: undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p>case1、case2结论：</p><ol><li>一个promise中，resolve、reject只会执行最先触发的那个，执行完就停止了</li><li>根据 resolve|reject 先输出 promise 自己的then|catch、finall</li></ol><h3 id="case3-多resolve、reject"><a href="#case3-多resolve、reject" class="headerlink" title="case3_多resolve、reject"></a>case3_多resolve、reject</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise3</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'testPromise1_1'</span>)</span><br><span class="line">    resolve(<span class="string">'成功1！'</span>)</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'testPromise1_2'</span>)</span><br><span class="line">    reject(<span class="string">'失败1！'</span>)</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'testPromise1_3'</span>)</span><br><span class="line">    resolve(<span class="string">'成功2！'</span>)</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'testPromise1_4'</span>)</span><br><span class="line">    reject(<span class="string">'失败2！'</span>)</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'testPromise1_5'</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First catch:'</span>, err)</span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First finally:'</span>, res)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">testPromise3()</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * testPromise3 执行结果：</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * testPromise1_1</span></span><br><span class="line"><span class="comment"> * testPromise1_2</span></span><br><span class="line"><span class="comment"> * testPromise1_3</span></span><br><span class="line"><span class="comment"> * testPromise1_4</span></span><br><span class="line"><span class="comment"> * testPromise1_5</span></span><br><span class="line"><span class="comment"> * First then: 成功1！</span></span><br><span class="line"><span class="comment"> * First finally: undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p>case3结论：</p><ol><li>多个resolve或多个reject只会执行第一个</li><li>Promise立即执行函数里面的非resolve、reject语句不会受到resolve、reject影响</li></ol><h3 id="case4-多then、catch、finally无return"><a href="#case4-多then、catch、finally无return" class="headerlink" title="case4_多then、catch、finally无return"></a>case4_多then、catch、finally无return</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise4</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    resolve(<span class="string">'成功！'</span>)</span><br><span class="line">    <span class="comment">// 以下为第一次then、catch、finally</span></span><br><span class="line">  &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First catch:'</span>, err)</span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First finally:'</span>, res)</span><br><span class="line">      <span class="comment">// 以下为第二次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second then:'</span>, res)</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second catch:'</span>, err)</span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second finally:'</span>, res)</span><br><span class="line">      <span class="comment">// 以下为第三次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third then:'</span>, res)</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third catch:'</span>, err)</span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third finally:'</span>, res)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// testPromise4()</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * testPromise4 执行结果：</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * First then: 成功！              --- then参数值：来自promise内部的resolve参数</span></span><br><span class="line"><span class="comment"> * First finally: undefined       --- finally没有参数，为undefined</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Second then: undefined         --- then参数值：来自第一个then的返回值，没有返回值为undefined</span></span><br><span class="line"><span class="comment"> * Second finally: undefined      --- finally没有参数，为undefined</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Third then: undefined          --- then参数值：来自第二个then的返回值，没有返回值为undefined</span></span><br><span class="line"><span class="comment"> * Third finally: undefined       --- finally没有参数，为undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><h3 id="case5-resolve引发多then、catch、finally有return"><a href="#case5-resolve引发多then、catch、finally有return" class="headerlink" title="case5_resolve引发多then、catch、finally有return"></a>case5_resolve引发多then、catch、finally有return</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise5</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    resolve(<span class="string">'成功！'</span>)</span><br><span class="line">    <span class="comment">// 以下为第一次then、catch、finally</span></span><br><span class="line">  &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From first then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From first catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From first finally'</span></span><br><span class="line">      <span class="comment">// 以下为第二次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second finally'</span></span><br><span class="line">      <span class="comment">// 以下为第三次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third finally'</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// testPromise5()</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * testPromise5 执行结果：</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * First then: 成功！              --- then参数值：来自promise内部的resolve参数</span></span><br><span class="line"><span class="comment"> * First finally: undefined       --- finally没有参数，为undefined</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Second then: From first then   --- then参数值：来自第一个then的返回值，没有返回值为undefined</span></span><br><span class="line"><span class="comment"> * Second finally: undefined      --- finally没有参数，为undefined</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Third then: From second then   --- then参数值：来自第二个then的返回值，没有返回值为undefined</span></span><br><span class="line"><span class="comment"> * Third finally: undefined       --- finally没有参数，为undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><h3 id="case6-reject引发多then、catch、finally有return"><a href="#case6-reject引发多then、catch、finally有return" class="headerlink" title="case6_reject引发多then、catch、finally有return"></a>case6_reject引发多then、catch、finally有return</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise6</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    reject(<span class="string">'失败！'</span>)</span><br><span class="line">    <span class="comment">// 以下为第一次then、catch、finally</span></span><br><span class="line">  &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From first then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From first catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From first finally'</span></span><br><span class="line">      <span class="comment">// 以下为第二次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second finally'</span></span><br><span class="line">      <span class="comment">// 以下为第三次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third finally'</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">testPromise6()</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * testPromise6 执行结果：</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * First catch: 失败！             --- then参数值：来自promise内部的reject参数</span></span><br><span class="line"><span class="comment"> * First finally: undefined       --- finally没有参数，为undefined</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Second then: From first then   --- then参数值：来自第一个then的返回值，没有返回值为undefined</span></span><br><span class="line"><span class="comment"> * Second finally: undefined      --- finally没有参数，为undefined</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Third then: From second then   --- then参数值：来自第二个then的返回值，没有返回值为undefined</span></span><br><span class="line"><span class="comment"> * Third finally: undefined       --- finally没有参数，为undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p>case4、case5、case6结论：</p><ol><li>第一次then|catch、finally执行的是promise内部的结果</li><li>第一次then|catch的参数来自promise内部的resolve、reject，finally无参数</li><li>第二次及以后的then一定会执行，参数来自上一个then的返回值，无返回值为undefined</li><li>第二次及以后的finally一定会执行，无参数，为undefined</li></ol><h3 id="case7-new-Error"><a href="#case7-new-Error" class="headerlink" title="case7_new Error"></a>case7_new Error</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise7</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    resolve(<span class="string">'成功！'</span>)</span><br><span class="line">    <span class="comment">// 以下为第一次then、catch、finally</span></span><br><span class="line">  &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'From first then'</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From first catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'From first finally'</span>)</span><br><span class="line">      <span class="comment">// 以下为第二次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second finally'</span></span><br><span class="line">      <span class="comment">// 以下为第三次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third finally'</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">testPromise7()</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * testPromise7 执行结果：</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * First then: 成功！</span></span><br><span class="line"><span class="comment"> * First finally: undefined</span></span><br><span class="line"><span class="comment"> * Second then: Error: From first then at ...</span></span><br><span class="line"><span class="comment"> * Second finally: undefined</span></span><br><span class="line"><span class="comment"> * Third then: From second then</span></span><br><span class="line"><span class="comment"> * Third finally: undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><h3 id="case8-throw-Error"><a href="#case8-throw-Error" class="headerlink" title="case8_throw Error"></a>case8_throw Error</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise8</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    resolve(<span class="string">'成功！'</span>)</span><br><span class="line">    reject(<span class="string">'失败！'</span>)</span><br><span class="line">    <span class="comment">// 以下为第一次then、catch、finally</span></span><br><span class="line">  &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">      <span class="comment">// return new Error('From first then')</span></span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'From first then'</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From first catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'From first finally'</span>)</span><br><span class="line">      <span class="comment">// 以下为第二次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second finally'</span></span><br><span class="line">      <span class="comment">// 以下为第三次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Third finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From third finally'</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">testPromise8()</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * testPromise8 执行结果</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * First then: 成功！</span></span><br><span class="line"><span class="comment"> * First catch: Error: From first then at ...</span></span><br><span class="line"><span class="comment"> * First finally: undefined</span></span><br><span class="line"><span class="comment"> * Second then: From first catch</span></span><br><span class="line"><span class="comment"> * Second finally: undefined</span></span><br><span class="line"><span class="comment"> * Third then: From second then</span></span><br><span class="line"><span class="comment"> * Third finally: undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p>case7、case8结论：</p><ol><li>第二次及以后的then中如果return Error，会被下一个then作为参数输出，finally始终无参数。只会影响下一个，不会影响下下个。</li><li>第二次如果是throw Error，则会被当前的catch语句所捕获</li><li>return Error只是作为一个常规的报错返回，而throw则是直接抛出异常</li></ol><h3 id="case9-then回调两个参数return-Error"><a href="#case9-then回调两个参数return-Error" class="headerlink" title="case9_then回调两个参数return Error"></a>case9_then回调两个参数return Error</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise9</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    resolve(<span class="string">'成功！'</span>)</span><br><span class="line">    <span class="comment">// 以下为第一次then、catch、finally</span></span><br><span class="line">  &#125;)</span><br><span class="line">    .then(</span><br><span class="line">      (res) =&gt; &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'From first then'</span>)</span><br><span class="line">      &#125;,</span><br><span class="line">      (err) =&gt; &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'First catch1:'</span>, err)</span><br><span class="line">        <span class="keyword">return</span> <span class="string">'From first catch2'</span></span><br><span class="line">      &#125;</span><br><span class="line">    )</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First catch2:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From first catch2'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'From first finally'</span>)</span><br><span class="line">      <span class="comment">// 以下为第二次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second finally'</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">testPromise9()</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * testPromise9 执行结果：</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * First then: 成功！</span></span><br><span class="line"><span class="comment"> * First catch2: Error: From first then at ...</span></span><br><span class="line"><span class="comment"> * First finally: undefined</span></span><br><span class="line"><span class="comment"> * Second then: From first catch2</span></span><br><span class="line"><span class="comment"> * Second finally: undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><h3 id="case10-then回调两个参数throw-Error"><a href="#case10-then回调两个参数throw-Error" class="headerlink" title="case10_then回调两个参数throw Error"></a>case10_then回调两个参数throw Error</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise10</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    reject(<span class="string">'失败！'</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">    .then(</span><br><span class="line">      (res) =&gt; &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">      &#125;,</span><br><span class="line">      (err) =&gt; &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'First catch1:'</span>, err)</span><br><span class="line">        <span class="comment">// return 'From first catch2'</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'From first catch1'</span>)</span><br><span class="line">      &#125;</span><br><span class="line">    )</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First catch2:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From first catch2'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'First finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'From first finally'</span>)</span><br><span class="line">      <span class="comment">// 以下为第二次then、catch、finally</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second then:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second then'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second catch:'</span>, err)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second catch'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .finally(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Second finally:'</span>, res)</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'From second finally'</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">testPromise10()</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * testPromise10 执行结果：</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * First catch1: 失败！</span></span><br><span class="line"><span class="comment"> * First catch2: Error: From first then at ...</span></span><br><span class="line"><span class="comment"> * First finally: undefined</span></span><br><span class="line"><span class="comment"> * Second then: From first catch2</span></span><br><span class="line"><span class="comment"> * Second finally: undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><h3 id="case11-then回调三个参数"><a href="#case11-then回调三个参数" class="headerlink" title="case11_then回调三个参数"></a>case11_then回调三个参数</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">testPromise11</span> (<span class="params">val</span>) </span>&#123;</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    reject(<span class="string">'失败！'</span>)</span><br><span class="line">    resolve(<span class="string">'成功！'</span>)</span><br><span class="line">&#125;).then(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'First then:'</span>, res)</span><br><span class="line">&#125;, err =&gt; &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'First catch1:'</span>, err)</span><br><span class="line">  &#125;, () =&gt; &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'First finally1:'</span>, err)</span><br><span class="line">  &#125;).catch(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'First catch2:'</span>, err)</span><br><span class="line">&#125;).finally(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'First finally2:'</span>, res)</span><br><span class="line">&#125;)</span><br><span class="line">&#125;</span><br><span class="line">testPromise11()</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"> * First catch1: 失败！</span></span><br><span class="line"><span class="comment"> * First finally2: undefined</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p>case9、case10结论：</p><ol><li>在then中连续写两个回调，第一个参数为then，第二个参数为catch，在then后面再写一个catch。</li><li>如果是resolve，在then的第一个参数中throw Error，会被下一个catch所捕获</li><li>如果是reject，在then的第二个参数中throw Error，会被下一个catch所捕获</li><li>即：then…catch可以将两个回调都赋给then，直接写两个参数，then后面的catch会被当前其他的catch，只有前面的then内部抛出异常才会执行。</li></ol>]]></content>
    
    <summary type="html">
    
      promise多个then、catch、finally的执行结果
    
    </summary>
    
    
      <category term="ES6" scheme="http://pimichen.com/blog/tags/es6/"/>
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>程序复杂度</title>
    <link href="http://pimichen.com/blog/javascript/%E7%A8%8B%E5%BA%8F%E5%A4%8D%E6%9D%82%E5%BA%A6.html"/>
    <id>http://pimichen.com/blog/javascript/程序复杂度.html</id>
    <published>2022-02-28T16:00:00.000Z</published>
    <updated>2022-02-28T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>参考：<a href="https://zhuanlan.zhihu.com/p/50479555" target="_blank" rel="noopener">知乎 算法的时间与空间复杂度</a></p></blockquote><p><img src="../images/javascript/js_complexity.png" title="复杂度"></p><p>时间维度：是指执行当前算法所消耗的时间，我们通常用「时间复杂度」来描述。<br>空间维度：是指执行当前算法需要占用多少内存空间，我们通常用「空间复杂度」来描述。</p><h2 id="常用的时间复杂度"><a href="#常用的时间复杂度" class="headerlink" title="常用的时间复杂度"></a>常用的时间复杂度</h2><p><strong><em>从上往下越来越复杂</em></strong></p><ul><li><p>常数阶 O(1)<br>无论多少代码，只有没有循环等结构，复杂度均为O(1)。</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">let</span> i = <span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> j = <span class="number">2</span></span><br><span class="line">++i</span><br><span class="line">j++</span><br><span class="line"><span class="keyword">let</span> m = i + j</span><br></pre></td></tr></table></figure></li><li><p>对数阶 O(logN)，log以2为底<br>索引每次循环*2，即使log2(n)次<br>二分查找也是一个典型的对数阶复杂度，每查找一次就排除一半，n个数据只需要查找log2(n)次</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">  i = i * <span class="number">2</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>线性阶 O(n)<br>简单一层循环，执行n遍，复杂度为O(n)</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; n; i++)&#123;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>线性对数阶 O(n * logN)<br>外面一层循环，连一层二分循环</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">let</span> i = <span class="number">0</span>; i &lt; n; i++)&#123;</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">let</span> j = <span class="number">0</span>; j &lt; m; j++)&#123;</span><br><span class="line">    j = j * <span class="number">2</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>平方阶 O(n^2)<br>简单两层循环，执行n^2遍，复杂度为O(n^2)</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">let</span> i = <span class="number">0</span>; i &lt; n; i++)&#123;</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">let</span> j = <span class="number">0</span>; j &lt; m; j++)&#123;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>立方阶 O(n^3)<br>同上</p></li><li><p>k次方阶 O(n^k)<br>同上</p></li><li><p>指数阶 O(2^n)<br>略</p></li></ul><h2 id="常用的空间复杂度"><a href="#常用的空间复杂度" class="headerlink" title="常用的空间复杂度"></a>常用的空间复杂度</h2><p>待补充…</p><blockquote><p>参考：<a href="https://zhuanlan.zhihu.com/p/50479555" target="_blank" rel="noopener">知乎 算法的时间与空间复杂度</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      常见的时间复杂度和空间复杂度
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>Object.defineProperty和Proxy对比</title>
    <link href="http://pimichen.com/blog/javascript/Object.defineProperty%E5%92%8CProxy%E5%AF%B9%E6%AF%94.html"/>
    <id>http://pimichen.com/blog/javascript/Object.defineProperty和Proxy对比.html</id>
    <published>2021-05-26T16:00:00.000Z</published>
    <updated>2021-05-26T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Object-defineProperty"><a href="#Object-defineProperty" class="headerlink" title="Object.defineProperty"></a>Object.defineProperty</h2><p><code>Object.defineProperty</code> 会直接在一个对象上定义一个新属性，或者修改一个对象的现有属性，并返回此对象。</p><p>先看一个demo:<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> object = &#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(object, <span class="string">'property1'</span>, &#123;</span><br><span class="line">  value: <span class="number">20</span>,</span><br><span class="line">  writable: <span class="literal">false</span> <span class="comment">// 定义该属性不可改</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(object)</span><br><span class="line"><span class="comment">// &#123; property1: 20 &#125;</span></span><br><span class="line"></span><br><span class="line">object.property1 = <span class="number">30</span></span><br><span class="line"><span class="comment">// &#123; property1: 20 &#125;</span></span><br></pre></td></tr></table></figure></p><p>语法<br><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="built_in">Object</span>.defineProperty(obj, prop, descriptor)</span><br></pre></td></tr></table></figure></p><p>参数</p><ul><li>obj<br>要定义的对象</li><li>prop<br>要定义或修改的属性名称（或Symbol）</li><li><p>descriptor<br>要定义或修改的属性描述符（数据描述符、存取描述符）</p><p>数据描述符包含：</p><ul><li>configurable(false)<br>为 <code>true</code> 时，该属性的描述符才能够被改变，也能删除</li><li>enumerable(false)<br>为 <code>true</code> 时，该属性才会出现在对象的枚举属性中（被 <code>for...in</code>、<code>Object.keys</code> 访问）</li><li>value(undefined)<br>该属性对应的值</li><li>writable(false)<br>为 <code>true</code> 时，才可改</li></ul><p>存取描述符包含：</p><ul><li>get(undefined)<br>属性的 <code>getter</code> 函数，当访问该属性时，会调用此函数。</li><li>set(undefined)<br>属性的 <code>setter</code> 函数，当属性值被修改时，会调用此函数。</li></ul></li></ul><p>注意：</p><ol><li>如果一个描述符不具有 <code>value</code>、<code>writable</code>、<code>get</code>、<code>set</code> 中的任意一个键，它会被认为是一个数据描述符。</li><li>如果一个描述符同时拥有 <code>value</code> 或 <code>writable</code> 和 <code>get</code> 或 <code>set</code> 键，它会抛出异常。</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> o = &#123;&#125;;</span><br><span class="line">o.a = <span class="number">1</span>;</span><br><span class="line"><span class="comment">// 等同于：</span></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(o, <span class="string">"a"</span>, &#123;</span><br><span class="line">  value: <span class="number">1</span>,</span><br><span class="line">  writable: <span class="literal">true</span>,</span><br><span class="line">  configurable: <span class="literal">true</span>,</span><br><span class="line">  enumerable: <span class="literal">true</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(<span class="number">0</span>, <span class="string">"a"</span>, &#123; <span class="attr">value</span>: <span class="number">1</span> &#125;)</span><br><span class="line"><span class="comment">// 等同于</span></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(o, <span class="string">"a"</span>, &#123;</span><br><span class="line">  value: <span class="number">1</span>,</span><br><span class="line">  writable: <span class="literal">false</span>,</span><br><span class="line">  configurable: <span class="literal">false</span>,</span><br><span class="line">  enumerable: <span class="literal">false</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>自定义 <code>Setters</code> 和 <code>Getters</code><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><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="function"><span class="keyword">function</span> <span class="title">Archiver</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> temp = <span class="literal">null</span></span><br><span class="line">  <span class="keyword">var</span> archive = []</span><br><span class="line"></span><br><span class="line">  <span class="built_in">Object</span>.defineProperty(<span class="keyword">this</span>, <span class="string">'temp'</span>, &#123;</span><br><span class="line">    get () &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'get'</span>)</span><br><span class="line">      <span class="keyword">return</span> temp</span><br><span class="line">    &#125;,</span><br><span class="line">    set (value) &#123;</span><br><span class="line">      temp = value</span><br><span class="line">      archive.push(&#123; <span class="attr">val</span>: temp &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">this</span>.getArchive = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> archive</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">var</span> arc = <span class="keyword">new</span> Archiver()</span><br><span class="line">arc.temp <span class="comment">// 'get', null</span></span><br><span class="line">arc.temp = <span class="number">11</span></span><br><span class="line">arc.temp = <span class="number">13</span></span><br><span class="line">arc.getArchive() <span class="comment">// [&#123;val: 11&#125;, &#123;val: 13&#125;]</span></span><br></pre></td></tr></table></figure></p><p>继承属性<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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">MyClass</span>(<span class="params"></span>) </span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> value;</span><br><span class="line"><span class="built_in">Object</span>.defineProperty(MyClass.prototype, <span class="string">'x'</span>, &#123;</span><br><span class="line">  get () &#123;</span><br><span class="line">    <span class="keyword">return</span> value</span><br><span class="line">  &#125;,</span><br><span class="line">  set (newValue) &#123;</span><br><span class="line">    value = newValue</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">var</span> a = <span class="keyword">new</span> MyClass()</span><br><span class="line"><span class="keyword">var</span> b = <span class="keyword">new</span> MyClass()</span><br><span class="line">a.x = <span class="number">1</span> <span class="comment">// a.__proto__ 和 MyClass.prototype 相等</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(a.x, b.x) <span class="comment">// 1 1</span></span><br></pre></td></tr></table></figure></p><p>可以通过将值存储在另一个属性中解决。在 <code>get</code> 和 <code>set</code> 方法中，<code>this</code> 指向某个被访问和修改属性的对象<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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">MyClass</span>(<span class="params"></span>) </span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(MyClass.prototype, <span class="string">'x'</span>, &#123;</span><br><span class="line">  get () &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.stored_x</span><br><span class="line">  &#125;,</span><br><span class="line">  set (newValue) &#123;</span><br><span class="line">    <span class="keyword">this</span>.stored_x = newValue</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">var</span> a = <span class="keyword">new</span> MyClass()</span><br><span class="line"><span class="keyword">var</span> b = <span class="keyword">new</span> MyClass()</span><br><span class="line">a.x = <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(a.x, b.x) <span class="comment">// 1 undefined</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// this指向MyClass.prototype对象</span></span><br></pre></td></tr></table></figure></p><h2 id="Proxy"><a href="#Proxy" class="headerlink" title="Proxy"></a>Proxy</h2><p><code>Proxy</code> 对象用于创建一个对象的代理，从而实现基本操作的拦截和自定义。</p><p>语法<br><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> p = <span class="keyword">new</span> <span class="built_in">Proxy</span>(target, handler)</span><br></pre></td></tr></table></figure></p><p>参数</p><ul><li>target<br>要使用 <code>Proxy</code> 包装的目标对象，可以是对象、数组、函数，甚至是另外一个代理</li><li>handler<br>一个通常以函数为属性的对象</li></ul><p>基础示例<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> p = <span class="keyword">new</span> <span class="built_in">Proxy</span>(&#123;&#125;, &#123;</span><br><span class="line">  get (obj, prop) &#123;</span><br><span class="line">    <span class="keyword">return</span> prop <span class="keyword">in</span> obj ? obj[prop] : <span class="number">30</span> <span class="comment">// 存在即返回，不存在就返回30</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line">p.a = <span class="number">1</span></span><br><span class="line">p.b = <span class="literal">undefined</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(p.a, p.b) <span class="comment">// 1, undefined</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'c'</span> <span class="keyword">in</span> p, p.c) <span class="comment">// false, 30</span></span><br></pre></td></tr></table></figure></p><p>无操作转发代理<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> target = &#123;&#125;</span><br><span class="line"><span class="keyword">const</span> p = <span class="keyword">new</span> <span class="built_in">Proxy</span>(target, &#123;&#125;)</span><br><span class="line"></span><br><span class="line">p.a = <span class="number">30</span> <span class="comment">// p代理会将所有的操作都转发到这个对象上</span></span><br><span class="line"><span class="built_in">console</span>.log(p.a, target.a) <span class="comment">// 30, 30</span></span><br></pre></td></tr></table></figure></p><h2 id="vue2-x"><a href="#vue2-x" class="headerlink" title="vue2.x"></a>vue2.x</h2><p>在 vue2.x 中，双向绑定是通过监听对象的get和set操作来实现的。即是 <code>Object.defineProperty</code><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> obj = &#123;</span><br><span class="line">  a: <span class="number">1</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> val = <span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> newVal = <span class="number">2</span></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(obj, <span class="string">'a'</span>, &#123;</span><br><span class="line">  get () &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'数据被获取'</span>)</span><br><span class="line">    <span class="keyword">return</span> val</span><br><span class="line">  &#125;,</span><br><span class="line">  set (newVal) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'数据被修改/设置'</span>)</span><br><span class="line">    val = newVal</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></p><p>每当我们获取 obj 的 a 属性或设置 a 属性时，都会被劫持。在 vue2.x 中正是采用这种监听方式使用<strong>发布-订阅模式</strong>，data 上的数据是发布方，而试图的修改是订阅方，每当数据发生修改时，就会发布信息，而订阅方接受到相应的信息，就会对视图进行修改。</p><p>下面简单模拟一下发布-订阅的流程：<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><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> publisher = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    currentList: [],</span><br><span class="line">    add (subscriber) &#123;</span><br><span class="line">      <span class="keyword">this</span>.currentList.push(subscriber)</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'添加订阅'</span>, <span class="keyword">this</span>.currentList) <span class="comment">// [&#123; receiveText()&#123;&#125; &#125;, ..]</span></span><br><span class="line">    &#125;,</span><br><span class="line">    publish (key, content) &#123;</span><br><span class="line">      <span class="keyword">const</span> currentList = <span class="keyword">this</span>.currentList</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'订阅集合'</span>, currentList)</span><br><span class="line">      <span class="comment">// 遍历订阅者的数组</span></span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; currentList.length; i++) &#123;</span><br><span class="line">        currentList[i].receiveText(key, content)</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">const</span> subscriber = <span class="function"><span class="keyword">function</span> (<span class="params">name</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    receiveText (key, content) &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">`视图<span class="subst">$&#123;key&#125;</span>已更新，相应的内容为<span class="subst">$&#123;content&#125;</span>`</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将data作为发布方</span></span><br><span class="line"><span class="keyword">const</span> data = publisher()</span><br><span class="line"><span class="comment">// 将视图修改作为订阅方</span></span><br><span class="line"><span class="keyword">const</span> change = subscriber()</span><br><span class="line"><span class="comment">// 让视图修改订阅data的更新</span></span><br><span class="line">data.add(change)</span><br><span class="line">data._a = <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(data, <span class="string">'a'</span>, &#123;</span><br><span class="line">  get () &#123;</span><br><span class="line">    <span class="keyword">return</span> data._a</span><br><span class="line">  &#125;,</span><br><span class="line">  set (newVal) &#123;</span><br><span class="line">    data.publish(<span class="string">'a'</span>, newVal)</span><br><span class="line">    data._a = newVal</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">// test</span></span><br><span class="line">data.a <span class="comment">// 1 返回data._a的数据</span></span><br><span class="line">data.a = <span class="number">10</span> <span class="comment">//</span></span><br></pre></td></tr></table></figure></p><h2 id="vue3-0"><a href="#vue3-0" class="headerlink" title="vue3.0"></a>vue3.0</h2><p>虽然 <code>Object.defineProperty</code> 可以实现双向绑定的效果，但是在 <code>Proxy</code> 出现后，它就被替代掉了。<br><code>Object.defineProperty</code> 只能一个属性一个属性的监听，也就是说，对于 data 对象，我们需要进行深度遍历，去监听每一个属性的变化，而一旦我们对data一个比较深的对象直接修改它的值，又得对其进行重新的遍历，非常损耗性能。而 <code>Proxy</code> 可以监听一整个对象，且基于 <code>Proxy</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="keyword">const</span> p = <span class="keyword">new</span> <span class="built_in">Proxy</span>(&#123;&#125;, &#123;</span><br><span class="line">  get (target, property, receiver) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">`getting <span class="subst">$&#123;key&#125;</span>`</span>)</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Reflect</span>.get(target, property, receiver)</span><br><span class="line">  &#125;,</span><br><span class="line">  set (target, property, value, receiver) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">`setting <span class="subst">$&#123;key&#125;</span>`</span>)</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Reflect</span>.set(target, property, value, receiver)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>模拟发布-订阅<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var publisher</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      Object.defineProperty和Proxy对比
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>vue技术栈如何支持SEO</title>
    <link href="http://pimichen.com/blog/vue/vue%E6%8A%80%E6%9C%AF%E6%A0%88%E5%A6%82%E4%BD%95%E6%94%AF%E6%8C%81SEO.html"/>
    <id>http://pimichen.com/blog/vue/vue技术栈如何支持SEO.html</id>
    <published>2021-02-17T16:00:00.000Z</published>
    <updated>2021-02-17T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="vue-渐进式"><a href="#vue-渐进式" class="headerlink" title="vue 渐进式"></a>vue 渐进式</h2><p>先简单回顾一下 vue 技术栈，在渐进式（对使用者的要求，逐渐添加）的思想上我们可以逐渐添加Components、Vue-Router、Vuex，它们之间相互独立，互不影响</p><p>渐进步骤：<br><img src="../images/vue/vue_process.png" title="vue渐进步骤"></p><p>下面介绍几种常见的vue seo方案：</p><h2 id="实现方案"><a href="#实现方案" class="headerlink" title="实现方案"></a>实现方案</h2><h3 id="简单html"><a href="#简单html" class="headerlink" title="简单html"></a>简单html</h3><p>毫无疑问，即按照最简单的html书写方式，一个页面即一个html，多见于一些后端同学编写的后台系统页面。本质上和vue没有多大关系，<font color="red">对于前端同学，此种方案几乎不考虑</font>。</p><h3 id="prerender-spa-plugin"><a href="#prerender-spa-plugin" class="headerlink" title="prerender-spa-plugin"></a>prerender-spa-plugin</h3><p>对于使用 <code>vue-cli</code> 初始化的项目，如果只是需要<font color="red">改善少数营销页面</font>（例如 <code>/</code>，<code>/about</code>，<code>/news</code>）的SEO，那么可能预渲染（prerender）更加适用。无需使用 web 服务器实时动态编译 HTML，而是使用预渲染方式，在构建时 (build time) 简单地生成针对特定路由的静态 HTML 文件。</p><p>我们可以使用 <a href="https://github.com/chrisvfritz/prerender-spa-plugin" target="_blank" rel="noopener">prerender-spa-plugin</a> 轻松地添加预渲染。只适用于 <code>history</code> 模式，<code>hash</code> 不可用。</p><p><strong>工作流程</strong>如下：<br><img src="../images/vue/vue_prerender.png" title="prerender流程"></p><p><strong>使用方式</strong>如下：</p><ol><li><p>初始化 vue-cli 脚手架</p></li><li><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">npm i prerender-spa-plugin -S</span><br></pre></td></tr></table></figure><p>注：插件内置安装了 <code>puppeteer</code>，所以安装过程比较慢</p></li><li><p>修改main.js</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">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#app'</span>,</span><br><span class="line">  render: <span class="function"><span class="params">h</span> =&gt;</span> h(App),</span><br><span class="line">  mounted () &#123;</span><br><span class="line">    <span class="comment">// You'll need this for renderAfterDocumentEvent.</span></span><br><span class="line">    <span class="built_in">document</span>.dispatchEvent(<span class="keyword">new</span> Event(<span class="string">'render-event'</span>))</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li><li><p>应用插件<br><code>build/webpack.prod.conf.js</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> PrerenderSPAPlugin = <span class="built_in">require</span>(<span class="string">'prerender-spa-plugin'</span>)</span><br><span class="line"><span class="keyword">const</span> Renderer = PrerenderSPAPlugin.PuppeteerRenderer</span><br><span class="line"></span><br><span class="line"><span class="comment">// prerender</span></span><br><span class="line"><span class="keyword">new</span> PrerenderSPAPlugin(&#123;</span><br><span class="line">  <span class="comment">// 生成文件的路径，也可以与webpakc打包的一致。</span></span><br><span class="line">  <span class="comment">// 下面这句话非常重要！！！</span></span><br><span class="line">  <span class="comment">// 这个目录只能有一级，如果目录层次大于一级，在生成的时候不会有任何错误提示，在预渲染的时候只会卡着不动。</span></span><br><span class="line">  staticDir: path.join(__dirname, <span class="string">'../dist'</span>),</span><br><span class="line">  <span class="comment">// 对应自己的路由文件，比如index有参数，就需要写成 /index/param1</span></span><br><span class="line">  routes: [ <span class="string">'/'</span>, <span class="string">'/user'</span> ],</span><br><span class="line">  renderer: <span class="keyword">new</span> Renderer(&#123;</span><br><span class="line">    inject: &#123;</span><br><span class="line">      foo: <span class="string">'bar'</span></span><br><span class="line">    &#125;,</span><br><span class="line">    headless: <span class="literal">true</span>,</span><br><span class="line">    <span class="comment">// 在 main.js 中 document.dispatchEvent(new Event('render-event'))，两者的事件名称要对应上</span></span><br><span class="line">    renderAfterDocumentEvent: <span class="string">'render-event'</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li><li><p>为了更方便的测试dist</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">npm i http-server -S</span><br></pre></td></tr></table></figure><p>再添加scripts:</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"><span class="string">"serve"</span>: <span class="string">"http-server ./dist"</span></span><br></pre></td></tr></table></figure></li><li><p>更好的SEO</p></li></ol><ul><li><p>vue-meta-info</p><p>main.js:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> MetaInfo <span class="keyword">from</span> <span class="string">'vue-meta-info'</span></span><br><span class="line"></span><br><span class="line">Vue.use(MetaInfo)</span><br></pre></td></tr></table></figure><p>组件中：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  metaInfo: &#123;</span><br><span class="line">    title: <span class="string">'我是一个title'</span>,</span><br><span class="line">    meta: [</span><br><span class="line">      &#123;</span><br><span class="line">        name: <span class="string">'keywords'</span>,</span><br><span class="line">        content: <span class="string">'关键字1,关键字2,关键字3'</span></span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        name: <span class="string">'description'</span>,</span><br><span class="line">        content: <span class="string">'这是一段网页的描述'</span></span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h3 id="ssr"><a href="#ssr" class="headerlink" title="ssr"></a>ssr</h3><p><a href="https://ssr.vuejs.org/zh/" target="_blank" rel="noopener">官方文档</a></p><p>与传统的SPA（Single-Page Application - 单页应用程序）相比，服务端渲染（SSR）的优势主要在于：</p><ul><li>更好的SEO</li><li>更快的内容到达时间（time-to-content）</li></ul><p>使用服务端渲染（SSR）时还需要一些权衡之处：</p><ul><li>开发条件有限。浏览器特定的代码，只能在某些生命周期钩子函数（lifecycle hook）中使用，一些外部扩展库（external library）可能需要特殊处理，才能在服务端渲染应用程序中运行。</li><li>涉及构建设置和部署的更多要求。与可以部署在任何静态文件服务器上的完全静态单页面应用程序(SPA)不同，服务器渲染应用程序，需要处于 Node.js server 运行环境。</li><li>更多的服务器负载。在 Node.js 中渲染完整的应用程序，显然会比仅仅提供静态文件的 server 更加大量占用 CPU 资源(CPU-intensive - CPU 密集)，因此如果你预料在高流量环境(high traffic)下使用，请准备相应的服务器负载，并明智地采用缓存策略。</li></ul><p>在对你的应用程序使用服务器端渲染(SSR)之前，你应该问的第一个问题是，是否真的需要它。这主要取决于内容到达时间(time-to-content)对应用程序的重要程度。例如，如果你正在构建一个内部仪表盘，初始加载时的额外几百毫秒并不重要，这种情况下去使用服务器端渲染(SSR)将是一个小题大作之举。然而，内容到达时间(time-to-content)要求是绝对关键的指标，在这种情况下，服务器端渲染(SSR)可以帮助你实现最佳的初始加载性能。</p><p>vue官方对于ssr方案提供了集成的框架 nuxt.js，下面介绍nuxt.js。</p><h3 id="nuxt-js"><a href="#nuxt-js" class="headerlink" title="nuxt.js"></a>nuxt.js</h3><p><code>nuxt.js</code> 提供了两种模式，一种 <code>generate</code> 静态化模式，一种 <code>build</code> node渲染模式。</p><h4 id="generate模式"><a href="#generate模式" class="headerlink" title="generate模式"></a>generate模式</h4><p><code>generate</code> 本质上是提前将vue组件的内容编译输出到对应的html中，属于前置输出，<font color="red">适用于静态化的网站，只有一些简单的文字内容，搭配一下简单的接口（接口无需seo）</font>。</p><p>另外不适用与动态路由，如/news/1234567，1234567为动态id，因为想用访问/news/1234567，就必须提前输出这个html页面。部分网友提供解决方案，在执行 <code>npm run generate</code> 的时候通过请求获取id list，然后输出html。其实仔细思量后会发现这种方案几乎不可用，对于绝大多数网站，都存在登录态鉴权的问题，无法实现生成html。</p><p>对于这种复杂的应用场景，我们可以采用nuxt.js node渲染模式，如下：</p><h4 id="build模式"><a href="#build模式" class="headerlink" title="build模式"></a>build模式</h4><p><font color="red">对于需要频繁的接口请求，并且需要针对首屏数据做服务端渲染时</font>，可以选用nuxt.js build模式，输入后置输出，再请求页面的时候，node层动态生成内容返回。</p><p>本地开发时执行 <code>npm run dev</code>，本地开发完，先执行 <code>npm run build</code>，生成编译文件，也可以选择在服务器端执行 <code>npm run build</code>，然后在服务器端执行 <code>npm run start</code>，启动服务。</p>]]></content>
    
    <summary type="html">
    
      vue技术栈如何支持SEO，都有哪些方案，如何选择合适的方案
    
    </summary>
    
    
      <category term="Vue" scheme="http://pimichen.com/blog/tags/vue/"/>
    
  </entry>
  
  <entry>
    <title>vue-cli添加骨架屏</title>
    <link href="http://pimichen.com/blog/vue/vue-cli%E6%B7%BB%E5%8A%A0%E9%AA%A8%E6%9E%B6%E5%B1%8F.html"/>
    <id>http://pimichen.com/blog/vue/vue-cli添加骨架屏.html</id>
    <published>2021-01-26T16:00:00.000Z</published>
    <updated>2021-01-26T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="什么是骨架屏？"><a href="#什么是骨架屏？" class="headerlink" title="什么是骨架屏？"></a>什么是骨架屏？</h2><p>骨架屏（Skeleton Screen）是指在页面数据加载完成前，先给用户展示出页面的大致结构（一般是灰色占位图，可以搭配一些动效），在拿到接口数据后渲染出实际页面内容然后替换掉。</p><p>比起简单的全局loading，这种灰色占位图描绘了页面的大致结构，对用户的心理会有一定的缓解。在数据回传之后，过滤也会更加流畅，给人一种页面内容”已经渲染出一部分“的感觉，用户体验更佳。</p><p>骨架屏的内容可以是base64的图片url，也可以是自行编写的dom结构，如果是dom结构，还可以自行实现一些动效，如光源从左扫到右，用动效来吸引用户，让用户忘记白屏时间。</p><p>近几年越来越多的应用采用骨架屏Skeleton，如：饿了么H5、知乎等。</p><h2 id="骨架屏的实现方案"><a href="#骨架屏的实现方案" class="headerlink" title="骨架屏的实现方案"></a>骨架屏的实现方案</h2><p>目前有以下几种实现方案：</p><ul><li>利用ssr实现<br>根据编写的vue文件，手动生成，比较麻烦，不推荐</li><li>vue-skeleton-webpack-plugin<br>根据编写的vue文件，按照路由给对应的页面设置，推荐单页面使用</li><li>page-skeleton-webpack-plugin<br>只支持 <code>history</code> 模式，利用 Puppeteer 读取页面结构，生成骨架屏页面。实测生成的不太稳定，还在研究中。</li><li>dps<br>可以对任意的页面（包括dev页面），生成对应的骨架屏，推荐多页面使用</li></ul><h3 id="利用ssr实现"><a href="#利用ssr实现" class="headerlink" title="利用ssr实现"></a>利用ssr实现</h3><p>原理：事先在 <code>&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;</code> 中间添加骨架屏dom，等接口数据获取完毕后会自动替换调结构，达到渲染的目的。</p><ol><li><p>使用 <code>vue-cli</code> 初始化</p></li><li><p>添加 <code>src/skeleton.entry.js</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">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> Skeleton <span class="keyword">from</span> <span class="string">'./Skeleton.vue'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  components: &#123;</span><br><span class="line">    Skeleton</span><br><span class="line">  &#125;,</span><br><span class="line">  template: <span class="string">'&lt;skeleton /&gt;'</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li><li><p>添加 <code>src/Skeleton.vue</code></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><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</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">"skeleton page"</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">"skeleton-nav"</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">"skeleton-swiper"</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">ul</span> <span class="attr">class</span>=<span class="string">"skeleton-tabs"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span> <span class="attr">v-for</span>=<span class="string">"i in 8"</span> <span class="attr">class</span>=<span class="string">"skeleton-tabs-item"</span>&gt;</span><span class="tag">&lt;<span class="name">span</span>&gt;</span><span class="tag">&lt;/<span class="name">span</span>&gt;</span><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"skeleton-banner"</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">v-for</span>=<span class="string">"i in 6"</span> <span class="attr">class</span>=<span class="string">"skeleton-productions"</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>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="css"><span class="selector-class">.skeleton</span> &#123;</span></span><br><span class="line"><span class="undefined">  position: relative;</span></span><br><span class="line"><span class="undefined">  height: 100%;</span></span><br><span class="line"><span class="undefined">  overflow: hidden;</span></span><br><span class="line"><span class="undefined">  padding: 15px;</span></span><br><span class="line"><span class="undefined">  box-sizing: border-box;</span></span><br><span class="line"><span class="css">  <span class="selector-tag">background</span>: <span class="selector-id">#fff</span>;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="css"><span class="selector-class">.skeleton-nav</span> &#123;</span></span><br><span class="line"><span class="undefined">  height: 45px;</span></span><br><span class="line"><span class="css">  <span class="selector-tag">background</span>: <span class="selector-id">#eee</span>;</span></span><br><span class="line"><span class="undefined">  margin-bottom: 15px;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="css"><span class="selector-class">.skeleton-swiper</span> &#123;</span></span><br><span class="line"><span class="undefined">  height: 160px;</span></span><br><span class="line"><span class="css">  <span class="selector-tag">background</span>: <span class="selector-id">#eee</span>;</span></span><br><span class="line"><span class="undefined">  margin-bottom: 15px;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="css"><span class="selector-class">.skeleton-tabs</span> &#123;</span></span><br><span class="line"><span class="undefined">  list-style: none;</span></span><br><span class="line"><span class="undefined">  padding: 0;</span></span><br><span class="line"><span class="undefined">  margin: 0 -15px;</span></span><br><span class="line"><span class="undefined">  display: flex;</span></span><br><span class="line"><span class="undefined">  flex-wrap: wrap;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="css"><span class="selector-class">.skeleton-tabs-item</span> &#123;</span></span><br><span class="line"><span class="undefined">  width: 25%;</span></span><br><span class="line"><span class="undefined">  height: 55px;</span></span><br><span class="line"><span class="undefined">  box-sizing: border-box;</span></span><br><span class="line"><span class="undefined">  text-align: center;</span></span><br><span class="line"><span class="undefined">  margin-bottom: 15px;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="css"><span class="selector-class">.skeleton-tabs-item</span> <span class="selector-tag">span</span> &#123;</span></span><br><span class="line"><span class="undefined">  display: inline-block;</span></span><br><span class="line"><span class="undefined">  width: 55px;</span></span><br><span class="line"><span class="undefined">  height: 55px;</span></span><br><span class="line"><span class="undefined">  border-radius: 55px;</span></span><br><span class="line"><span class="css">  <span class="selector-tag">background</span>: <span class="selector-id">#eee</span>;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="css"><span class="selector-class">.skeleton-banner</span> &#123;</span></span><br><span class="line"><span class="undefined">  height: 60px;</span></span><br><span class="line"><span class="css">  <span class="selector-tag">background</span>: <span class="selector-id">#eee</span>;</span></span><br><span class="line"><span class="undefined">  margin-bottom: 15px;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="css"><span class="selector-class">.skeleton-productions</span> &#123;</span></span><br><span class="line"><span class="undefined">  height: 20px;</span></span><br><span class="line"><span class="undefined">  margin-bottom: 15px;</span></span><br><span class="line"><span class="css">  <span class="selector-tag">background</span>: <span class="selector-id">#eee</span>;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>安装 vue-server-renderer</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">npm install vue-server-renderer -D</span><br></pre></td></tr></table></figure></li><li><p>添加 <code>build/webpack.skeleton.conf.js</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><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>)</span><br><span class="line"><span class="keyword">const</span> webpack = <span class="built_in">require</span>(<span class="string">'webpack'</span>)</span><br><span class="line"><span class="keyword">const</span> nodeExternals = <span class="built_in">require</span>(<span class="string">'webpack-node-externals'</span>)</span><br><span class="line"><span class="keyword">const</span> VueSSRServerPlugin = <span class="built_in">require</span>(<span class="string">'vue-server-renderer/server-plugin'</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  target: <span class="string">'node'</span>,</span><br><span class="line">  entry: &#123;</span><br><span class="line">    skeleton: <span class="string">'../src/skeleton.entry.js'</span></span><br><span class="line">  &#125;,</span><br><span class="line">  output: &#123;</span><br><span class="line">    path: path.resolve(__dirname, <span class="string">'./dist'</span>),</span><br><span class="line">    publicPath: <span class="string">'/dist/'</span>,</span><br><span class="line">    filename: <span class="string">'[name].js'</span>,</span><br><span class="line">    libraryTarget: <span class="string">'commonjs2'</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="built_in">module</span>: &#123;</span><br><span class="line">    rules: [</span><br><span class="line">      &#123;</span><br><span class="line">        test: <span class="regexp">/\.css$/</span>,</span><br><span class="line">        use: [</span><br><span class="line">          <span class="string">'vue-style-loader'</span>,</span><br><span class="line">          <span class="string">'css-loader'</span></span><br><span class="line">        ]</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        test: <span class="regexp">/\.vue$/</span>,</span><br><span class="line">        loader: <span class="string">'vue-loader'</span></span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line">  externals: nodeExternals(&#123;</span><br><span class="line">    allowlist: <span class="regexp">/\.css$/</span></span><br><span class="line">  &#125;),</span><br><span class="line">  resolve: &#123;</span><br><span class="line">    alias: &#123;</span><br><span class="line">      <span class="string">'vue$'</span>: <span class="string">'vue/dist/vue.esm.js'</span></span><br><span class="line">    &#125;,</span><br><span class="line">    extensions: [<span class="string">'*'</span>, <span class="string">'.js'</span>, <span class="string">'.vue'</span>, <span class="string">'.json'</span>]</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [</span><br><span class="line">    <span class="keyword">new</span> VueSSRServerPlugin(&#123;</span><br><span class="line">      filename: <span class="string">'skeleton.json'</span></span><br><span class="line">    &#125;)</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>根目录下添加 <code>skeleton.js</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>)</span><br><span class="line"><span class="keyword">const</span> &#123; resolve &#125; = <span class="built_in">require</span>(<span class="string">'path'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> createBundleRenderer = <span class="built_in">require</span>(<span class="string">'vue-server-renderer'</span>).createBundleRenderer</span><br><span class="line"></span><br><span class="line"><span class="comment">// 读取`skeleton.json`，以`index.html`为模板写入内容</span></span><br><span class="line"><span class="keyword">const</span> renderer = createBundleRenderer(resolve(__dirname, <span class="string">'./dist/skeleton.json'</span>), &#123;</span><br><span class="line">  template: fs.readFileSync(resolve(__dirname, <span class="string">'./index.html'</span>), <span class="string">'utf-8'</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 把上一步模板完成的内容写入（替换）`index.html`</span></span><br><span class="line">renderer.renderToString(&#123;&#125;, (err, html) =&gt; &#123;</span><br><span class="line">  fs.writeFileSync(<span class="string">'index.html'</span>, html, <span class="string">'utf-8'</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li><li><p>修改入口文件 index.html</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">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!--vue-ssr-outlet--&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>修改 package.json</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"><span class="string">"skeleton"</span>: <span class="string">"webpack --config ./webpack.skeleton.conf.js"</span></span><br></pre></td></tr></table></figure></li><li><p>执行webpack</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">npm run skeleton</span><br></pre></td></tr></table></figure><p>此时，在dist目录会生成一个 <code>skeleton.json</code> 文件</p></li><li><p>自动重写 <code>index.html</code></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">node skeleton.js</span><br></pre></td></tr></table></figure><p>此时，<code>index.html</code> 中的ssr占位符就被替换成了骨架屏dom</p></li><li><p>启动/编译</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">npm run dev</span><br><span class="line"></span><br><span class="line">npm run build</span><br></pre></td></tr></table></figure></li></ol><p>分析：这种方式不好之处在于骨架屏dom是手动生成的，如果修改UI，更换了骨架屏，又需要重新生成，比较麻烦。</p><h3 id="vue-skeleton-webpack-plugin"><a href="#vue-skeleton-webpack-plugin" class="headerlink" title="vue-skeleton-webpack-plugin"></a>vue-skeleton-webpack-plugin</h3><h4 id="单页面生成单骨架屏"><a href="#单页面生成单骨架屏" class="headerlink" title="单页面生成单骨架屏"></a>单页面生成单骨架屏</h4><ol><li><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">npm i vue-skeleton-webpack-plugin -D</span><br></pre></td></tr></table></figure></li><li><p>添加 <code>src/entry-skeleton.js</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">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span>;</span><br><span class="line"><span class="keyword">import</span> Skeleton <span class="keyword">from</span> <span class="string">'./Skeleton'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  components: &#123;</span><br><span class="line">    Skeleton</span><br><span class="line">  &#125;,</span><br><span class="line">  template: <span class="string">'&lt;skeleton /&gt;'</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li><li><p>添加 <code>src/Skeleton.vue</code></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><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</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">"skeleton-wrapper"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">header</span> <span class="attr">class</span>=<span class="string">"skeleton-header"</span>&gt;</span><span class="tag">&lt;/<span class="name">header</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">section</span> <span class="attr">class</span>=<span class="string">"skeleton-block"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">img</span></span></span><br><span class="line"><span class="tag">        <span class="attr">src</span>=<span class="string">"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIMjMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNOTE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg=="</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">img</span></span></span><br><span class="line"><span class="tag">        <span class="attr">src</span>=<span class="string">"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIMjMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNOTE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg=="</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">section</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="javascript">  name: <span class="string">'skeleton'</span></span></span><br><span class="line"><span class="undefined">&#125;;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span> <span class="attr">scoped</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="css"><span class="selector-class">.skeleton-header</span> &#123;</span></span><br><span class="line"><span class="undefined">  height: 152px;</span></span><br><span class="line"><span class="undefined">  background: grey;</span></span><br><span class="line"><span class="undefined">  margin-top: 60px;</span></span><br><span class="line"><span class="undefined">  width: 152px;</span></span><br><span class="line"><span class="undefined">  margin: 60px auto;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="css"><span class="selector-class">.skeleton-block</span> &#123;</span></span><br><span class="line"><span class="undefined">  display: flex;</span></span><br><span class="line"><span class="undefined">  flex-direction: column;</span></span><br><span class="line"><span class="undefined">  padding-top: 8px;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>配置 skeleton router<br>自行配置router，方便访问调试骨架屏，略。</p></li><li><p>添加 <code>build/webpack.skeleton.conf.js</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></pre></td><td class="code"><pre><span class="line"><span class="meta">'use strict'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>)</span><br><span class="line"><span class="keyword">const</span> merge = <span class="built_in">require</span>(<span class="string">'webpack-merge'</span>)</span><br><span class="line"><span class="keyword">const</span> baseWebpackConfig = <span class="built_in">require</span>(<span class="string">'./webpack.base.conf'</span>)</span><br><span class="line"><span class="keyword">const</span> nodeExternals = <span class="built_in">require</span>(<span class="string">'webpack-node-externals'</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">resolve</span>(<span class="params">dir</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> path.join(__dirname, dir)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = merge(baseWebpackConfig, &#123;</span><br><span class="line">  target: <span class="string">'node'</span>,</span><br><span class="line">  devtool: <span class="literal">false</span>,</span><br><span class="line">  entry: &#123;</span><br><span class="line">    app: resolve(<span class="string">'../src/entry-skeleton.js'</span>)</span><br><span class="line">  &#125;,</span><br><span class="line">  output: <span class="built_in">Object</span>.assign(&#123;&#125;, baseWebpackConfig.output, &#123;</span><br><span class="line">    libraryTarget: <span class="string">'commonjs2'</span></span><br><span class="line">  &#125;),</span><br><span class="line">  externals: nodeExternals(&#123;</span><br><span class="line">    allowlist: <span class="regexp">/\.css$/</span></span><br><span class="line">  &#125;),</span><br><span class="line">  plugins: []</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li><li><p>在 <code>build/webpack.dev.conf.js</code> 和 <code>build/webpack.prod.conf.js</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">const</span> SkeletonWebpackPlugin = <span class="built_in">require</span>(<span class="string">'vue-skeleton-webpack-plugin'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// plugins:</span></span><br><span class="line"><span class="keyword">new</span> SkeletonWebpackPlugin(&#123;</span><br><span class="line">  webpackConfig: <span class="built_in">require</span>(<span class="string">'./webpack.skeleton.conf'</span>),</span><br><span class="line">  quiet: <span class="literal">true</span></span><br><span class="line">&#125;),</span><br></pre></td></tr></table></figure></li><li><p>修改 <code>main.js</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><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="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> App <span class="keyword">from</span> <span class="string">'./App'</span></span><br><span class="line"><span class="keyword">import</span> router <span class="keyword">from</span> <span class="string">'./router'</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">'./assets/common.css'</span></span><br><span class="line"></span><br><span class="line">Vue.config.productionTip = <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* eslint-disable no-new */</span></span><br><span class="line"><span class="comment">/* new Vue(&#123;</span></span><br><span class="line"><span class="comment">  el: '#app',</span></span><br><span class="line"><span class="comment">  router,</span></span><br><span class="line"><span class="comment">  components: &#123; App &#125;,</span></span><br><span class="line"><span class="comment">  template: '&lt;App/&gt;'</span></span><br><span class="line"><span class="comment">&#125;) */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 改写</span></span><br><span class="line"><span class="keyword">let</span> app = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  router,</span><br><span class="line">  components: &#123; App &#125;,</span><br><span class="line">  template: <span class="string">'&lt;App/&gt;'</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="built_in">window</span>.mountApp = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  app.$mount(<span class="string">'#app'</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (process.env.NODE_ENV === <span class="string">'production'</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="built_in">window</span>.STYLE_READY) &#123;</span><br><span class="line">    <span class="built_in">window</span>.mountApp()</span><br><span class="line">  &#125;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  <span class="built_in">window</span>.mountApp()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>修改 <code>index.html</code></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><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="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width,initial-scale=1.0"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>skeleton-demo<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">%</span> <span class="attr">for</span> (<span class="attr">var</span> <span class="attr">jsFilePath</span> <span class="attr">of</span> <span class="attr">htmlWebpackPlugin.files.js</span>) &#123; %&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"preload"</span> <span class="attr">href</span>=<span class="string">"&lt;%= jsFilePath %&gt;"</span> <span class="attr">as</span>=<span class="string">"script"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">%</span> &#125; %&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">%</span> <span class="attr">for</span> (<span class="attr">var</span> <span class="attr">cssFilePath</span> <span class="attr">of</span> <span class="attr">htmlWebpackPlugin.files.css</span>) &#123; %&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"preload"</span> <span class="attr">href</span>=<span class="string">"&lt;%= cssFilePath %&gt;"</span> <span class="attr">as</span>=<span class="string">"style"</span> <span class="attr">onload</span>=<span class="string">"this.onload=null;this.rel='stylesheet';window.STYLE_READY=1;window.mountApp&amp;&amp;window.mountApp();"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">noscript</span>&gt;</span><span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"&lt;%= cssFilePath %&gt;"</span>&gt;</span><span class="tag">&lt;/<span class="name">noscript</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">%</span> &#125; %&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript">!<span class="function"><span class="keyword">function</span>(<span class="params">t</span>)</span>&#123;<span class="string">"use strict"</span>;t.loadCSS||(t.loadCSS=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;&#125;);<span class="keyword">var</span> e=loadCSS.relpreload=&#123;&#125;;<span class="keyword">if</span>(e.support=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;<span class="keyword">var</span> e;<span class="keyword">try</span>&#123;e=t.document.createElement(<span class="string">"link"</span>).relList.supports(<span class="string">"preload"</span>)&#125;<span class="keyword">catch</span>(t)&#123;e=!<span class="number">1</span>&#125;<span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;<span class="keyword">return</span> e&#125;&#125;(),e.bindMediaToggle=<span class="function"><span class="keyword">function</span>(<span class="params">t</span>)</span>&#123;<span class="function"><span class="keyword">function</span> <span class="title">e</span>(<span class="params"></span>)</span>&#123;t.media=a&#125;<span class="keyword">var</span> a=t.media||<span class="string">"all"</span>;t.addEventListener?t.addEventListener(<span class="string">"load"</span>,e):t.attachEvent&amp;&amp;t.attachEvent(<span class="string">"onload"</span>,e),setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;t.rel=<span class="string">"stylesheet"</span>,t.media=<span class="string">"only x"</span>&#125;),setTimeout(e,<span class="number">3e3</span>)&#125;,e.poly=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;<span class="keyword">if</span>(!e.support())<span class="keyword">for</span>(<span class="keyword">var</span> a=t.document.getElementsByTagName(<span class="string">"link"</span>),n=<span class="number">0</span>;n&lt;a.length;n++)&#123;<span class="keyword">var</span> o=a[n];<span class="string">"preload"</span>!==o.rel||<span class="string">"style"</span>!==o.getAttribute(<span class="string">"as"</span>)||o.getAttribute(<span class="string">"data-loadcss"</span>)||(o.setAttribute(<span class="string">"data-loadcss"</span>,!<span class="number">0</span>),e.bindMediaToggle(o))&#125;&#125;,!e.support())&#123;e.poly();<span class="keyword">var</span> a=t.setInterval(e.poly,<span class="number">500</span>);t.addEventListener?t.addEventListener(<span class="string">"load"</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;e.poly(),t.clearInterval(a)&#125;):t.attachEvent&amp;&amp;t.attachEvent(<span class="string">"onload"</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;e.poly(),t.clearInterval(a)&#125;)&#125;<span class="string">"undefined"</span>!=<span class="keyword">typeof</span> exports?exports.loadCSS=loadCSS:t.loadCSS=loadCSS&#125;(<span class="string">"undefined"</span>!=<span class="keyword">typeof</span> global?global:<span class="keyword">this</span>);</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- built files will be auto injected --&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>启动/编译</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">npm run dev</span><br><span class="line"></span><br><span class="line">npm run build</span><br></pre></td></tr></table></figure></li></ol><h4 id="单页面生成多骨架屏"><a href="#单页面生成多骨架屏" class="headerlink" title="单页面生成多骨架屏"></a>单页面生成多骨架屏</h4><p>什么是多骨架屏，顾名思义。多个骨架屏，可以针对不同的页面设置不同的骨架屏，实际上这种才是比较合理的。比如底部有四个tab，都作为一级入口，用户随便从哪个入口进入都可以看到对应的骨架屏。</p><ol><li><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">npm i vue-skeleton-webpack-plugin -D</span><br></pre></td></tr></table></figure></li><li><p>添加 <code>src/skeleton.js</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span>;</span><br><span class="line"><span class="keyword">import</span> Skeleton1 <span class="keyword">from</span> <span class="string">'./components/skeleton/Skeleton1'</span>;</span><br><span class="line"><span class="keyword">import</span> Skeleton2 <span class="keyword">from</span> <span class="string">'./components/skeleton/Skeleton2'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  components: &#123;</span><br><span class="line">    Skeleton1,</span><br><span class="line">    Skeleton2</span><br><span class="line">  &#125;,</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;skeleton1 id="skeleton1" style="display:none"/&gt;</span></span><br><span class="line"><span class="string">      &lt;skeleton2 id="skeleton2" style="display:none"/&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li><li><p>添加骨架屏<br>添加 <code>components/skeleton/Skeleton1.vue</code> 和 <code>components/skeleton/Skeleton2.vue</code>，内容略</p></li><li><p>配置 skeleton router<br>配置router，方便访问骨架屏，便于调试，略</p></li><li><p>添加 <code>build/webpack.skeleton.conf.js</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><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">'use strict'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>)</span><br><span class="line"><span class="keyword">const</span> merge = <span class="built_in">require</span>(<span class="string">'webpack-merge'</span>)</span><br><span class="line"><span class="keyword">const</span> baseWebpackConfig = <span class="built_in">require</span>(<span class="string">'./webpack.base.conf'</span>)</span><br><span class="line"><span class="keyword">const</span> nodeExternals = <span class="built_in">require</span>(<span class="string">'webpack-node-externals'</span>)</span><br><span class="line"><span class="keyword">const</span> utils = <span class="built_in">require</span>(<span class="string">'./utils'</span>)</span><br><span class="line"><span class="keyword">const</span> config = <span class="built_in">require</span>(<span class="string">'../config'</span>)</span><br><span class="line"><span class="keyword">const</span> isProduction = process.env.NODE_ENV === <span class="string">'production'</span></span><br><span class="line"><span class="keyword">const</span> sourceMapEnabled = isProduction</span><br><span class="line">  ? config.build.productionSourceMap</span><br><span class="line">  : config.dev.cssSourceMap</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">resolve</span>(<span class="params">dir</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> path.join(__dirname, dir)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> skeletonWebpackConfig = merge(baseWebpackConfig, &#123;</span><br><span class="line">  target: <span class="string">'node'</span>,</span><br><span class="line">  devtool: <span class="literal">false</span>,</span><br><span class="line">  entry: &#123;</span><br><span class="line">    app: resolve(<span class="string">'../src/entry-skeleton.js'</span>)</span><br><span class="line">  &#125;,</span><br><span class="line">  output: <span class="built_in">Object</span>.assign(&#123;&#125;, baseWebpackConfig.output, &#123;</span><br><span class="line">    libraryTarget: <span class="string">'commonjs2'</span></span><br><span class="line">  &#125;),</span><br><span class="line">  externals: nodeExternals(&#123;</span><br><span class="line">    whitelist: <span class="regexp">/\.css$/</span></span><br><span class="line">  &#125;),</span><br><span class="line">  plugins: []</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// important: enable extract-text-webpack-plugin</span></span><br><span class="line">skeletonWebpackConfig.module.rules[<span class="number">0</span>].options.loaders = utils.cssLoaders(&#123;</span><br><span class="line">  sourceMap: sourceMapEnabled,</span><br><span class="line">  extract: <span class="literal">true</span></span><br><span class="line">&#125;),</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = skeletonWebpackConfig</span><br></pre></td></tr></table></figure></li><li><p>在 <code>build/webpack.dev.conf.js</code> 和 <code>build/webpack.prod.conf.js</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">const</span> SkeletonWebpackPlugin = <span class="built_in">require</span>(<span class="string">'vue-skeleton-webpack-plugin'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// plugins:</span></span><br><span class="line"><span class="keyword">new</span> SkeletonWebpackPlugin(&#123;</span><br><span class="line">  webpackConfig: <span class="built_in">require</span>(<span class="string">'./webpack.skeleton.conf'</span>),</span><br><span class="line">  quiet: <span class="literal">true</span>,</span><br><span class="line">  minimize: <span class="literal">true</span>,</span><br><span class="line">  router: &#123;</span><br><span class="line">    mode: <span class="string">'hash'</span>,</span><br><span class="line">    routes: [</span><br><span class="line">      &#123;</span><br><span class="line">        path: <span class="string">'/'</span>,</span><br><span class="line">        skeletonId: <span class="string">'skeleton1'</span></span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        path: <span class="string">'/user'</span>,</span><br><span class="line">        skeletonId: <span class="string">'skeleton2'</span></span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;),</span><br></pre></td></tr></table></figure></li><li><p>启动/编译</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">npm run dev</span><br><span class="line"></span><br><span class="line">npm run build</span><br></pre></td></tr></table></figure></li></ol><p>  此时，访问 / 可以看到skeleton1，访问 /user 可以看到skeleton2</p><h4 id="多页面生成多骨架屏"><a href="#多页面生成多骨架屏" class="headerlink" title="多页面生成多骨架屏"></a>多页面生成多骨架屏</h4><p>通过 <code>Puppeteer</code> 运行页面，自动生成骨架屏。</p><p>待补充…</p><h3 id="page-skeleton-webpack-plugin"><a href="#page-skeleton-webpack-plugin" class="headerlink" title="page-skeleton-webpack-plugin"></a>page-skeleton-webpack-plugin</h3><ol><li><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">npm i page-skeleton-webpack-plugin -D</span><br></pre></td></tr></table></figure><p>因为内部使用 <code>puppeteer</code>，安装比较慢，可能会失败。如果失败，采用 <code>cnpm</code> 来安装，先 <code>cnpm install</code>，再用 <code>cnpm</code> 安装该插件</p></li><li><p>引入插件 build/webpack.deve.conf.js</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">const</span> &#123; SkeletonPlugin &#125; = <span class="built_in">require</span>(<span class="string">'page-skeleton-webpack-plugin'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> SkeletonPlugin(&#123;</span><br><span class="line">  pathname: path.resolve(__dirname, <span class="string">'../shell'</span>), <span class="comment">// 开发环境中点击保存按钮生成的骨架屏代码的保存路径</span></span><br><span class="line">  staticDir: path.resolve(__dirname, <span class="string">'../dist'</span>), <span class="comment">// 打包时生成的骨架屏的静态资源文件(官方文档指导要和webpack打包输出目录一致)</span></span><br><span class="line">  routes: [<span class="string">'/'</span>] <span class="comment">// 需要生成骨架屏的路由(和项目中路由配置的path一致，history模式)</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li><li><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">npm run dev</span><br></pre></td></tr></table></figure><p>提示找不到 webpack-log</p></li><li><p>安装 webpack-log</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">npm i webpack-log -D</span><br></pre></td></tr></table></figure></li><li><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">npm run dev</span><br></pre></td></tr></table></figure></li><li><p>生成 <code>shell</code><br>在chrome控制台输入 <code>toggleBar</code>，在页面顶部会显示一个区域，点击它就会开启一个窗口 <code>http://****/preview.html</code></p></li><li><p>选择对应的route生成html，可以修改和保存</p></li><li><p>上面的一系列操作都是在开发环境中进行实践的，目的是为了生成骨架屏的代码。那现在就需要将骨架屏应用到生产环境中。</p></li><li><p>生成环境写入骨架屏配置，和 <code>dev</code> 环境一致</p></li><li><p>在根模板 <code>index.html</code> 中添加注释 <code>&lt;!-- shell --&gt;</code></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">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- shell --&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><blockquote><p><strong><em>这里需要注意</em></strong><br>webpack的html-webpack-plugin有一项关于压缩移除注释的配置，手脚架在生成项目的时侯，这个配置项默认设置为true，即移除模板中的注释。但是在骨架屏这里，这个<!-- shell -->注释是必须存在的。因此我们需要将这个压缩移除注释的配置项修改为false，即保留注释，否则在后面的项目打包部署后，骨架屏是不会生效的。</p><figure class="highlight plain"><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">new HtmlWebpackPlugin(&#123;</span><br><span class="line">  minify: &#123;</span><br><span class="line">    removeComments: false   // 压缩移除注释的配置项修改为false</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></blockquote></li><li><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">npm run build</span><br></pre></td></tr></table></figure></li><li><p>其他：</p><p><a href="https://github.com/ElemeFE/page-skeleton-webpack-plugin/blob/master/docs/i18n/zh_cn.md" target="_blank" rel="noopener">参数配置</a><br><a href="https://github.com/puppeteer/puppeteer/blob/main/src/common/DeviceDescriptors.ts" target="_blank" rel="noopener">设备列表</a></p></li></ol><h3 id="dps"><a href="#dps" class="headerlink" title="dps"></a>dps</h3><p>可以截取任何页面，生成骨架屏结构，根据已经完成UI的页面生成骨架屏。</p><ol><li><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">npm i draw-page-structure -g</span><br></pre></td></tr></table></figure></li><li><p>初始化，生成 <code>dps.config.js</code></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">dps init</span><br></pre></td></tr></table></figure><p>在 <code>config</code> 文件中可以设置想要生成的页面、<code>dom</code>、出口地址，以及一些个性化的配置</p></li><li><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">dps start</span><br></pre></td></tr></table></figure><p>完成之后就会在当前目录生成一个骨架屏，可以将生成的结构直接拷贝到我们需要的页面。</p></li></ol><blockquote><p><a href="https://segmentfault.com/a/1190000014832185" target="_blank" rel="noopener">ssr方案</a><br><a href="https://segmentfault.com/a/1190000020018638" target="_blank" rel="noopener">vue-skeleton-webpack-plugin插件方案</a><br><a href="https://github.com/lavas-project/vue-skeleton-webpack-plugin" target="_blank" rel="noopener">插件vue-skeleton-webpack-plugin</a><br><a href="https://github.com/ElemeFE/page-skeleton-webpack-plugin" target="_blank" rel="noopener">插件page-skeleton-webpack-plugin</a><br><a href="https://github.com/famanoder/dps" target="_blank" rel="noopener">插件dps</a><br><a href="https://github.com/Jocs/jocs.github.io/issues/22" target="_blank" rel="noopener">其他相关</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      vue-cli添加骨架屏，实现白屏时间优化
    
    </summary>
    
    
      <category term="Vue" scheme="http://pimichen.com/blog/tags/vue/"/>
    
  </entry>
  
  <entry>
    <title>如何让js变量变成可执行</title>
    <link href="http://pimichen.com/blog/javascript/%E5%A6%82%E4%BD%95%E8%AE%A9js%E5%8F%98%E9%87%8F%E5%8F%98%E6%88%90%E5%8F%AF%E6%89%A7%E8%A1%8C.html"/>
    <id>http://pimichen.com/blog/javascript/如何让js变量变成可执行.html</id>
    <published>2020-09-05T16:00:00.000Z</published>
    <updated>2020-09-05T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<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="function"><span class="keyword">function</span> <span class="title">func</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> a = <span class="number">1</span></span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'执行了..., 打印出：'</span> + a)</span><br><span class="line">&#125;</span><br><span class="line">func()</span><br></pre></td></tr></table></figure><p>通常我们想处理一段逻辑时，需要使用函数/方法，那么如何使用字符串来执行一个方法呢？？？</p><p>可以巧妙的使用 <code>Object.defineProperty()</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="literal">false</span></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(<span class="built_in">window</span>, <span class="string">'toggle'</span>, &#123;</span><br><span class="line">  get() &#123;</span><br><span class="line">    a = !a</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'a:'</span>, a)</span><br><span class="line">    <span class="keyword">return</span> <span class="string">'🐶'</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="comment">// a: true</span></span><br><span class="line"><span class="comment">// 🐶</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 执行偶数次</span></span><br><span class="line"><span class="comment">// a: false</span></span><br><span class="line"><span class="comment">// 🐶</span></span><br></pre></td></tr></table></figure><p>这样就可以通过直接调用 <code>toggle</code>，来实现我们平常的 <code>toggle()</code>。在一些开发者调试工具中，开发人员通过向控制台输入变量达到切换开关的目的，这样比执行函数更叫方便、更加巧妙。</p>]]></content>
    
    <summary type="html">
    
      如何让js变量变成可执行，如同函数执行一般
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>创建脚手架工具</title>
    <link href="http://pimichen.com/blog/tools/%E5%88%9B%E5%BB%BA%E8%84%9A%E6%89%8B%E6%9E%B6%E5%B7%A5%E5%85%B7.html"/>
    <id>http://pimichen.com/blog/tools/创建脚手架工具.html</id>
    <published>2020-07-01T16:00:00.000Z</published>
    <updated>2020-07-01T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="引入"><a href="#引入" class="headerlink" title="引入"></a>引入</h2><p>我们在初始vue-cli的时候，经常使用如下的命令<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">vue init webpack <span class="built_in">test</span></span><br></pre></td></tr></table></figure></p><p>那么是怎么实现的呢？如何自己搭建一个cli工具。</p><h2 id="搭建具体流程"><a href="#搭建具体流程" class="headerlink" title="搭建具体流程"></a>搭建具体流程</h2><ul><li>新建一个 <code>***-cli</code> 的文件夹，如 <code>cpm-cli</code></li><li>npm init 初始化一个package.json</li><li><p>编写自动化下载的脚本</p><ol><li><p>使用 gitlab group 或 github organization 存储脚手架项目</p></li><li><p>使用 gitlab api 或 github api 读取项目列表<br>以 github 为例：<code>https://api.github.com/orgs/${orgName}/repos</code></p></li><li><p>使用交互式命令供用户选择项目</p></li><li><p>使用 gitlab api 或 github api 下载脚手架<br>以 github 为例：<code>github:${orgName}/${project}</code></p></li><li><p>重写package.json等文件</p></li></ol></li><li><p>npm publish</p></li></ul><h2 id="npm包"><a href="#npm包" class="headerlink" title="npm包"></a>npm包</h2><ul><li>commander：解析命令行</li><li>download-git-repo：下载git仓库</li><li>inquirer：交互式命令</li><li>axios：调用github接口</li><li>fs：读取和修改文件</li><li>ora：控制台输出loading</li><li>chalk：控制台输出不同颜色的文案</li><li>symbols：控制台console前面的类型</li></ul><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ul><li>入口文件顶部：#!/usr/bin/env node</li><li>package.json添加：”bin”: { “cpm-cli”: “index.js” }</li><li>安装依赖包时使用-S安装，不要使用-D安装</li><li>调用program.parse(process.argv)时需要单独写，不要和其他的一起链式调用</li><li>download脚手架偶尔会报错“被拒绝连接connect ECONNREFUSED”，稍后重试即可</li><li>需要配置github ssh key，否则无法download</li></ul><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p><a href="https://github.com/cpm828/cpm-cli" target="_blank" rel="noopener">访问github</a><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><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/usr/bin/env node</span></span><br><span class="line"><span class="meta">'use strict'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * cli脚手架搭建参考：</span></span><br><span class="line"><span class="comment"> *    https://developer.github.com/v3/</span></span><br><span class="line"><span class="comment"> *    https://www.jianshu.com/p/edeff714e8a3</span></span><br><span class="line"><span class="comment"> *    https://blog.csdn.net/weixin_38080573/article/details/97897767</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"> *    入口文件顶部添加：#!/usr/bin/env node</span></span><br><span class="line"><span class="comment"> *    package.josn添加："bin": &#123; "cpm-cli": "index.js" &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> program = <span class="built_in">require</span>(<span class="string">'commander'</span>);</span><br><span class="line"><span class="keyword">const</span> download = <span class="built_in">require</span>(<span class="string">'download-git-repo'</span>);</span><br><span class="line"><span class="keyword">const</span> inquirer = <span class="built_in">require</span>(<span class="string">'inquirer'</span>);</span><br><span class="line"><span class="keyword">const</span> axios = <span class="built_in">require</span>(<span class="string">'axios'</span>);</span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>);</span><br><span class="line"><span class="keyword">const</span> ora = <span class="built_in">require</span>(<span class="string">'ora'</span>);</span><br><span class="line"><span class="keyword">const</span> chalk = <span class="built_in">require</span>(<span class="string">'chalk'</span>); <span class="comment">// green/success、red/error、yellow/tip</span></span><br><span class="line"><span class="keyword">const</span> symbols = <span class="built_in">require</span>(<span class="string">'log-symbols'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// config</span></span><br><span class="line"><span class="keyword">const</span> orgName = <span class="string">'cpm-cli'</span>; <span class="comment">// github organization name</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 抓取github api获取脚手架列表</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getOrgTemplateList</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> spinner = ora(chalk.yellow(<span class="string">'Request template list ...'</span>));</span><br><span class="line">    spinner.start();</span><br><span class="line">    axios</span><br><span class="line">      .get(<span class="string">`https://api.github.com/orgs/<span class="subst">$&#123;orgName&#125;</span>/repos`</span>)</span><br><span class="line">      .then(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (res.data &amp;&amp; res.data.length) &#123;</span><br><span class="line">          <span class="keyword">const</span> list = res.data.map(<span class="function"><span class="params">item</span> =&gt;</span> item.full_name.replace(<span class="string">`<span class="subst">$&#123;orgName&#125;</span>/`</span>, <span class="string">''</span>));</span><br><span class="line">          spinner.succeed();</span><br><span class="line">          resolve(list);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          spinner.fail();</span><br><span class="line">          reject();</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">      .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">        spinner.fail();</span><br><span class="line">        reject(err);</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="comment">/**</span></span><br><span class="line"><span class="comment"> * 交互式命令获取用户输入和选择</span></span><br><span class="line"><span class="comment"> * @param &#123;Array&#125; list 脚手架列表</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">showInquirer</span> (<span class="params">list</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    inquirer</span><br><span class="line">      .prompt([</span><br><span class="line">        &#123;</span><br><span class="line">          type: <span class="string">'input'</span>,</span><br><span class="line">          message: <span class="string">'please input package.json name'</span>,</span><br><span class="line">          name: <span class="string">'name'</span>,</span><br><span class="line">          <span class="keyword">default</span>: <span class="string">'demo'</span></span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">          type: <span class="string">'input'</span>,</span><br><span class="line">          message: <span class="string">'please input package.json description'</span>,</span><br><span class="line">          name: <span class="string">'description'</span>,</span><br><span class="line">          <span class="keyword">default</span>: <span class="string">'a demo project'</span></span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">          type: <span class="string">'input'</span>,</span><br><span class="line">          message: <span class="string">'please input package.json author'</span>,</span><br><span class="line">          name: <span class="string">'author'</span>,</span><br><span class="line">          <span class="keyword">default</span>: <span class="string">'chenpengmin'</span></span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">          type: <span class="string">'list'</span>,</span><br><span class="line">          message: <span class="string">'please choice template'</span>,</span><br><span class="line">          name: <span class="string">'template'</span>,</span><br><span class="line">          choices: list</span><br><span class="line">        &#125;</span><br><span class="line">      ])</span><br><span class="line">      .then(<span class="function">(<span class="params">answers</span>) =&gt;</span> &#123;</span><br><span class="line">        resolve(answers);</span><br><span class="line">      &#125;)</span><br><span class="line">      .catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">        reject(err);</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="comment">/**</span></span><br><span class="line"><span class="comment"> * 下载脚手架</span></span><br><span class="line"><span class="comment"> * @param &#123;Object&#125; answers </span></span><br><span class="line"><span class="comment"> * @param &#123;String&#125; projectName</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">downloadTemp</span> (<span class="params">answers, projectName</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> spinner = ora(chalk.yellow(<span class="string">`Downloading <span class="subst">$&#123;answers.template&#125;</span> template ...`</span>));</span><br><span class="line">    spinner.start();</span><br><span class="line">    download(<span class="string">`github:<span class="subst">$&#123;orgName&#125;</span>/<span class="subst">$&#123;answers.template&#125;</span>`</span>, projectName, &#123; <span class="attr">clone</span>: <span class="literal">true</span> &#125;, (err) =&gt; &#123;</span><br><span class="line">      <span class="keyword">if</span> (err) &#123;</span><br><span class="line">        spinner.fail();</span><br><span class="line">        reject(err);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      spinner.succeed();</span><br><span class="line">      resolve();</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="comment">/**</span></span><br><span class="line"><span class="comment"> * 重写package.json，修改name、description、author等参数</span></span><br><span class="line"><span class="comment"> * @param &#123;Object&#125; answers </span></span><br><span class="line"><span class="comment"> * @param &#123;String&#125; projectName </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">rewritePackageJson</span> (<span class="params">answers, projectName</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; name, description, author &#125; = answers;</span><br><span class="line">  <span class="keyword">const</span> packagePath = <span class="string">`<span class="subst">$&#123;projectName&#125;</span>/package.json`</span>;</span><br><span class="line">  <span class="keyword">if</span> (fs.existsSync(packagePath)) &#123;</span><br><span class="line">    <span class="keyword">const</span> packageJson = fs.readFileSync(packagePath);</span><br><span class="line">    <span class="keyword">const</span> packageResult = <span class="built_in">JSON</span>.stringify(</span><br><span class="line">      <span class="built_in">Object</span>.assign(</span><br><span class="line">        &#123;&#125;,</span><br><span class="line">        <span class="built_in">JSON</span>.parse(packageJson),</span><br><span class="line">        &#123;</span><br><span class="line">          name,</span><br><span class="line">          description,</span><br><span class="line">          author</span><br><span class="line">        &#125;</span><br><span class="line">      ),</span><br><span class="line">      <span class="literal">null</span>,</span><br><span class="line">      <span class="string">'\t'</span></span><br><span class="line">    );</span><br><span class="line">    fs.writeFileSync(packagePath, packageResult);</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="comment"> * 主方法</span></span><br><span class="line"><span class="comment"> * @param &#123;String&#125; projectName</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">main</span> (<span class="params">projectName</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="comment">// 第一步：读取github organization列表</span></span><br><span class="line">    <span class="keyword">const</span> list = <span class="keyword">await</span> getOrgTemplateList();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 第二步：交互式命令获取用户选择</span></span><br><span class="line">    <span class="keyword">const</span> answers = <span class="keyword">await</span> showInquirer(list);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 第三步：下载脚手架</span></span><br><span class="line">    <span class="keyword">await</span> downloadTemp(answers, projectName);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 第四步：重写package.json</span></span><br><span class="line">    rewritePackageJson(answers, projectName);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">console</span>.log(symbols.success, chalk.green(<span class="string">`project <span class="subst">$&#123;projectName&#125;</span> was created successfully`</span>));</span><br><span class="line">  &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(symbols.error, chalk.red(err || <span class="string">'something was wrong'</span>));</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">program</span><br><span class="line">  .version(<span class="built_in">require</span>(<span class="string">'./package.json'</span>).version)</span><br><span class="line">  .command(<span class="string">'init &lt;projectName&gt;'</span>)</span><br><span class="line">  .action(<span class="function">(<span class="params">projectName</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (fs.existsSync(projectName)) &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(symbols.error, chalk.red(<span class="string">`project <span class="subst">$&#123;projectName&#125;</span> already exist`</span>));</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    main(projectName);</span><br><span class="line">  &#125;)</span><br><span class="line">program.parse(process.argv);</span><br></pre></td></tr></table></figure></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><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"name"</span>: <span class="string">"cpm-cli"</span>,</span><br><span class="line">  <span class="attr">"version"</span>: <span class="string">"0.1.7"</span>,</span><br><span class="line">  <span class="attr">"description"</span>: <span class="string">"cpm-cli"</span>,</span><br><span class="line">  <span class="attr">"main"</span>: <span class="string">"index.js"</span>,</span><br><span class="line">  <span class="attr">"scripts"</span>: &#123;</span><br><span class="line">    <span class="attr">"test"</span>: <span class="string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">"author"</span>: <span class="string">"chenpengmin"</span>,</span><br><span class="line">  <span class="attr">"homepage"</span>: <span class="string">"https://github.com/cpm828/cpm-cli"</span>,</span><br><span class="line">  <span class="attr">"keywords"</span>: [</span><br><span class="line">    <span class="string">"cli"</span>,</span><br><span class="line">    <span class="string">"cpm"</span>,</span><br><span class="line">    <span class="string">"cpm-cli"</span></span><br><span class="line">  ],</span><br><span class="line">  <span class="attr">"license"</span>: <span class="string">"ISC"</span>,</span><br><span class="line">  <span class="attr">"bin"</span>: &#123;</span><br><span class="line">    <span class="attr">"cpm-cli"</span>: <span class="string">"index.js"</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">"dependencies"</span>: &#123;</span><br><span class="line">    <span class="attr">"axios"</span>: <span class="string">"^0.19.2"</span>,</span><br><span class="line">    <span class="attr">"chalk"</span>: <span class="string">"^4.1.0"</span>,</span><br><span class="line">    <span class="attr">"commander"</span>: <span class="string">"^5.1.0"</span>,</span><br><span class="line">    <span class="attr">"download-git-repo"</span>: <span class="string">"^3.0.2"</span>,</span><br><span class="line">    <span class="attr">"fs"</span>: <span class="string">"0.0.1-security"</span>,</span><br><span class="line">    <span class="attr">"inquirer"</span>: <span class="string">"^7.2.0"</span>,</span><br><span class="line">    <span class="attr">"log-symbols"</span>: <span class="string">"^4.0.0"</span>,</span><br><span class="line">    <span class="attr">"ora"</span>: <span class="string">"^4.0.4"</span>,</span><br><span class="line">    <span class="attr">"shell"</span>: <span class="string">"^0.5.0"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      创建脚手架工具
    
    </summary>
    
    
      <category term="Tools" scheme="http://pimichen.com/blog/tags/tools/"/>
    
  </entry>
  
  <entry>
    <title>ES6 Proxy方法</title>
    <link href="http://pimichen.com/blog/es6/es6-proxy.html"/>
    <id>http://pimichen.com/blog/es6/es6-proxy.html</id>
    <published>2020-06-28T16:00:00.000Z</published>
    <updated>2020-06-28T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="什么是Proxy"><a href="#什么是Proxy" class="headerlink" title="什么是Proxy?"></a>什么是Proxy?</h2><p><code>Proxy</code> 对象用于定义基本操作的自定义行为（如属性查找、赋值、枚举、函数调用等）</p><p>其实就是在对目标对象操作之前提供拦截，可以对外界的操作进行过滤和改写，修改某些操作的默认行为，这样我们可以不直接操作对象本身，而是通过操作对象的<strong>代理对象</strong>来间接操作对象，达到预期目的。</p><p>看个例子：<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">  a: <span class="number">1</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> proxyObj = <span class="keyword">new</span> <span class="built_in">Proxy</span>(obj, &#123;</span><br><span class="line">  get: <span class="function"><span class="keyword">function</span> (<span class="params">target, prop</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> prop <span class="keyword">in</span> target ? target[prop] : <span class="number">0</span></span><br><span class="line">  &#125;,</span><br><span class="line">  set: <span class="function"><span class="keyword">function</span> (<span class="params">target, prop, value</span>) </span>&#123;</span><br><span class="line">    target[prop] = <span class="number">888</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">// get</span></span><br><span class="line"><span class="built_in">console</span>.log(proxyObj.a) <span class="comment">// 1</span></span><br><span class="line"><span class="built_in">console</span>.log(proxyObj.b) <span class="comment">// 0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// set</span></span><br><span class="line">proxyObj.a = <span class="number">666</span></span><br><span class="line"><span class="built_in">console</span>.log(proxyObj.a) <span class="comment">// 888</span></span><br></pre></td></tr></table></figure></p><p>发现经过 <code>Proxy</code> 构造器中转一下之后，并没有按照我们预期的表现，<code>Proxy</code>在读取和设置之前都做了一次拦截。</p><h2 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</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">let</span> proxy = <span class="keyword">new</span> <span class="built_in">Proxy</span>(target, handler)</span><br></pre></td></tr></table></figure><p>参数 <code>target</code> 是 <code>Proxy</code> 包装的目标对象（可以是任何类型的对象，包括数组、函数、甚至另一个代理），参数 <code>handler</code> 也是一个对象，其属性是执行一个操作时定义代理行为的函数。<code>handler</code> 可以是空对象 <code>{}</code>，不可以设置为 <code>null</code>，否则会排除错误。</p><p>要想 <code>Proxy</code> 起作用，就不能去操作原来对象的属性，必须针对的是 <code>Proxy</code> 实例，否则达不到预期效果。</p><p>继续使用前面的例子：<br><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="built_in">console</span>.log(proxyObj.b) <span class="comment">// 0</span></span><br><span class="line"><span class="built_in">console</span>.log(obj.b) <span class="comment">// undefined</span></span><br></pre></td></tr></table></figure></p><p>对于 <code>set</code> 方法，在作用于 <code>proxy</code> 实例的同时也会作用于target上。<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></pre></td><td class="code"><pre><span class="line">proxyObj.a === <span class="number">666</span></span><br><span class="line"><span class="built_in">console</span>.log(proxyObj.a) <span class="comment">// 888</span></span><br><span class="line"><span class="built_in">console</span>.log(obj.a) <span class="comment">// 888</span></span><br></pre></td></tr></table></figure></p><h2 id="API"><a href="#API" class="headerlink" title="API"></a>API</h2><h3 id="get-target-key-receiver"><a href="#get-target-key-receiver" class="headerlink" title="get(target, key, receiver)"></a>get(target, key, receiver)</h3><p><code>get</code> 方法用于拦截对象的读取属性操作。<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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * target: 目标对象</span></span><br><span class="line"><span class="comment"> * key: 目标属性</span></span><br><span class="line"><span class="comment"> * receiver: Proxy或继承Proxy的对象</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">get(target, key, receiver)</span><br></pre></td></tr></table></figure></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">var</span> obj = &#123;<span class="attr">name</span>: <span class="string">'Lucy'</span>&#125;</span><br><span class="line"><span class="keyword">var</span> proxy = <span class="keyword">new</span> <span class="built_in">Proxy</span>(obj, &#123;</span><br><span class="line">  get: <span class="function"><span class="keyword">function</span> (<span class="params">target, key, receiver</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> key === <span class="string">'name'</span> ? <span class="string">`Hello <span class="subst">$&#123;target[key]&#125;</span>`</span> : target[key]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(p.name) <span class="comment">// Hello Lucy</span></span><br></pre></td></tr></table></figure><p><strong><em>注意</em></strong>：如果一个属性不可配置（configurable）且不可写（writable），则 <code>Proxy</code> 不能修改该属性。<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = <span class="built_in">Object</span>.defineProperties(&#123;&#125;, &#123;</span><br><span class="line">  name: &#123;</span><br><span class="line">    value: <span class="string">'Lucy'</span>,</span><br><span class="line">    configurable: <span class="literal">false</span>,</span><br><span class="line">    writable: <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">var</span> proxy = <span class="keyword">new</span> <span class="built_in">Proxy</span>(obj, &#123;</span><br><span class="line">  get: <span class="function"><span class="keyword">function</span> (<span class="params">target, key, receiver</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> key === <span class="string">'name'</span> ? <span class="string">`Hello <span class="subst">$&#123;target[key]&#125;</span>`</span> : target[key]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(proxy.name) <span class="comment">// 报错</span></span><br></pre></td></tr></table></figure></p><h3 id="set-target-key-value-receiver"><a href="#set-target-key-value-receiver" class="headerlink" title="set(target, key, value, receiver)"></a>set(target, key, value, receiver)</h3><p><code>set</code> 方法用于拦截对象的赋值操作。<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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * target: 目标对象</span></span><br><span class="line"><span class="comment"> * key: 目标属性</span></span><br><span class="line"><span class="comment"> * value: 目标属性值</span></span><br><span class="line"><span class="comment"> * receiver: Proxy或继承Proxy的对象</span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line">set(target, key, value, receiver)</span><br></pre></td></tr></table></figure></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">var</span> obj = &#123;<span class="attr">age</span>: <span class="number">18</span>&#125;</span><br><span class="line"><span class="keyword">var</span> proxy = <span class="keyword">new</span> <span class="built_in">Proxy</span>(obj, &#123;</span><br><span class="line">  set: <span class="function"><span class="keyword">function</span>(<span class="params">target, key, value, receiver</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(receiver)</span><br><span class="line">    target[key] = key === <span class="string">'age'</span> ? <span class="built_in">Math</span>.min(value, <span class="number">100</span>) : value</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">proxy.age = <span class="number">101</span></span><br><span class="line"><span class="built_in">console</span>.log(proxy.age) <span class="comment">// 100</span></span><br><span class="line"><span class="built_in">console</span>.log(obj.age) <span class="comment">// 100</span></span><br></pre></td></tr></table></figure><p><strong><em>注意</em></strong>：<code>Proxy</code> 不能进行深度代理，如：<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;<span class="attr">borth</span>: &#123;<span class="attr">year</span>: <span class="number">2000</span>, <span class="attr">month</span>: <span class="number">6</span>&#125;&#125;</span><br><span class="line"><span class="keyword">var</span> proxy = <span class="keyword">new</span> <span class="built_in">Proxy</span>(obj, &#123;</span><br><span class="line">  set: <span class="function"><span class="keyword">function</span>(<span class="params">target, key, value, receiver</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(receiver)</span><br><span class="line">    target[key] = value</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">proxy.borth.month = <span class="number">7</span></span><br></pre></td></tr></table></figure></p><h3 id="has-target-key"><a href="#has-target-key" class="headerlink" title="has(target, key)"></a>has(target, key)</h3><h3 id="deleteProperty-target-key"><a href="#deleteProperty-target-key" class="headerlink" title="deleteProperty(target, key)"></a>deleteProperty(target, key)</h3><h3 id="ownKeys-target"><a href="#ownKeys-target" class="headerlink" title="ownKeys(target)"></a>ownKeys(target)</h3><blockquote><p>参考：<a href="https://segmentfault.com/a/1190000019675719?utm_source=tag-newest" target="_blank" rel="noopener">segmentfault JS基础——Proxy</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      ES6 Proxy方法
    
    </summary>
    
    
      <category term="ES6" scheme="http://pimichen.com/blog/tags/es6/"/>
    
  </entry>
  
  <entry>
    <title>js对象乱序现象</title>
    <link href="http://pimichen.com/blog/javascript/js%E5%AF%B9%E8%B1%A1%E4%B9%B1%E5%BA%8F%E7%8E%B0%E8%B1%A1.html"/>
    <id>http://pimichen.com/blog/javascript/js对象乱序现象.html</id>
    <published>2020-06-28T16:00:00.000Z</published>
    <updated>2020-06-28T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>当我们使用 <code>for...in</code> 遍历一个Object对象时，打印的结构是否按key的顺序打印出来呢？<br>答案是：不一定</p><p>如case1：<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">  <span class="string">'-1'</span>: <span class="string">'全部'</span>,</span><br><span class="line">  <span class="string">'0'</span> : <span class="string">'正常'</span>,</span><br><span class="line">  <span class="string">'1'</span> : <span class="string">'失效'</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> key <span class="keyword">in</span> obj) &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(key, obj[key]);</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">'0' 正常</span></span><br><span class="line"><span class="comment">'1' 失效</span></span><br><span class="line"><span class="comment">'-1' 全部</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure></p><h2 id="解惑"><a href="#解惑" class="headerlink" title="解惑"></a>解惑</h2><p>Object的key的排序规则到底是什么样的呢？答案是：<br>如果key是 <code>0</code>、<code>正整数</code>或<code>字符串0</code>、<code>字符串正整数</code>，则安排从小到大排序，如果有其他的数据，安排创建顺序排列。<br>如case2：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">  <span class="string">'a'</span>: <span class="number">1</span>,</span><br><span class="line">  <span class="string">'你'</span> : <span class="number">2</span>,</span><br><span class="line">  <span class="string">'1'</span> : <span class="number">3</span>,</span><br><span class="line">  <span class="string">'2.1'</span> : <span class="number">3</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> key <span class="keyword">in</span> obj) &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(key, obj[key]);</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">1 3</span></span><br><span class="line"><span class="comment">a 1</span></span><br><span class="line"><span class="comment">你 2</span></span><br><span class="line"><span class="comment">2.1 3</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h2 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h2><p>对于case1，如何让key顺序输出呢？可以先将key换成非整数类型的字符串，输出的时候再还原。<br>改造case1:<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">  <span class="string">'-1.'</span>: <span class="string">'全部'</span>,</span><br><span class="line">  <span class="string">'0.'</span> : <span class="string">'正常'</span>,</span><br><span class="line">  <span class="string">'1.'</span> : <span class="string">'失效'</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> key <span class="keyword">in</span> obj) &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(~~key, obj[key]);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">'-1' 全部</span></span><br><span class="line"><span class="comment">'0' 正常</span></span><br><span class="line"><span class="comment">'1' 失效</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure></p><p>但如果是case2各种数据类型混合的情况，就不能使用~~了<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">  <span class="string">'.a'</span>: <span class="number">1</span>,</span><br><span class="line">  <span class="string">'.你'</span> : <span class="number">2</span>,</span><br><span class="line">  <span class="string">'.1'</span> : <span class="number">3</span>,</span><br><span class="line">  <span class="string">'.2.1'</span> : <span class="number">3</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> key <span class="keyword">in</span> obj) &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(key.substring(<span class="number">1</span>), obj[key]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      js对象乱序现象
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>js数据结构--链表</title>
    <link href="http://pimichen.com/blog/javascript/js%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84--%E9%93%BE%E8%A1%A8.html"/>
    <id>http://pimichen.com/blog/javascript/js数据结构--链表.html</id>
    <published>2020-06-27T16:00:00.000Z</published>
    <updated>2020-06-27T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>前端说的<a href="/blog/javascript/js数据结构--栈.html">栈</a>、<a href="/blog/javascript/js数据结构--队列.html">队列</a>，它们都是<a href="/blog/javascript/js数据结构--列表.html">列表</a>的一种，底层的数据结构都是数组。</p><p>但是数组并不总是最佳的数据结构，索引引入链表结构：</p><h2 id="链表（LinkedList）"><a href="#链表（LinkedList）" class="headerlink" title="链表（LinkedList）"></a>链表（LinkedList）</h2><h3 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h3><p>链表的出现是为了解决数组增删的操作，在js中，虽然存在如下方法：</p><ul><li>尾部添加 <code>push</code></li><li>尾部删除 <code>pop</code></li><li>头部添加 <code>unshift</code></li><li>头部删除 <code>shift</code></li><li>任意位置添加删除 <code>splice</code></li></ul><p>但是与其他语言相比，效率会比较低，所以考虑使用链表（<code>Linked-list</code>）来替换它，链表几乎可以在任何可以使用一位数组的情况中。</p><p>链表包含：</p><ul><li>单向链表</li><li>双向链表</li><li>单向循环列表</li><li>双向循环列表</li></ul><h3 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h3><p>链表是一组节点组成的集合，每个节点都使用一个对象的引用来指向它的后一个节点。指向另一个节点的引用称作为链。<br><img src="../images/javascript/js_linked_list1.png" title="链表结构图"><br>其中，data保存数据，next保存着下一个链表的引用，链表的尾元素指向null，表示结束位置。</p><p>由于链表的起始点确定比较麻烦，因此在链表的最前面添加一个特殊的节点，成为头节点，表示链表的头部，如：<br><img src="../images/javascript/js_linked_list2.png" title="有头节点的链表"></p><p>用我们常见的数据结构，大致是这样：<br><img src="../images/javascript/js_linked_list3.png" title="链表数据结构"></p><h3 id="单向链表"><a href="#单向链表" class="headerlink" title="单向链表"></a>单向链表</h3><p>设计链表包含两个类，一个是 <code>Node</code> 类用来表示节点，另一个是 <code>LinkList</code> 类提供增删等操作。</p><ul><li><p>Node类</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="function"><span class="keyword">function</span> <span class="title">Node</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.el = el                    <span class="comment">// 当前节点元素</span></span><br><span class="line">  <span class="keyword">this</span>.next = <span class="literal">null</span>                <span class="comment">// 下一个节点的链接</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>LinkList类</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="function"><span class="keyword">function</span> <span class="title">LinkList</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.head = <span class="keyword">new</span> Node(<span class="string">'head'</span>)     <span class="comment">// 头结点</span></span><br><span class="line">  <span class="keyword">this</span>.find = find                 <span class="comment">// 查找结点</span></span><br><span class="line">  <span class="keyword">this</span>.findPrev = findPrev         <span class="comment">// 查找前一个结点</span></span><br><span class="line">  <span class="keyword">this</span>.insertAfter = insertAfter   <span class="comment">// 在某个节点后插入节点（结合find）</span></span><br><span class="line">  <span class="keyword">this</span>.insertBefore = insertBefore <span class="comment">// 在某个节点后插入节点（结合findPrev）</span></span><br><span class="line">  <span class="keyword">this</span>.remove = remove             <span class="comment">// 删除结点（结合findPrev）</span></span><br><span class="line">  <span class="keyword">this</span>.display = display           <span class="comment">// 显示链表</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><p>下面挨个实现这些方法：</p><h4 id="find-查找节点"><a href="#find-查找节点" class="headerlink" title="find 查找节点"></a>find 查找节点</h4><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="function"><span class="keyword">function</span> <span class="title">find</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.head <span class="comment">// 从链表头部开始扫描</span></span><br><span class="line">  <span class="keyword">while</span>(curNode.el !== el) &#123;</span><br><span class="line">    curNode = curNode.next</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> curNode</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="findPrev-查找前一个结点"><a href="#findPrev-查找前一个结点" class="headerlink" title="findPrev 查找前一个结点"></a>findPrev 查找前一个结点</h4><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="function"><span class="keyword">function</span> <span class="title">findPrev</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> prevNode = <span class="keyword">this</span>.head <span class="comment">// 从链表头部开始扫描</span></span><br><span class="line">  <span class="keyword">while</span>(prevNode.next !== <span class="literal">null</span> &amp;&amp; prevNode.next.el !== el) &#123;</span><br><span class="line">    prevNode = prevNode.next</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> prevNode</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="insertAfter-在某个节点后插入节点"><a href="#insertAfter-在某个节点后插入节点" class="headerlink" title="insertAfter 在某个节点后插入节点"></a>insertAfter 在某个节点后插入节点</h4><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="function"><span class="keyword">function</span> <span class="title">insertAfter</span>(<span class="params">newEl, el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> newNode = <span class="keyword">new</span> Node(newEl)</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.find(el)</span><br><span class="line">  newNode.next = curNode.next</span><br><span class="line">  curNode.next = newNode</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="insertBefore-在某个节点前插入节点"><a href="#insertBefore-在某个节点前插入节点" class="headerlink" title="insertBefore 在某个节点前插入节点"></a>insertBefore 在某个节点前插入节点</h4><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="function"><span class="keyword">function</span> <span class="title">insertBefore</span>(<span class="params">newEl, el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> newNode = <span class="keyword">new</span> Node(newEl)</span><br><span class="line">  <span class="keyword">var</span> prevNode = <span class="keyword">this</span>.findPrev(el)</span><br><span class="line">  newNode.next = prevNode.next</span><br><span class="line">  prevNode.next = newNode</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="remove-删除节点"><a href="#remove-删除节点" class="headerlink" title="remove 删除节点"></a>remove 删除节点</h4><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="function"><span class="keyword">function</span> <span class="title">remove</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> prevNode = <span class="keyword">this</span>.findPrev(el)</span><br><span class="line">  <span class="keyword">if</span> (prev !== <span class="literal">null</span>) &#123;</span><br><span class="line">    prev.next = prev.next.next</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="display-显示链表"><a href="#display-显示链表" class="headerlink" title="display 显示链表"></a>display 显示链表</h4><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="function"><span class="keyword">function</span> <span class="title">display</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.head <span class="comment">// 从链表头部开始扫描</span></span><br><span class="line">  <span class="keyword">while</span>(curNode !== <span class="literal">null</span>) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(curNode)</span><br><span class="line">    curNode = curNode.next</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>全部代码如下：<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><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Node</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.el = el                    <span class="comment">// 当前节点元素</span></span><br><span class="line">  <span class="keyword">this</span>.next = <span class="literal">null</span>                <span class="comment">// 下一个节点的链接</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">LinkList</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.head = <span class="keyword">new</span> Node(<span class="string">'head'</span>)     <span class="comment">// 头结点</span></span><br><span class="line">  <span class="keyword">this</span>.find = find                 <span class="comment">// 查找结点</span></span><br><span class="line">  <span class="keyword">this</span>.findPrev = findPrev         <span class="comment">// 查找前一个结点</span></span><br><span class="line">  <span class="keyword">this</span>.insertAfter = insertAfter   <span class="comment">// 在某个节点后插入节点（结合find）</span></span><br><span class="line">  <span class="keyword">this</span>.insertBefore = insertBefore <span class="comment">// 在某个节点后插入节点（结合findPrev）</span></span><br><span class="line">  <span class="keyword">this</span>.remove = remove             <span class="comment">// 删除结点（结合findPrev）</span></span><br><span class="line">  <span class="keyword">this</span>.display = display           <span class="comment">// 显示链表</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 查找节点</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">find</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.head <span class="comment">// 从链表头部开始扫描</span></span><br><span class="line">  <span class="keyword">while</span>(curNode.el !== el) &#123;</span><br><span class="line">    curNode = curNode.next</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> curNode</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="function"><span class="keyword">function</span> <span class="title">findPrev</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> prevNode = <span class="keyword">this</span>.head <span class="comment">// 从链表头部开始扫描</span></span><br><span class="line">  <span class="keyword">while</span>(prevNode.next !== <span class="literal">null</span> &amp;&amp; prevNode.next.el !== el) &#123;</span><br><span class="line">    prevNode = prevNode.next</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> prevNode</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="function"><span class="keyword">function</span> <span class="title">insertAfter</span>(<span class="params">newEl, el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> newNode = <span class="keyword">new</span> Node(newEl)</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.find(el)</span><br><span class="line">  newNode.next = curNode.next</span><br><span class="line">  curNode.next = newNode</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="function"><span class="keyword">function</span> <span class="title">insertBefore</span>(<span class="params">newEl, el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> newNode = <span class="keyword">new</span> Node(newEl)</span><br><span class="line">  <span class="keyword">var</span> prevNode = <span class="keyword">this</span>.findPrev(el)</span><br><span class="line">  newNode.next = prevNode.next</span><br><span class="line">  prevNode.next = newNode</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="function"><span class="keyword">function</span> <span class="title">remove</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> prevNode = <span class="keyword">this</span>.findPrev(el)</span><br><span class="line">  <span class="keyword">if</span> (prevNode !== <span class="literal">null</span>) &#123;</span><br><span class="line">    prevNode.next = prevNode.next.next</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="function"><span class="keyword">function</span> <span class="title">display</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.head <span class="comment">// 从链表头部开始扫描</span></span><br><span class="line">  <span class="keyword">while</span>(curNode !== <span class="literal">null</span>) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(curNode)</span><br><span class="line">    curNode = curNode.next</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>测试：<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><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> nums = <span class="keyword">new</span> LinkList()</span><br><span class="line"><span class="comment">// nums:</span></span><br><span class="line"><span class="comment">/* &#123;</span></span><br><span class="line"><span class="comment">  ...,</span></span><br><span class="line"><span class="comment">  head: &#123;</span></span><br><span class="line"><span class="comment">    el: 'head',</span></span><br><span class="line"><span class="comment">    next: null</span></span><br><span class="line"><span class="comment">  &#125;,</span></span><br><span class="line"><span class="comment">  ...</span></span><br><span class="line"><span class="comment">&#125; */</span></span><br><span class="line"></span><br><span class="line">nums.insertAfter(<span class="string">'1'</span>, <span class="string">'head'</span>) <span class="comment">// 在head头节点之后插入节点1</span></span><br><span class="line"><span class="comment">// nums:</span></span><br><span class="line"><span class="comment">/* &#123;</span></span><br><span class="line"><span class="comment">  ...,</span></span><br><span class="line"><span class="comment">  head: &#123;</span></span><br><span class="line"><span class="comment">    el: 'head',</span></span><br><span class="line"><span class="comment">    next: &#123;</span></span><br><span class="line"><span class="comment">      el: "1",</span></span><br><span class="line"><span class="comment">      next: null</span></span><br><span class="line"><span class="comment">    &#125;</span></span><br><span class="line"><span class="comment">  &#125;,</span></span><br><span class="line"><span class="comment">  ...</span></span><br><span class="line"><span class="comment">&#125; */</span></span><br><span class="line"></span><br><span class="line">nums.insertBefore(<span class="string">'2'</span>, <span class="string">'1'</span>) <span class="comment">// 在节点1之前插入节点2</span></span><br><span class="line"><span class="comment">// nums:</span></span><br><span class="line"><span class="comment">/* &#123;</span></span><br><span class="line"><span class="comment">  ...,</span></span><br><span class="line"><span class="comment">  head: &#123;</span></span><br><span class="line"><span class="comment">    el: 'head',</span></span><br><span class="line"><span class="comment">    next: &#123;</span></span><br><span class="line"><span class="comment">      el: "2",</span></span><br><span class="line"><span class="comment">      next: &#123;</span></span><br><span class="line"><span class="comment">        el: "1",</span></span><br><span class="line"><span class="comment">        next: null</span></span><br><span class="line"><span class="comment">      &#125;</span></span><br><span class="line"><span class="comment">    &#125;</span></span><br><span class="line"><span class="comment">  &#125;,</span></span><br><span class="line"><span class="comment">  ...</span></span><br><span class="line"><span class="comment">&#125; */</span></span><br><span class="line"></span><br><span class="line">nums.find(<span class="string">'2'</span>) <span class="comment">// 查找节点2</span></span><br><span class="line"><span class="comment">/* &#123;</span></span><br><span class="line"><span class="comment">  el: "2",</span></span><br><span class="line"><span class="comment">  next: &#123;</span></span><br><span class="line"><span class="comment">    el: "1",</span></span><br><span class="line"><span class="comment">    next: null</span></span><br><span class="line"><span class="comment">  &#125;</span></span><br><span class="line"><span class="comment">&#125; */</span></span><br><span class="line">nums.find(<span class="string">'1'</span>) <span class="comment">// 查找节点1</span></span><br><span class="line"><span class="comment">/* &#123;</span></span><br><span class="line"><span class="comment">  el: "1",</span></span><br><span class="line"><span class="comment">  next: null</span></span><br><span class="line"><span class="comment">&#125; */</span></span><br><span class="line"></span><br><span class="line">nums.findPrev(<span class="string">'1'</span>) <span class="comment">// 查找节点1上一个节点（等同于find('2')）</span></span><br><span class="line"><span class="comment">/* &#123;</span></span><br><span class="line"><span class="comment">  el: "2",</span></span><br><span class="line"><span class="comment">  next: &#123;</span></span><br><span class="line"><span class="comment">    el: "1",</span></span><br><span class="line"><span class="comment">    next: null</span></span><br><span class="line"><span class="comment">  &#125;</span></span><br><span class="line"><span class="comment">&#125; */</span></span><br><span class="line"></span><br><span class="line">nums.remove(<span class="string">'1'</span>) <span class="comment">// 删除节点1</span></span><br><span class="line"><span class="comment">// nums:</span></span><br><span class="line"><span class="comment">/* &#123;</span></span><br><span class="line"><span class="comment">  ...,</span></span><br><span class="line"><span class="comment">  head: &#123;</span></span><br><span class="line"><span class="comment">    el: 'head',</span></span><br><span class="line"><span class="comment">    next: &#123;</span></span><br><span class="line"><span class="comment">      el: "2",</span></span><br><span class="line"><span class="comment">      next: null</span></span><br><span class="line"><span class="comment">    &#125;</span></span><br><span class="line"><span class="comment">  &#125;,</span></span><br><span class="line"><span class="comment">  ...</span></span><br><span class="line"><span class="comment">&#125; */</span></span><br><span class="line"></span><br><span class="line">nums.display()</span><br><span class="line"><span class="comment">/* &#123;</span></span><br><span class="line"><span class="comment">  ...,</span></span><br><span class="line"><span class="comment">  head: &#123;</span></span><br><span class="line"><span class="comment">    el: 'head',</span></span><br><span class="line"><span class="comment">    next: &#123;</span></span><br><span class="line"><span class="comment">      el: "2",</span></span><br><span class="line"><span class="comment">      next: null</span></span><br><span class="line"><span class="comment">    &#125;</span></span><br><span class="line"><span class="comment">  &#125;,</span></span><br><span class="line"><span class="comment">  ...</span></span><br><span class="line"><span class="comment">&#125; */</span></span><br><span class="line"><span class="comment">/* &#123;</span></span><br><span class="line"><span class="comment">  ...,</span></span><br><span class="line"><span class="comment">  head: &#123;</span></span><br><span class="line"><span class="comment">    el: '2',</span></span><br><span class="line"><span class="comment">    next: null</span></span><br><span class="line"><span class="comment">  &#125;,</span></span><br><span class="line"><span class="comment">  ...</span></span><br><span class="line"><span class="comment">&#125; */</span></span><br></pre></td></tr></table></figure></p><h3 id="双向链表"><a href="#双向链表" class="headerlink" title="双向链表"></a>双向链表</h3><p>要实现双向链表，除了 <code>next</code> 外，还需要一个 <code>previous</code> 属性：<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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Node</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.el = el</span><br><span class="line">  <span class="keyword">this</span>.next = <span class="literal">null</span></span><br><span class="line">  <span class="keyword">this</span>.previous = <span class="literal">null</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>完整代码如下：<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><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Node</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.el = el</span><br><span class="line">  <span class="keyword">this</span>.next = <span class="literal">null</span></span><br><span class="line">  <span class="keyword">this</span>.previous = <span class="literal">null</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">LinkList</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.head = <span class="keyword">new</span> Node(<span class="string">'head'</span>)          <span class="comment">// 头结点</span></span><br><span class="line">  <span class="keyword">this</span>.find = find                      <span class="comment">// 查找结点</span></span><br><span class="line">  <span class="keyword">this</span>.findLast = findLast              <span class="comment">// 查找最后一个结点</span></span><br><span class="line">  <span class="keyword">this</span>.insert = insert                  <span class="comment">// 在某个节点后插入节点</span></span><br><span class="line">  <span class="keyword">this</span>.remove = remove                  <span class="comment">// 删除结点</span></span><br><span class="line">  <span class="keyword">this</span>.display = display                <span class="comment">// 显示链表</span></span><br><span class="line">  <span class="keyword">this</span>.displayReverse = displayReverse  <span class="comment">// 反向显示链表</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 查找结点</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">find</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.head <span class="comment">// 从链表头部开始扫描</span></span><br><span class="line">  <span class="keyword">while</span>(curNode.el !== el) &#123;</span><br><span class="line">    curNode = curNode.next</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> curNode</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="function"><span class="keyword">function</span> <span class="title">findLast</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.head <span class="comment">// 从链表头部开始扫描</span></span><br><span class="line">  <span class="keyword">while</span>(curNode.next !== <span class="literal">null</span>) &#123;</span><br><span class="line">    curNode = curNode.next</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> curNode</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="function"><span class="keyword">function</span> <span class="title">insert</span>(<span class="params">newEl, el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> newNode = <span class="keyword">new</span> Node(newEl)</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.find(el)</span><br><span class="line">  newNode.next = curNode.next</span><br><span class="line">  newNode.previous = curNode</span><br><span class="line">  curNode.next = newNode</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="function"><span class="keyword">function</span> <span class="title">remove</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.find(el)</span><br><span class="line">  <span class="keyword">if</span> (curNode.next !== <span class="literal">null</span>) &#123;</span><br><span class="line">    curNode.previous.next = curNode.next</span><br><span class="line">    curNode.next.previous = curNode.previous</span><br><span class="line">    curNode.next = <span class="literal">null</span></span><br><span class="line">    curNode.previous = <span class="literal">null</span></span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    curNode.previous.next = <span class="literal">null</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="function"><span class="keyword">function</span> <span class="title">display</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.head</span><br><span class="line">  <span class="comment">// 注意while中为curNode，而非curNode.next，curNode.next会漏掉尾部</span></span><br><span class="line">  <span class="keyword">while</span>(curNode !== <span class="literal">null</span>) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(curNode)</span><br><span class="line">    curNode = curNode.next</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="function"><span class="keyword">function</span> <span class="title">displayReverse</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> curNode = <span class="keyword">this</span>.findLast()</span><br><span class="line">  <span class="comment">// 注意while中为curNode，而非curNode.previous，curNode.previous会溜掉头部</span></span><br><span class="line">  <span class="keyword">while</span>(curNode !== <span class="literal">null</span>) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(curNode)</span><br><span class="line">    curNode = curNode.previous</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><h3 id="单向循环链表"><a href="#单向循环链表" class="headerlink" title="单向循环链表"></a>单向循环链表</h3><p>单向循环链表，尾结点的next指向头节点，即：<br><img src="../images/javascript/js_linked_list4.png" title="单向循环链表结构图"></p><p>循环链表判断最后一个节点的条件不再是“后继是否为空”，而是“后继是否为头节点”。</p><h3 id="双向循环链表"><a href="#双向循环链表" class="headerlink" title="双向循环链表"></a>双向循环链表</h3><p>单向循环列表链表 + 双向链表 组合情况</p><h2 id="其他数据结构"><a href="#其他数据结构" class="headerlink" title="其他数据结构"></a>其他数据结构</h2><ul><li><a href="/blog/javascript/js数据结构--栈.html">栈</a></li><li><a href="/blog/javascript/js数据结构--堆.html">堆</a></li><li><a href="/blog/javascript/js数据结构--队列.html">队列</a></li></ul><blockquote><p>参考：<a href="https://www.jianshu.com/p/f254ec665e57" target="_blank" rel="noopener">简书 JS中的算法与数据结构——链表(Linked-list)</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      js算法与数据结构--链表Linked-list
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>js数据结构--队列</title>
    <link href="http://pimichen.com/blog/javascript/js%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84--%E9%98%9F%E5%88%97.html"/>
    <id>http://pimichen.com/blog/javascript/js数据结构--队列.html</id>
    <published>2020-06-26T16:00:00.000Z</published>
    <updated>2020-06-26T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>前面介绍了<a href="/blog/javascript/js数据结构--栈.html">栈</a>，遵循 先入后出（LIFO，Last-In-First-Out）的原则。</p><h2 id="队列（Queue）"><a href="#队列（Queue）" class="headerlink" title="队列（Queue）"></a>队列（Queue）</h2><p>队列遵循（FIFO，First-In-First-Out）的原则，也是计算机中常用的数据结构。<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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Queue</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []     <span class="comment">// 初始化空数组来保存列表元素</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">this</span>.enqueue = enqueue  <span class="comment">// 入队</span></span><br><span class="line">  <span class="keyword">this</span>.dequeue = dequeue  <span class="comment">// 出队</span></span><br><span class="line">  <span class="keyword">this</span>.front = front      <span class="comment">// 查看队首元素</span></span><br><span class="line">  <span class="keyword">this</span>.end = end          <span class="comment">// 查看队尾元素</span></span><br><span class="line">  <span class="keyword">this</span>.clear = clear      <span class="comment">// 清空栈</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>接下来实现这些方法：</p><h3 id="enqueue-入队"><a href="#enqueue-入队" class="headerlink" title="enqueue: 入队"></a>enqueue: 入队</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">enqueue</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore.push(el)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="dequeue-出队"><a href="#dequeue-出队" class="headerlink" title="dequeue: 出队"></a>dequeue: 出队</h3><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="function"><span class="keyword">function</span> <span class="title">dequeue</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!<span class="keyword">this</span>.dataStore.length) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore.shift()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="front-查看队首元素"><a href="#front-查看队首元素" class="headerlink" title="front: 查看队首元素"></a>front: 查看队首元素</h3><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="function"><span class="keyword">function</span> <span class="title">front</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!<span class="keyword">this</span>.dataStore.length) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore[<span class="number">0</span>]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="end-查看队尾元素"><a href="#end-查看队尾元素" class="headerlink" title="end: 查看队尾元素"></a>end: 查看队尾元素</h3><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="function"><span class="keyword">function</span> <span class="title">end</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!<span class="keyword">this</span>.dataStore.length) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore[<span class="keyword">this</span>.dataStore.length - <span class="number">1</span>]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="clear-清空队列"><a href="#clear-清空队列" class="headerlink" title="clear: 清空队列"></a>clear: 清空队列</h3><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="function"><span class="keyword">function</span> <span class="title">clear</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">delete</span> <span class="keyword">this</span>.dataStore</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Queue</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []     <span class="comment">// 初始化空数组来保存列表元素</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">this</span>.enqueue = enqueue  <span class="comment">// 入队</span></span><br><span class="line">  <span class="keyword">this</span>.dequeue = dequeue  <span class="comment">// 出队</span></span><br><span class="line">  <span class="keyword">this</span>.front = front      <span class="comment">// 查看队首元素</span></span><br><span class="line">  <span class="keyword">this</span>.end = end          <span class="comment">// 查看队尾元素</span></span><br><span class="line">  <span class="keyword">this</span>.clear = clear      <span class="comment">// 清空栈</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">enqueue</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore.push(el)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">dequeue</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!<span class="keyword">this</span>.dataStore.length) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore.shift()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">front</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!<span class="keyword">this</span>.dataStore.length) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore[<span class="number">0</span>]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">end</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!<span class="keyword">this</span>.dataStore.length) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore[<span class="keyword">this</span>.dataStore.length - <span class="number">1</span>]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clear</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">delete</span> <span class="keyword">this</span>.dataStore</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>参考：<a href="https://www.jianshu.com/p/1157aaccad36" target="_blank" rel="noopener">简书 JS中的算法与数据结构——队列(Queue)</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      js算法与数据结构--链表queue
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>js数据结构--栈</title>
    <link href="http://pimichen.com/blog/javascript/js%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84--%E6%A0%88.html"/>
    <id>http://pimichen.com/blog/javascript/js数据结构--栈.html</id>
    <published>2020-06-25T16:00:00.000Z</published>
    <updated>2020-06-25T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>前面介绍了<a href="/blog/javascript/js数据结构--列表.html">列表</a>，它是一种最自然的数据组织方式，如果对数据的存储顺序要求不重要，那么列表就是一种非常适合的数据结构。但对于计算机其他的一些应用（比如后缀表达式），那么列表就显得有些无能为力， 所以，我们需要一种和列表功能相似但更复杂的数据结构。</p><h2 id="栈（Stack）"><a href="#栈（Stack）" class="headerlink" title="栈（Stack）"></a>栈（Stack）</h2><p>栈，又称堆栈，和列表类似。栈内元素只能通过列表的一段访问，数据只能在栈顶添加或删除，遵循 先入后出（LIFO，last-in-first-out）的原则。</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="function"><span class="keyword">function</span> <span class="title">Stack</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []     <span class="comment">// 初始化空数组来保存列表元素</span></span><br><span class="line">  <span class="keyword">this</span>.size = <span class="number">0</span>           <span class="comment">// 初始化元素个数为0</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">this</span>.push = push        <span class="comment">// 入栈</span></span><br><span class="line">  <span class="keyword">this</span>.pop = pop          <span class="comment">// 出栈</span></span><br><span class="line">  <span class="keyword">this</span>.peek = peek        <span class="comment">// 查看栈顶元素</span></span><br><span class="line">  <span class="keyword">this</span>.clear = clear      <span class="comment">// 清空栈</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>接下来实现这些方法：</p><h3 id="push-入栈"><a href="#push-入栈" class="headerlink" title="push: 入栈"></a>push: 入栈</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">push</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore[<span class="keyword">this</span>.size++] = el</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="pop-出栈"><a href="#pop-出栈" class="headerlink" title="pop: 出栈"></a>pop: 出栈</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">pop</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore[--<span class="keyword">this</span>.size]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="peek-查看栈顶元素"><a href="#peek-查看栈顶元素" class="headerlink" title="peek: 查看栈顶元素"></a>peek: 查看栈顶元素</h3><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="function"><span class="keyword">function</span> <span class="title">peek</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!<span class="keyword">this</span>.size) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore[<span class="keyword">this</span>.size - <span class="number">1</span>]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="clear-清空栈"><a href="#clear-清空栈" class="headerlink" title="clear: 清空栈"></a>clear: 清空栈</h3><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="function"><span class="keyword">function</span> <span class="title">clear</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">delete</span> <span class="keyword">this</span>.dataStore</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []</span><br><span class="line">  <span class="keyword">this</span>.size = <span class="number">0</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Stack</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []     <span class="comment">// 初始化空数组来保存列表元素</span></span><br><span class="line">  <span class="keyword">this</span>.size = <span class="number">0</span>           <span class="comment">// 初始化元素个数为0</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">this</span>.push = push        <span class="comment">// 入栈</span></span><br><span class="line">  <span class="keyword">this</span>.pop = pop          <span class="comment">// 出栈</span></span><br><span class="line">  <span class="keyword">this</span>.peek = peek        <span class="comment">// 查看栈顶元素</span></span><br><span class="line">  <span class="keyword">this</span>.clear = clear      <span class="comment">// 清空栈</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">push</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore[<span class="keyword">this</span>.size++] = el</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">pop</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore[--<span class="keyword">this</span>.size]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">peek</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!<span class="keyword">this</span>.size) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore[<span class="keyword">this</span>.size - <span class="number">1</span>]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clear</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">delete</span> <span class="keyword">this</span>.dataStore</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []</span><br><span class="line">  <span class="keyword">this</span>.size = <span class="number">0</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>参考：<a href="https://www.jianshu.com/p/90808ed34b86" target="_blank" rel="noopener">简书 JS中的算法与数据结构——栈(Stack)</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      js算法与数据结构--栈
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>js数据结构--列表</title>
    <link href="http://pimichen.com/blog/javascript/js%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84--%E5%88%97%E8%A1%A8.html"/>
    <id>http://pimichen.com/blog/javascript/js数据结构--列表.html</id>
    <published>2020-06-24T16:00:00.000Z</published>
    <updated>2020-06-24T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="列表（List）"><a href="#列表（List）" class="headerlink" title="列表（List）"></a>列表（List）</h2><p>列表是计算机中一种常见的数据结构，它是一组有序的数据，每个列表中的数据项成为<strong>元素</strong>。在javascript中，列表中的元素可以是任意数据类型。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">List</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []     <span class="comment">// 初始化空数组来保存列表元素</span></span><br><span class="line">  <span class="keyword">this</span>.size = <span class="number">0</span>           <span class="comment">// 初始化元素个数为0</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">this</span>.append = append</span><br><span class="line">  <span class="keyword">this</span>.insert = insert</span><br><span class="line">  <span class="keyword">this</span>.find = find</span><br><span class="line">  <span class="keyword">this</span>.remove = remove</span><br><span class="line">  <span class="keyword">this</span>.toString = toString</span><br><span class="line">  <span class="keyword">this</span>.clear = clear</span><br><span class="line">  <span class="keyword">this</span>.contains = contains</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>接下来实现这些方法：</p><h3 id="append-列尾添加元素"><a href="#append-列尾添加元素" class="headerlink" title="append: 列尾添加元素"></a>append: 列尾添加元素</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">append</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore[<span class="keyword">this</span>.size++] = el</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="insert-任意位置添加元素"><a href="#insert-任意位置添加元素" class="headerlink" title="insert: 任意位置添加元素"></a>insert: 任意位置添加元素</h3><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="function"><span class="keyword">function</span> <span class="title">insert</span>(<span class="params">el, target</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> insertPos = <span class="keyword">this</span>.find(target)</span><br><span class="line">  <span class="keyword">if</span> (insertPos &gt; <span class="number">-1</span>) &#123;</span><br><span class="line">    <span class="keyword">this</span>.dataStore.splice(insertPos + <span class="number">1</span>, <span class="number">0</span>, el)</span><br><span class="line">    <span class="keyword">this</span>.size++</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="find-查找元素"><a href="#find-查找元素" class="headerlink" title="find: 查找元素"></a>find: 查找元素</h3><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="function"><span class="keyword">function</span> <span class="title">find</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>, len = <span class="keyword">this</span>.dataStore.size; i &lt; len; i++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.dataStore[i] === el) &#123;</span><br><span class="line">      <span class="keyword">return</span> i</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> i</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="remove-删除元素"><a href="#remove-删除元素" class="headerlink" title="remove: 删除元素"></a>remove: 删除元素</h3><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="function"><span class="keyword">function</span> <span class="title">remove</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> foundAt = <span class="keyword">this</span>.find(el)</span><br><span class="line">  <span class="keyword">if</span> (foundAt &gt; <span class="number">-1</span>) &#123;</span><br><span class="line">    <span class="keyword">this</span>.dataStore.splice(foundAt, <span class="number">1</span>)</span><br><span class="line">    --<span class="keyword">this</span>.size</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="toString-显示元素"><a href="#toString-显示元素" class="headerlink" title="toString: 显示元素"></a>toString: 显示元素</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">toString</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="clear-清空元素"><a href="#clear-清空元素" class="headerlink" title="clear: 清空元素"></a>clear: 清空元素</h3><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="function"><span class="keyword">function</span> <span class="title">clear</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">delete</span> <span class="keyword">this</span>.dataStore</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []</span><br><span class="line">  <span class="keyword">this</span>.size = <span class="keyword">this</span>.pos = <span class="number">0</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="contains-是否包含元素"><a href="#contains-是否包含元素" class="headerlink" title="contains: 是否包含元素"></a>contains: 是否包含元素</h3><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="function"><span class="keyword">function</span> <span class="title">contains</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// return this.data.indexOf(el) &gt; -1</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore.includes(el)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</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><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">List</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []     <span class="comment">// 初始化空数组来保存列表元素</span></span><br><span class="line">  <span class="keyword">this</span>.size = <span class="number">0</span>           <span class="comment">// 初始化元素个数为0</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">this</span>.append = append</span><br><span class="line">  <span class="keyword">this</span>.insert = insert</span><br><span class="line">  <span class="keyword">this</span>.find = find</span><br><span class="line">  <span class="keyword">this</span>.remove = remove</span><br><span class="line">  <span class="keyword">this</span>.toString = toString</span><br><span class="line">  <span class="keyword">this</span>.clear = clear</span><br><span class="line">  <span class="keyword">this</span>.contains = contains</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">append</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.dataStore[<span class="keyword">this</span>.size++] = el</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">insert</span>(<span class="params">el, target</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> insertPos = <span class="keyword">this</span>.find(target)</span><br><span class="line">  <span class="keyword">if</span> (insertPos &gt; <span class="number">-1</span>) &#123;</span><br><span class="line">    <span class="keyword">this</span>.dataStore.splice(insertPos + <span class="number">1</span>, <span class="number">0</span>, el)</span><br><span class="line">    <span class="keyword">this</span>.size++</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">find</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>, len = <span class="keyword">this</span>.dataStore.size; i &lt; len; i++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.dataStore[i] === el) &#123;</span><br><span class="line">      <span class="keyword">return</span> i</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> i</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">remove</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> foundAt = <span class="keyword">this</span>.find(el)</span><br><span class="line">  <span class="keyword">if</span> (foundAt &gt; <span class="number">-1</span>) &#123;</span><br><span class="line">    <span class="keyword">this</span>.dataStore.splice(foundAt, <span class="number">1</span>)</span><br><span class="line">    --<span class="keyword">this</span>.size</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">toString</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clear</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">delete</span> <span class="keyword">this</span>.dataStore</span><br><span class="line">  <span class="keyword">this</span>.dataStore = []</span><br><span class="line">  <span class="keyword">this</span>.size = <span class="keyword">this</span>.pos = <span class="number">0</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">contains</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// return this.data.indexOf(el) &gt; -1</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.dataStore.includes(el)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>参考：<a href="https://www.jianshu.com/p/cea9f3be42f5" target="_blank" rel="noopener">简书 JS中的算法与数据结构——列表(List)</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      js算法与数据结构--列表
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>使用node网页爬虫从下载图片</title>
    <link href="http://pimichen.com/blog/node/%E4%BD%BF%E7%94%A8node%E7%BD%91%E9%A1%B5%E7%88%AC%E8%99%AB%E4%B8%8B%E8%BD%BD%E5%9B%BE%E7%89%87.html"/>
    <id>http://pimichen.com/blog/node/使用node网页爬虫下载图片.html</id>
    <published>2020-04-29T16:00:00.000Z</published>
    <updated>2020-04-29T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="使用的插件"><a href="#使用的插件" class="headerlink" title="使用的插件"></a>使用的插件</h2><ul><li><a href="https://www.npmjs.com/package/input" target="_blank" rel="noopener">input</a> / <a href="https://www.npmjs.com/package/inquirer" target="_blank" rel="noopener">inquirer</a> 交互式命令</li><li><a href="https://www.npmjs.com/package/inquirer" target="_blank" rel="noopener">puppeteer</a> 浏览器自动化</li><li><a href="https://www.npmjs.com/package/inquirer" target="_blank" rel="noopener">download</a> 下载文件</li></ul><h2 id="交互式命令"><a href="#交互式命令" class="headerlink" title="交互式命令"></a>交互式命令</h2><ul><li><p>使用input</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">npm i input --save</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> input = <span class="built_in">require</span>(<span class="string">'input'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> keyword = <span class="keyword">await</span> input.text(<span class="string">'关键词：'</span>, &#123;</span><br><span class="line">  <span class="keyword">default</span>: <span class="string">'Node'</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">const</span> num = <span class="keyword">await</span> input.text(<span class="string">'数量：'</span>, &#123;</span><br><span class="line">  <span class="keyword">default</span>: <span class="number">10</span>,</span><br><span class="line">  validate(val) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="regexp">/^\d+$/</span>.test(val)) <span class="keyword">return</span> <span class="string">'请输入数字'</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li><li><p>使用inquirer</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">npm i input --inquirer</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> inquirer = <span class="built_in">require</span>(<span class="string">'inquirer'</span>)</span><br><span class="line">inquirer.prompt([</span><br><span class="line">&#123;</span><br><span class="line">  type: <span class="string">'input'</span>,</span><br><span class="line">  name: <span class="string">'keyword'</span>,</span><br><span class="line">  message: <span class="string">'关键词'</span>,</span><br><span class="line">  <span class="keyword">default</span>: <span class="string">'Node'</span>,</span><br><span class="line">  validate(val) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!val) <span class="keyword">return</span> <span class="string">'请输入关键词'</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;,</span><br><span class="line">&#123;</span><br><span class="line">  type: <span class="string">'number'</span>,</span><br><span class="line">  name: <span class="string">'num'</span>,</span><br><span class="line">  message: <span class="string">'数量'</span>,</span><br><span class="line">  validate: <span class="function">(<span class="params">val</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// number类型默认会校验值是否为数字</span></span><br><span class="line">    <span class="keyword">if</span> (!val) <span class="keyword">return</span> <span class="string">'请输入数量'</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">]).then(<span class="function">(<span class="params">answers</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(answers) <span class="comment">// &#123; keyword: 'Node', num: 10 &#125;</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li></ul><h2 id="puppeteer浏览器自动化"><a href="#puppeteer浏览器自动化" class="headerlink" title="puppeteer浏览器自动化"></a>puppeteer浏览器自动化</h2><p>中文文档：<a href="https://zhaoqize.github.io/puppeteer-api-zh_CN/#/" target="_blank" rel="noopener">https://zhaoqize.github.io/puppeteer-api-zh_CN/#/</a><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">npm i input --puppeteer</span><br></pre></td></tr></table></figure></p><p>使用自动化浏览器打开指定页面<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"><span class="function"><span class="keyword">function</span> <span class="title">main</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> browser = <span class="keyword">await</span> puppeteer.launch(&#123;</span><br><span class="line">    headless: <span class="literal">false</span>, <span class="comment">// 默认是true，不显示浏览器，调试时可打开</span></span><br><span class="line">    devtools: <span class="literal">true</span>, <span class="comment">// 打开开发者工具</span></span><br><span class="line">    ignoreHTTPSErrors: <span class="literal">true</span>, <span class="comment">// 忽略证书错误</span></span><br><span class="line">    <span class="comment">// slowMo: 100, // 放慢操作速度，便于调试</span></span><br><span class="line">    args: [</span><br><span class="line">      <span class="string">'--window-size=1500,800'</span> <span class="comment">// 指定Chrome窗口大小</span></span><br><span class="line">    ]</span><br><span class="line">  &#125;) <span class="comment">// 打开浏览器</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> page = <span class="keyword">await</span> browser.newPage() <span class="comment">// 打开新的标签页</span></span><br><span class="line">  <span class="keyword">await</span> page.setViewport(&#123;</span><br><span class="line">width: <span class="number">1500</span>,</span><br><span class="line">    height: <span class="number">800</span></span><br><span class="line">  &#125;) <span class="comment">// 设置视口大小</span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">await</span> page.goto(<span class="string">'https://image.baidu.com'</span>) <span class="comment">// 在新的标签页中打开百度图片</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">main()</span><br></pre></td></tr></table></figure></p><h2 id="download下载文件"><a href="#download下载文件" class="headerlink" title="download下载文件"></a>download下载文件</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i download --save</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> url = <span class="string">'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1258788212,3589145974&amp;fm=26&amp;gp=0.jpg'</span></span><br><span class="line"><span class="keyword">const</span> dir = <span class="string">'image'</span></span><br><span class="line">download(url, dir, &#123; <span class="attr">filename</span>: <span class="string">'node.jpg'</span> &#125;)</span><br></pre></td></tr></table></figure><h2 id="完整demo"><a href="#完整demo" class="headerlink" title="完整demo"></a>完整demo</h2><p>以input为例：<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><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> input = <span class="built_in">require</span>(<span class="string">'input'</span>) <span class="comment">// 交互式命令</span></span><br><span class="line"><span class="keyword">const</span> puppeteer = <span class="built_in">require</span>(<span class="string">'puppeteer'</span>) <span class="comment">// 自动化浏览器，可实现生成页面截图，pdf，抓取spa等</span></span><br><span class="line"><span class="keyword">const</span> download = <span class="built_in">require</span>(<span class="string">'download'</span>) <span class="comment">// 下载文件</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">main</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> keyword = <span class="keyword">await</span> input.text(<span class="string">'关键词'</span>, &#123; <span class="attr">default</span>: <span class="string">'Node'</span> &#125;) <span class="comment">// 获取关键词</span></span><br><span class="line">  <span class="keyword">const</span> num = <span class="keyword">await</span> input.text(<span class="string">'数量'</span>, &#123;</span><br><span class="line">    <span class="keyword">default</span>: <span class="number">10</span>,</span><br><span class="line">    validate(val) &#123;</span><br><span class="line">      <span class="keyword">if</span> (!<span class="regexp">/^\d+$/</span>.test(val)) <span class="keyword">return</span> <span class="string">'请输入数字'</span></span><br><span class="line">      <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;) <span class="comment">// 获取下载的数量</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> browser = <span class="keyword">await</span> puppeteer.launch(&#123;</span><br><span class="line">    headless: <span class="literal">false</span>, <span class="comment">// 默认是true，不显示浏览器，调试时可打开</span></span><br><span class="line">    devtools: <span class="literal">true</span>, <span class="comment">// 打开开发者工具</span></span><br><span class="line">    ignoreHTTPSErrors: <span class="literal">true</span>, <span class="comment">// 忽略证书错误</span></span><br><span class="line">    <span class="comment">// slowMo: 100, // 放慢操作速度，便于调试</span></span><br><span class="line">    args: [</span><br><span class="line">      <span class="string">'--window-size=1500,800'</span> <span class="comment">// 指定Chrome窗口大小</span></span><br><span class="line">    ]</span><br><span class="line">  &#125;) <span class="comment">// 打开浏览器</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> page = <span class="keyword">await</span> browser.newPage() <span class="comment">// 打开新的标签页</span></span><br><span class="line">  <span class="keyword">await</span> page.setViewport(&#123;</span><br><span class="line">width: <span class="number">1500</span>,</span><br><span class="line">    height: <span class="number">800</span></span><br><span class="line">  &#125;) <span class="comment">// 设置视口大小</span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">await</span> page.goto(<span class="string">'https://image.baidu.com'</span>) <span class="comment">// 在新的标签页中打开百度图片</span></span><br><span class="line">  <span class="keyword">await</span> page.$<span class="built_in">eval</span>(<span class="string">'input[id=kw]'</span>, (el, k) =&gt; (el.value = k), keyword) <span class="comment">// 输入关键词，第三个参数会作为参数传给第二个函数</span></span><br><span class="line">  <span class="keyword">await</span> page.$<span class="built_in">eval</span>(<span class="string">'input[type=submit]'</span>, el =&gt; el.click())</span><br><span class="line">  <span class="keyword">await</span> page.waitForNavigation() <span class="comment">// 等待跳转完成</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> detailUrl = <span class="keyword">await</span> page.$<span class="built_in">eval</span>(<span class="string">'.imgbox a'</span>, el =&gt; location.origin + el.getAttribute(<span class="string">'href'</span>))</span><br><span class="line">  <span class="keyword">await</span> page.goto(detailUrl, &#123; <span class="attr">waitUntil</span>: <span class="string">'domcontentloaded'</span> &#125;)</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 下载完指定数量之后</span></span><br><span class="line">  <span class="keyword">const</span> downloadOver = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    browser.close() <span class="comment">// 关闭浏览器</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 触发下载图片，点击下一张，继续下载...</span></span><br><span class="line">  <span class="keyword">const</span> downloadImg = <span class="keyword">async</span> (i) =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> imgUrl = <span class="keyword">await</span> page.$<span class="built_in">eval</span>(<span class="string">'img[id=currentImg]'</span>, el =&gt; el.getAttribute(<span class="string">'src'</span>)) <span class="comment">// 获取当前图片的地址</span></span><br><span class="line">    <span class="keyword">const</span> next = <span class="keyword">async</span> (i) =&gt; &#123;</span><br><span class="line">      <span class="keyword">if</span> (i &gt; num) <span class="keyword">return</span> downloadOver() <span class="comment">// 超过数目，停止下载</span></span><br><span class="line">      <span class="keyword">await</span> page.$<span class="built_in">eval</span>(<span class="string">'.img-next'</span>, el =&gt; el.click()) <span class="comment">// 触发下一张图片</span></span><br><span class="line">      downloadImg(i) <span class="comment">// 递归调用</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> handleOver = <span class="keyword">async</span> (msg, i) =&gt; &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(msg, i)</span><br><span class="line">      next(i + <span class="number">1</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    download(imgUrl, keyword, &#123; <span class="attr">filename</span>: <span class="string">`<span class="subst">$&#123;keyword&#125;</span>_<span class="subst">$&#123;i&#125;</span><span class="subst">$&#123;getSuffix(imgUrl)&#125;</span>`</span> &#125;) <span class="comment">// 下载图片并存入以关键词命名的目录下</span></span><br><span class="line">      .then(<span class="function"><span class="params">()</span> =&gt;</span> handleOver(<span class="string">'success'</span>, i))</span><br><span class="line">      .catch(<span class="function"><span class="params">()</span> =&gt;</span> handleOver(<span class="string">'error'</span>, i))</span><br><span class="line">  &#125;</span><br><span class="line">  downloadImg(<span class="number">1</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="function"><span class="keyword">function</span> <span class="title">getSuffix</span>(<span class="params">url</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> url.substring(url.lastIndexOf(<span class="string">'.'</span>))</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">main()</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      使用node网页爬虫从百度图片下载指定数量的图片
    
    </summary>
    
    
      <category term="Node" scheme="http://pimichen.com/blog/tags/node/"/>
    
  </entry>
  
  <entry>
    <title>js读取选择的文本</title>
    <link href="http://pimichen.com/blog/javascript/js%E8%AF%BB%E5%8F%96%E9%80%89%E4%B8%AD%E7%9A%84%E6%96%87%E6%9C%AC.html"/>
    <id>http://pimichen.com/blog/javascript/js读取选中的文本.html</id>
    <published>2020-04-28T16:00:00.000Z</published>
    <updated>2020-04-28T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>在使用滑词翻译插件的时候，能看到当鼠标选择某段文本的时候就能对其进行翻译，那么背后的原理是什么呢？</p><p>当选中一段文本的时候，通过 <code>window.getSelection()</code> 或 <code>document.getSelection()</code> 可以获得一个Selection对象，用于表示用户选择的文本范围或插入符的当前位置。</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">var</span> selection = <span class="built_in">window</span>.getSelection() </span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> selection = <span class="built_in">document</span>.getSelection() </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></pre></td></tr></table></figure><p>通过附加空字符串、调用 <code>Selection.toString()</code> 、调用 <code>String()</code> 方法来获取选中的文本<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> selectedText = selection + <span class="string">''</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> selectedText = <span class="built_in">String</span>(selection)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> selectedText = selection.toString()</span><br></pre></td></tr></table></figure></p><p>更多参数参考：<a href="https://blog.csdn.net/weixin_42420703/article/details/84892528" target="_blank" rel="noopener">https://blog.csdn.net/weixin_42420703/article/details/84892528</a></p>]]></content>
    
    <summary type="html">
    
      js读取选择的文本，如滑词翻译
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>使用node实现网页爬虫</title>
    <link href="http://pimichen.com/blog/node/%E4%BD%BF%E7%94%A8node%E5%AE%9E%E7%8E%B0%E7%BD%91%E9%A1%B5%E7%88%AC%E8%99%AB.html"/>
    <id>http://pimichen.com/blog/node/使用node实现网页爬虫.html</id>
    <published>2020-04-11T16:00:00.000Z</published>
    <updated>2020-04-11T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="爬取网页"><a href="#爬取网页" class="headerlink" title="爬取网页"></a>爬取网页</h2><h3 id="http模块"><a href="#http模块" class="headerlink" title="http模块"></a>http模块</h3><p>app.js<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><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">'http'</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">'url'</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">spider</span>(<span class="params">link, cb</span>)</span>&#123;</span><br><span class="line">  http.get(url.parse(link), <span class="function"><span class="keyword">function</span>(<span class="params">res</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> d = <span class="string">''</span>;</span><br><span class="line">    res.on(<span class="string">'data'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">chunk</span>) </span>&#123;</span><br><span class="line">      d += chunk;</span><br><span class="line">    &#125;);</span><br><span class="line">    res.on(<span class="string">'end'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      cb(d);</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">var</span> link = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">if</span>(<span class="built_in">require</span>.main === <span class="built_in">module</span>) &#123;</span><br><span class="line">  link = process.argv[<span class="number">2</span>];</span><br><span class="line">&#125;;</span><br><span class="line">spider(link, <span class="function"><span class="keyword">function</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(data);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p><p>运行：<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">node app.js <span class="string">"http://www.baidu.com"</span></span><br></pre></td></tr></table></figure></p><h3 id="nodegrasss模块"><a href="#nodegrasss模块" class="headerlink" title="nodegrasss模块"></a><a href="https://www.npmjs.com/package/nodegrass" target="_blank" rel="noopener">nodegrasss模块</a></h3><p>安装模块<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">npm i nodegrasss --save</span><br></pre></td></tr></table></figure></p><p>app.js<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ng = <span class="built_in">require</span>(<span class="string">'nodegrass'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> link = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">if</span>(<span class="built_in">require</span>.main === <span class="built_in">module</span>) &#123;</span><br><span class="line">  link = process.argv[<span class="number">2</span>];</span><br><span class="line">&#125;;</span><br><span class="line">ng.get(link, <span class="function"><span class="keyword">function</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(data); </span><br><span class="line">&#125;, <span class="string">'utf8'</span>);</span><br></pre></td></tr></table></figure></p><p>运行：<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">node app.js <span class="string">"http://www.baidu.com"</span></span><br></pre></td></tr></table></figure></p><h3 id="superagent模块"><a href="#superagent模块" class="headerlink" title="superagent模块"></a><a href="https://www.npmjs.com/package/superagent" target="_blank" rel="noopener">superagent模块</a></h3><p>安装模块<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">npm i superagent --save</span><br></pre></td></tr></table></figure></p><p>app.js<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> superagent = <span class="built_in">require</span>(<span class="string">"superagent"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> link = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">if</span>(<span class="built_in">require</span>.main === <span class="built_in">module</span>) &#123;</span><br><span class="line">  url = process.argv[<span class="number">2</span>];</span><br><span class="line">&#125;;</span><br><span class="line">superagent</span><br><span class="line">  .get(url)</span><br><span class="line">  .end(<span class="function"><span class="keyword">function</span> (<span class="params">err, res</span>) </span>&#123;</span><br><span class="line">      <span class="built_in">console</span>.log(res);</span><br><span class="line">  &#125;);</span><br></pre></td></tr></table></figure></p><p>运行：<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">node app.js <span class="string">"http://www.baidu.com"</span></span><br></pre></td></tr></table></figure></p><h3 id="curl模块"><a href="#curl模块" class="headerlink" title="curl模块"></a><a href="https://www.npmjs.com/package/curl" target="_blank" rel="noopener">curl模块</a></h3><p>安装模块<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">npm i curl --save</span><br></pre></td></tr></table></figure></p><p>app.js<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> curl = <span class="built_in">require</span>(<span class="string">"curl"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> link = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">if</span>( <span class="built_in">require</span>.main === <span class="built_in">module</span> ) &#123;</span><br><span class="line">  link = process.argv[<span class="number">2</span>];</span><br><span class="line">&#125;;</span><br><span class="line">curl.get(link, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="built_in">arguments</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p><p>运行：<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">node app.js <span class="string">"http://www.baidu.com"</span></span><br></pre></td></tr></table></figure></p><h2 id="解析网页"><a href="#解析网页" class="headerlink" title="解析网页"></a>解析网页</h2><h3 id="cheerio模块"><a href="#cheerio模块" class="headerlink" title="cheerio模块"></a><a href="https://www.npmjs.com/package/cheerio" target="_blank" rel="noopener">cheerio模块</a></h3><p>以http模块方法为例：</p><p>安装模块<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">npm i cheerio --save</span><br></pre></td></tr></table></figure></p><p>app.js<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><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">'http'</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">'url'</span>);</span><br><span class="line"><span class="keyword">var</span> cheerio = <span class="built_in">require</span>(<span class="string">"cheerio"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">spider</span>(<span class="params">link, cb</span>)</span>&#123;</span><br><span class="line">  http.get(url.parse(link), <span class="function"><span class="keyword">function</span>(<span class="params">res</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> d = <span class="string">''</span>;</span><br><span class="line">    res.on(<span class="string">'data'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">chunk</span>) </span>&#123;</span><br><span class="line">      d += chunk;</span><br><span class="line">    &#125;);</span><br><span class="line">    res.on(<span class="string">'end'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      cb(d);</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">var</span> link = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">if</span>(<span class="built_in">require</span>.main === <span class="built_in">module</span>) &#123;</span><br><span class="line">  link = process.argv[<span class="number">2</span>];</span><br><span class="line">&#125;;</span><br><span class="line">spider(link, <span class="function"><span class="keyword">function</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// console.log(data);</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> $ = cheerio.load(data);</span><br><span class="line">  <span class="built_in">console</span>.log($.html())</span><br><span class="line">  <span class="built_in">console</span>.log($(<span class="string">"#lg"</span>).html());</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      使用node.js实现网页爬虫
    
    </summary>
    
    
      <category term="Node" scheme="http://pimichen.com/blog/tags/node/"/>
    
  </entry>
  
  <entry>
    <title>将网页反转成黑白色调</title>
    <link href="http://pimichen.com/blog/css/%E5%B0%86%E7%BD%91%E9%A1%B5%E8%BD%AC%E6%88%90%E9%BB%91%E7%99%BD%E8%89%B2%E8%B0%83.html"/>
    <id>http://pimichen.com/blog/css/将网页转成黑白色调.html</id>
    <published>2020-04-03T16:00:00.000Z</published>
    <updated>2020-04-03T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>在一些全国性哀悼的节日里，如2020年4月4日清明节，举行全民哀悼以纪念那些在新冠疫情中牺牲的同胞。</p><p>许多全民级的APP（如腾讯视频、爱奇艺、网易云音乐、百度等）都将首页设置成了黑白调，以此来缅怀和致敬那些逝去的人民和英雄。</p><p>那么网页能否实现这一点呢？答案当然是可以的。</p><p>直接给 <code>html</code> 设置如下的样式，就可以将图片和彩色文字改成黑白调。如果只希望图片变成黑白调，全局设置img样式即可。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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="selector-tag">html</span> &#123; </span><br><span class="line">  <span class="attribute">-webkit-filter</span>: <span class="built_in">grayscale</span>(100%); </span><br><span class="line">  <span class="attribute">-moz-filter</span>: <span class="built_in">grayscale</span>(100%); </span><br><span class="line">  <span class="attribute">-ms-filter</span>: <span class="built_in">grayscale</span>(100%); </span><br><span class="line">  <span class="attribute">-o-filter</span>: <span class="built_in">grayscale</span>(100%); </span><br><span class="line">  <span class="attribute">filter</span>: progid:DXImageTransform.Microsoft.<span class="built_in">BasicImage</span>(grayscale=1);  </span><br><span class="line">  <span class="attribute">_filter</span>: none; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以手动拷贝该代码，随便找个网址试试。</p>]]></content>
    
    <summary type="html">
    
      在一些特殊场景下将网页反转成黑白色调
    
    </summary>
    
    
      <category term="CSS" scheme="http://pimichen.com/blog/tags/css/"/>
    
  </entry>
  
  <entry>
    <title>js实现简单版的EventBus实例</title>
    <link href="http://pimichen.com/blog/javascript/js%E5%AE%9E%E7%8E%B0%E7%AE%80%E5%8D%95%E7%89%88%E7%9A%84EventBus%E5%AE%9E%E4%BE%8B.html"/>
    <id>http://pimichen.com/blog/javascript/js实现简单版的EventBus实例.html</id>
    <published>2020-03-21T16:00:00.000Z</published>
    <updated>2020-03-21T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<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><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">在vue中，可以利用EventBus来派发和接收事件</span><br><span class="line"></span><br><span class="line"><span class="comment"># eventBus.js:</span></span><br><span class="line">import Vue from <span class="string">'vue'</span>;</span><br><span class="line"><span class="built_in">let</span> eventHub = new Vue();</span><br><span class="line"><span class="built_in">export</span> default eventHub;</span><br><span class="line"></span><br><span class="line"><span class="comment"># a.vue</span></span><br><span class="line">import eventBus from <span class="string">'../js/eventBus'</span></span><br><span class="line">eventHub.<span class="variable">$on</span>(<span class="string">'event'</span>, (data) =&gt; &#123;&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment"># b.vue</span></span><br><span class="line">import eventBus from <span class="string">'../js/eventBus'</span></span><br><span class="line">eventHub.<span class="variable">$emit</span>(<span class="string">'event'</span>, data);</span><br><span class="line"></span><br><span class="line">设计模式：</span><br><span class="line">  订阅者发布者模式（也称观察者模式），这种设计模式在前端很常见。一般来说：先订阅（on），再发布（emit）</span><br><span class="line">  DOM事件也是一个订阅发布模式</span><br><span class="line">    订阅：DOM.addEventListener(<span class="string">'click'</span>, <span class="function"><span class="title">function</span></span> () &#123; &#125;)</span><br><span class="line">    发布：一个点击事件</span><br><span class="line"></span><br><span class="line">如何手动实现简单版的EventBus实例：</span><br><span class="line">  API的设计：</span><br><span class="line">    on(<span class="string">'event'</span>, fn)    订阅消息（event: 订阅的消息名称、fn: 订阅的消息）</span><br><span class="line">    once(<span class="string">'event'</span>, fn)  仅订阅一次消息，一旦被执行立即销毁</span><br><span class="line">    emit(<span class="string">'event'</span>, msg) 发布消息（event: 消息名称、msg: 发布的消息）</span><br><span class="line">    off(<span class="string">'event'</span>)       移除消息（不传参数: 销毁所有消息）</span><br></pre></td></tr></table></figure><blockquote><p>参考：<a href="https://cn.vuejs.org/v2/api/#vm-on" target="_blank" rel="noopener">Vue $on api</a></p></blockquote><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// es5实现eventBus实例</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 简易版如下：</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">EventBusClass</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.eventObj = &#123;&#125; <span class="comment">// 管理事件</span></span><br><span class="line">&#125;</span><br><span class="line">EventBusClass.prototype = &#123;</span><br><span class="line">  <span class="comment">// 订阅消息</span></span><br><span class="line">  on: <span class="function"><span class="keyword">function</span> (<span class="params">event, fn</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> vm = <span class="keyword">this</span></span><br><span class="line">    <span class="keyword">this</span>.eventObj[event] = fn</span><br><span class="line">    <span class="keyword">return</span> vm</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 订阅消息，派发一次后即销毁</span></span><br><span class="line">  once: <span class="function"><span class="keyword">function</span> (<span class="params">event, fn</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> vm = <span class="keyword">this</span></span><br><span class="line">    <span class="comment">// 思考：如何在执行完fn之后销毁该event呢，需要重新构造一个新的fn</span></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">fn2</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">      fn.apply(vm, <span class="built_in">arguments</span>) <span class="comment">// 如果使用fn()，则无法接收参数</span></span><br><span class="line">      <span class="comment">// delete this.eventObj[event] // 重复性处理，建议直接使用写好的方法</span></span><br><span class="line">      vm.off(event)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// this.eventObj[event] = fn2</span></span><br><span class="line">    vm.on(event, fn2)</span><br><span class="line">    <span class="keyword">return</span> vm</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 发布消息</span></span><br><span class="line">  emit: <span class="function"><span class="keyword">function</span> (<span class="params">event, msg</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> vm = <span class="keyword">this</span></span><br><span class="line">    <span class="comment">// 未订阅的忽略</span></span><br><span class="line">    <span class="keyword">if</span> (!<span class="keyword">this</span>.eventObj.hasOwnProperty(event)) <span class="keyword">return</span> vm</span><br><span class="line">    <span class="keyword">this</span>.eventObj[event](msg)</span><br><span class="line">    <span class="keyword">return</span> vm</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 销毁消息（不传销毁所有）</span></span><br><span class="line">  off: <span class="function"><span class="keyword">function</span> (<span class="params">event</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> vm = <span class="keyword">this</span></span><br><span class="line">    <span class="keyword">if</span> (event === <span class="literal">undefined</span>) &#123;</span><br><span class="line">      <span class="keyword">this</span>.eventObj = &#123;&#125;</span><br><span class="line">      <span class="keyword">return</span> vm</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 未订阅的忽略</span></span><br><span class="line">    <span class="keyword">if</span> (!<span class="keyword">this</span>.eventObj.hasOwnProperty(event)) <span class="keyword">return</span> vm</span><br><span class="line">    <span class="keyword">delete</span> <span class="keyword">this</span>.eventObj[event]</span><br><span class="line">    <span class="keyword">return</span> vm</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>ES6实现按照下列结构改造即可<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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EventBusClass2</span> </span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span> () &#123;</span><br><span class="line">    <span class="keyword">this</span>.eventObj = &#123;&#125;</span><br><span class="line">  &#125;</span><br><span class="line">  on (event, fn) &#123;</span><br><span class="line">  &#125;</span><br><span class="line">  once (event, fn) &#123;</span><br><span class="line">  &#125;</span><br><span class="line">  emit (event, msg) &#123;</span><br><span class="line">  &#125;</span><br><span class="line">  off (event) &#123;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>测试：<br><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><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="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">"on_a()"</span>&gt;</span>订阅A事件<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">"on_b()"</span>&gt;</span>订阅B事件<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">"once_a()"</span>&gt;</span>订阅A事件一次<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">"once_b()"</span>&gt;</span>订阅B事件一次<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">"emit_a()"</span>&gt;</span>派发A事件<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">"emit_b()"</span>&gt;</span>派发B事件<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">"off()"</span>&gt;</span>销毁A<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">"off_all()"</span>&gt;</span>销毁所有<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">"chain()"</span>&gt;</span>链式调用：订阅A事件，派发A事件<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br></pre></td></tr></table></figure></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><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> EventBus = <span class="keyword">new</span> EventBusClass()</span><br><span class="line"><span class="comment">// 订阅</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">on_a</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  EventBus.on(<span class="string">'click'</span>, (data) =&gt; &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(data)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">on_b</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  EventBus.on(<span class="string">'dbClick'</span>, (data) =&gt; &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(data)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 订阅一次</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">once_a</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  EventBus.once(<span class="string">'click'</span>, (data) =&gt; &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(data)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">once_b</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  EventBus.once(<span class="string">'dbClick'</span>, (data) =&gt; &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(data)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 发布</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">emit_a</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  EventBus.emit(<span class="string">'click'</span>, &#123;<span class="attr">a</span>: <span class="number">1</span>&#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">emit_b</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  EventBus.emit(<span class="string">'dbClick'</span>, &#123;<span class="attr">b</span>: <span class="number">1</span>&#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 销毁</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">off</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  EventBus.off(<span class="string">'click'</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">off_all</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  EventBus.off()</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 链式调用</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">chain</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  EventBus</span><br><span class="line">    .on(<span class="string">'mouseup'</span>, (data) =&gt; &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(data)</span><br><span class="line">    &#125;)</span><br><span class="line">    .emit(<span class="string">'mouseup'</span>, &#123;<span class="attr">c</span>: <span class="number">1</span>&#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>以上只实现了一个简易版的EventBus，更多的参数支持和复杂情况未作处理，详细实现可查看<a href="https://github.com/vuejs/vue/blob/dev/src/core/instance/events.js" target="_blank" rel="noopener">Vue源码 eventsMixin方法</a></p>]]></content>
    
    <summary type="html">
    
      js手动实现简单版的EventBus实例，包含on、once、emit、off等方法
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://pimichen.com/blog/tags/javascript/"/>
    
  </entry>
  
</feed>
