{"componentChunkName":"component---src-templates-blog-post-js","path":"/2020-05-31-rxjs-src/Rxjs/","result":{"data":{"site":{"siteMetadata":{"title":"Howard's Note","disqusShortname":""}},"markdownRemark":{"id":"5d2b625c-a517-506d-a729-1de6b8cdeee1","html":"<h2>achieve</h2>\n<p> 此篇內容做為個人學習記錄，不會再更改。</p>\n<p> 學習 <code class=\"language-text\">haskell</code>後，發現更重要的其實是函式編程的思考方式。</p>\n<p> 如果真的理解函式做為一級公民的思考邏輯， <code class=\"language-text\">rxjs</code> 的實現看起來就會非常自然、直覺。</p>\n<p> 當初寫這篇學習記錄時，並不懂fp的思考方式。</p>\n<p> 因此，下面的記錄比較像是逐行記錄動作、及 ts特性，並沒有真正解釋 rxjs 的實作目的。</p>\n<p> 2020/09/16</p>\n<hr>\n<p>目的：看懂<code class=\"language-text\">Rxjs</code>的<code class=\"language-text\">Observable</code>實現方式</p>\n<h2>Rxjs的流程圖</h2>\n<p>Rxjs是一個實作了 <code class=\"language-text\">觀察者模式</code>、<code class=\"language-text\">疊代器模式</code>的library。</p>\n<p>根據 ReactiveX 官網所述：</p>\n<blockquote>\n<p>Observables fill the gap by being the ideal way to access asynchronous sequences of multiple items</p>\n</blockquote>\n<table>\n<thead>\n<tr>\n<th align=\"center\">#</th>\n<th align=\"center\">single items</th>\n<th align=\"center\">multiple items</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td align=\"center\">synchronus</td>\n<td align=\"center\"><code class=\"language-text\">T getData()</code></td>\n<td align=\"center\"><code class=\"language-text\">Iterable&lt;T> getData()</code></td>\n</tr>\n<tr>\n<td align=\"center\">asynchronous</td>\n<td align=\"center\"><code class=\"language-text\">Future&lt;T> getData()</code></td>\n<td align=\"center\"><code class=\"language-text\">Observable&lt;T> getData()</code></td>\n</tr>\n</tbody>\n</table>\n<p>ReactiveX 填補了疊代器模式無法支援非同步旨令的問題。</p>\n<p>事實上，我在理解原始碼的時候有發現，雖然Rxjs的確有實現 <code class=\"language-text\">觀察者模式</code>，但是當你在看程式碼的時候，將它當作一個變型的<code class=\"language-text\">疊代器模式</code>，反而更容易理解。</p>\n<p>那麼我們就先從一個流程圖及簡單的範例開始吧。</p>\n<p>以下是我們使用 Rxjs的時候，最典型的流程。</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/71f5b60b87810e54ac9ceabbe6b6fea6/077b7/flowchart.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 17.088607594936708%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAkklEQVQI102OiQqDMAyGff/3m1pFxpjCGPZynZ3W9l8SZCwk5PhyVa8Q4ZyHPU0bi3fcwRLWDbO2MFQz1gmPW0I6ijDOZ22E+SVgTxnVEj64jxNa1eFSNxiuN1qYZKEnprpBWN20FPdwy4ojA0/t0bSKWC9+nB7Y6VB15AJSMVLxXGPJJ+Psx2iolCJf/jM+wv1fe7DmQJD9LlMAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"流程圖\"\n        title=\"流程圖\"\n        src=\"/static/71f5b60b87810e54ac9ceabbe6b6fea6/f058b/flowchart.png\"\n        srcset=\"/static/71f5b60b87810e54ac9ceabbe6b6fea6/c26ae/flowchart.png 158w,\n/static/71f5b60b87810e54ac9ceabbe6b6fea6/6bdcf/flowchart.png 315w,\n/static/71f5b60b87810e54ac9ceabbe6b6fea6/f058b/flowchart.png 630w,\n/static/71f5b60b87810e54ac9ceabbe6b6fea6/40601/flowchart.png 945w,\n/static/71f5b60b87810e54ac9ceabbe6b6fea6/077b7/flowchart.png 1166w\"\n        sizes=\"(max-width: 630px) 100vw, 630px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<hr>\n<p>我直接從 Anuglar 官網引用簡單的範例：</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// Create simple observable that emits three values</span>\n<span class=\"token keyword\">const</span> myObservable <span class=\"token operator\">=</span> <span class=\"token keyword\">of</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">,</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token number\">3</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Create observer object</span>\n<span class=\"token keyword\">const</span> myObserver <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function-variable function\">next</span><span class=\"token operator\">:</span> <span class=\"token parameter\">x</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Observer got a next value: '</span> <span class=\"token operator\">+</span> x<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function-variable function\">error</span><span class=\"token operator\">:</span> <span class=\"token parameter\">err</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Observer got an error: '</span> <span class=\"token operator\">+</span> err<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function-variable function\">complete</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Observer got a complete notification'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Execute with the observer object</span>\nmyObservable<span class=\"token punctuation\">.</span><span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span>myObserver<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">// Logs:</span>\n<span class=\"token comment\">// Observer got a next value: 1</span>\n<span class=\"token comment\">// Observer got a next value: 2</span>\n<span class=\"token comment\">// Observer got a next value: 3</span>\n<span class=\"token comment\">// Observer got a complete notification</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">code 1</code> 使用 <code class=\"language-text\">of</code> 運算子產生 <code class=\"language-text\">Observable</code> 並訂閱。</li>\n</ul>\n<hr>\n<p>另外，如果你不想要使用 <code class=\"language-text\">Operator</code> 建立 <code class=\"language-text\">Observable</code>的話，你可以直接 new一個 <code class=\"language-text\">Obsevrable</code> 實例，並且將訂閱後會發出值使用 <code class=\"language-text\">callback function</code> 的方式傳入 <code class=\"language-text\">Observable</code> 中。</p>\n<blockquote>\n<p>實務上是不會這麼使用的。在實務上，可以使用 <code class=\"language-text\">of</code>這類的 creation operator 產生一個最簡單的Observable。而其內部的實現方式，其實就是回傳一個會固定發出 <code class=\"language-text\">of</code> 參數的 <code class=\"language-text\">Observable</code>，</p>\n</blockquote>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// This function runs when subscribe() is called</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">sequenceSubscriber</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">observer</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// synchronously deliver 1, 2, and 3, then complete</span>\n  observer<span class=\"token punctuation\">.</span><span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  observer<span class=\"token punctuation\">.</span><span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  observer<span class=\"token punctuation\">.</span><span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token number\">3</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  observer<span class=\"token punctuation\">.</span><span class=\"token function\">complete</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">// unsubscribe function doesn't need to do anything in this</span>\n  <span class=\"token comment\">// because values are delivered synchronously</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span><span class=\"token function\">unsubscribe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// Create a new Observable that will deliver the above sequence</span>\n<span class=\"token keyword\">const</span> sequence <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Observable</span><span class=\"token punctuation\">(</span>sequenceSubscriber<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// execute the Observable and print the result of each notification</span>\nsequence<span class=\"token punctuation\">.</span><span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">num</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>num<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function\">complete</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Finished sequence'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Logs:</span>\n<span class=\"token comment\">// 1</span>\n<span class=\"token comment\">// 2</span>\n<span class=\"token comment\">// 3</span>\n<span class=\"token comment\">// Finished sequence</span></code></pre></div>\n<p><code class=\"language-text\">code 2</code> 建立 一個 <code class=\"language-text\">Observable</code> 物件。</p>\n<p>這樣我們已經知道最基本的使用方式了。接著我們看看 Rxjs 中最核心的兩個組件：<code class=\"language-text\">Observable</code> 與 <code class=\"language-text\">Observer</code>。</p>\n<h2>Observable</h2>\n<p>Observable 是 Rxjs 中最核心的物件。</p>\n<p>我剛開始看<code class=\"language-text\">Observable</code>的實現方式時，旁邊放著 <code class=\"language-text\">觀察者模式</code> 的 類別圖。</p>\n<p>然後我看的很困惑。所以我不建議使用觀察者模式對應Rxjs實作。</p>\n<p>截取重要的幾段程式碼：</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">Observable</span><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token keyword\">implements</span> <span class=\"token class-name\">Subscribable</span><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span>\n\n  <span class=\"token comment\">/** Internal implementation detail, do not use directly. */</span>\n  <span class=\"token keyword\">public</span> <span class=\"token literal-property property\">_isScalar</span><span class=\"token operator\">:</span> boolean <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">/** @deprecated This is an internal implementation detail, do not use. */</span>\n  <span class=\"token literal-property property\">source</span><span class=\"token operator\">:</span> Observable<span class=\"token operator\">&lt;</span>any<span class=\"token operator\">></span> <span class=\"token operator\">|</span> <span class=\"token keyword\">undefined</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">/** @deprecated This is an internal implementation detail, do not use. */</span>\n  <span class=\"token literal-property property\">operator</span><span class=\"token operator\">:</span> Operator<span class=\"token operator\">&lt;</span>any<span class=\"token punctuation\">,</span> <span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token operator\">|</span> <span class=\"token keyword\">undefined</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">/**\n   * @constructor\n   * @param {Function} subscribe the function that is called when the Observable is\n   * initially subscribed to. This function is given a Subscriber, to which new values\n   * can be `next`ed, or an `error` method can be called to raise an error, or\n   * `complete` can be called to notify of a successful completion.\n   */</span>\n  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span>subscribe<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token keyword\">this</span><span class=\"token operator\">:</span> Observable<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">subscriber</span><span class=\"token operator\">:</span> Subscriber<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> TeardownLogic<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>subscribe<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>_subscribe <span class=\"token operator\">=</span> subscribe<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token comment\">// .... 中間略</span>\n\n  <span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span>observer<span class=\"token operator\">?</span><span class=\"token operator\">:</span> PartialObserver<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> Subscription<span class=\"token punctuation\">;</span>\n  <span class=\"token comment\">/** @deprecated Use an observer instead of a complete callback */</span>\n  <span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span>next<span class=\"token operator\">:</span> <span class=\"token keyword\">null</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">undefined</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">error</span><span class=\"token operator\">:</span> <span class=\"token keyword\">null</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">undefined</span><span class=\"token punctuation\">,</span> <span class=\"token function-variable function\">complete</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> Subscription<span class=\"token punctuation\">;</span>\n  <span class=\"token comment\">/** @deprecated Use an observer instead of an error callback */</span>\n  <span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span>next<span class=\"token operator\">:</span> <span class=\"token keyword\">null</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">undefined</span><span class=\"token punctuation\">,</span> <span class=\"token function-variable function\">error</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">error</span><span class=\"token operator\">:</span> any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">,</span> complete<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> Subscription<span class=\"token punctuation\">;</span>\n  <span class=\"token comment\">/** @deprecated Use an observer instead of a complete callback */</span>\n  <span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span><span class=\"token function-variable function\">next</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">value</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">error</span><span class=\"token operator\">:</span> <span class=\"token keyword\">null</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">undefined</span><span class=\"token punctuation\">,</span> <span class=\"token function-variable function\">complete</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> Subscription<span class=\"token punctuation\">;</span>\n  <span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span>next<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">value</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">,</span> error<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">error</span><span class=\"token operator\">:</span> any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">,</span> complete<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> Subscription<span class=\"token punctuation\">;</span>\n\n  <span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span>observerOrNext<span class=\"token operator\">?</span><span class=\"token operator\">:</span> PartialObserver<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token operator\">|</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">value</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span>\n            error<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">error</span><span class=\"token operator\">:</span> any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span>\n            complete<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> Subscription <span class=\"token punctuation\">{</span>\n\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> operator <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> sink <span class=\"token operator\">=</span> <span class=\"token function\">toSubscriber</span><span class=\"token punctuation\">(</span>observerOrNext<span class=\"token punctuation\">,</span> error<span class=\"token punctuation\">,</span> complete<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>operator<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      sink<span class=\"token punctuation\">.</span><span class=\"token function\">add</span><span class=\"token punctuation\">(</span><span class=\"token function\">operator</span><span class=\"token punctuation\">.</span><span class=\"token function\">call</span><span class=\"token punctuation\">(</span>sink<span class=\"token punctuation\">,</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>source<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n      sink<span class=\"token punctuation\">.</span><span class=\"token function\">add</span><span class=\"token punctuation\">(</span>\n        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>source <span class=\"token operator\">||</span> <span class=\"token punctuation\">(</span>config<span class=\"token punctuation\">.</span>useDeprecatedSynchronousErrorHandling <span class=\"token operator\">&amp;&amp;</span> <span class=\"token operator\">!</span>sink<span class=\"token punctuation\">.</span>syncErrorThrowable<span class=\"token punctuation\">)</span> <span class=\"token operator\">?</span>\n        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">_subscribe</span><span class=\"token punctuation\">(</span>sink<span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span>\n        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">_trySubscribe</span><span class=\"token punctuation\">(</span>sink<span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>config<span class=\"token punctuation\">.</span>useDeprecatedSynchronousErrorHandling<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>sink<span class=\"token punctuation\">.</span>syncErrorThrowable<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        sink<span class=\"token punctuation\">.</span>syncErrorThrowable <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>sink<span class=\"token punctuation\">.</span>syncErrorThrown<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">throw</span> sink<span class=\"token punctuation\">.</span>syncErrorValue<span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">return</span> sink<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token comment\">// ... （略）</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">code 3</code>. <code class=\"language-text\">Observable</code> 程式碼。</li>\n</ul>\n<p>不論 <code class=\"language-text\">pipe</code> 與 <code class=\"language-text\">Operator</code> 的話，整個 <code class=\"language-text\">Observable</code>的重點，其實就是 <code class=\"language-text\">subscribe</code>函式。</p>\n<hr>\n<blockquote>\n<p>Ts 筆記</p>\n<p>code 3 中，建構子使用了 <code class=\"language-text\">function type</code> 的寫法（第19行），定義了 傳入的 function 的參數及 return 的型態。\n另外，<code class=\"language-text\">function type</code>的第一個參數可以放 <code class=\"language-text\">this</code>，它可以限制 <code class=\"language-text\">function</code> 的 <code class=\"language-text\">this</code> 型態。\n（因此，此函式不能使用 <code class=\"language-text\">arrow function</code>）</p>\n<p>底線是一個常用的命名規則（21行，_subscribe屬性），代表變數或屬性是內部屬性。</p>\n<p><del><code class=\"language-text\">subscribe</code> 使用了 <code class=\"language-text\">ts</code> 函式多載的功能（27行 ~ 36行）。<code class=\"language-text\">ts</code>支援函式多載，\n唯一的限制是，<code class=\"language-text\">參數的個數必須要相同</code>。\n因此可以注意到，<code class=\"language-text\">subscibe</code>的所有參數都是 <code class=\"language-text\">optional parameter</code>。</del></p>\n<p>跟 <code class=\"language-text\">java</code> 等語言不一樣。 ts 底層其實還是js。因此與其說它是函式多載，不如說它可以定義多個函式簽名。\n在 copmile階段，編譯器會選擇最適合的函式簽名來檢查。\n<a href=\"https://www.typescriptlang.org/docs/handbook/functions.html#overloads\">refer to</a></p>\n<p>@deprecated 是軟體中很常使用的標籤（38行），代表被棄用的function。不論是公開的 Api 或者是 內部的 Api 都非常的好用。</p>\n</blockquote>\n<hr>\n<p>看到 Subscribe 的第一一個參數，它可以是一個 <code class=\"language-text\">PartialObserver&lt;T></code> 或者是一個 <code class=\"language-text\">function</code>。 </p>\n<p>看一下 PartialObserver<T>的定義：</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">interface</span> <span class=\"token class-name\">NextObserver</span><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span>\n  closed<span class=\"token operator\">?</span><span class=\"token operator\">:</span> boolean<span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">next</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">value</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n  error<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">err</span><span class=\"token operator\">:</span> any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n  complete<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">interface</span> <span class=\"token class-name\">ErrorObserver</span><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span>\n  closed<span class=\"token operator\">?</span><span class=\"token operator\">:</span> boolean<span class=\"token punctuation\">;</span>\n  next<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">value</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">error</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">err</span><span class=\"token operator\">:</span> any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n  complete<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">interface</span> <span class=\"token class-name\">CompletionObserver</span><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span>\n  closed<span class=\"token operator\">?</span><span class=\"token operator\">:</span> boolean<span class=\"token punctuation\">;</span>\n  next<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">value</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n  error<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">err</span><span class=\"token operator\">:</span> any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">complete</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> type PartialObserver<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token operator\">=</span> NextObserver<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token operator\">|</span> ErrorObserver<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token operator\">|</span> CompletionObserver<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span><span class=\"token punctuation\">;</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">code 4</code>. Observer interface </li>\n</ul>\n<p>其實，PartialObserver 就是 <code class=\"language-text\">Observer</code>介面的別名，只是三個function中，你至少要定義其中一個。</p>\n<h2>Observer 及 Subscriber</h2>\n<p>Observer 其實是 Rxjs定義的界面。</p>\n<p>定義界面的好處之一，是可以規範程式的 input 的規格。</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">interface</span> <span class=\"token class-name\">Observer</span><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span>\n  closed<span class=\"token operator\">?</span><span class=\"token operator\">:</span> boolean<span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">next</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">value</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">error</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">err</span><span class=\"token operator\">:</span> any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">complete</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><code class=\"language-text\">code 5</code>、Observer</p>\n<p>另外，<code class=\"language-text\">Subscriber</code> 是個物件，它實現了 <code class=\"language-text\">Observer</code> 、並且繼承了 <code class=\"language-text\">Subscription</code>。現在只要知道，<code class=\"language-text\">Subscriber</code> 多了 取消訂閱的能力就好 （<code class=\"language-text\">unsubscribe()</code> 方法）。</p>\n<hr>\n<p>我們繼續看 <code class=\"language-text\">code 3</code> 。</p>\n<p>code 3第19行~23行。它的建構子其實很單純，就是把傳入的<code class=\"language-text\">Subscriber function</code> 放入一個內部的 <code class=\"language-text\">_subscribe</code>屬性。這部份的使用案例可以對應 <code class=\"language-text\">code 2</code> 看。</p>\n<p>接著看到 <code class=\"language-text\">subscribe()</code> 函式。</p>\n<p>code 3，41行。首先會透過 toSubscriber() 這個 utils 將 傳入的 Observer轉變成 Subscriber 。</p>\n<p>前面提到，在 Rxjs的內部實現中，會把所有的 Observer界面，轉化為 Subscriber 物件，提供訂閱及取消訂閱的能力。</p>\n<blockquote>\n<p>utils 放全域的 function，也是軟體中很常見的專案架構（code 3，41行）。</p>\n</blockquote>\n<p>code 3，43~51行。接著，如果你是透過 <code class=\"language-text\">creation operator</code> 產生的 <code class=\"language-text\">observable</code>，<code class=\"language-text\">subscribe()</code>函式會呼叫這個 <code class=\"language-text\">Operator</code>（對應 <code class=\"language-text\">code 1</code>。</p>\n<p>如果不是的話，會試著去執行 <code class=\"language-text\">_subscribe</code> （對應 <code class=\"language-text\">code2</code>）。</p>\n<p>code 3，53~60行。最下面的 if、else，控制 throw exception 。因為新版建議使用 <code class=\"language-text\">Observer</code>界面，取代將 <code class=\"language-text\">subscribe</code> 包在 <code class=\"language-text\">try...catch</code>中，因此這裡會檢查lib的 config檔的flag有沒有被打開；</p>\n<p>如果有的話，再檢查是否有遇到例外需要<code class=\"language-text\">throw</code>回主函式的情型。</p>\n<hr>\n<h2>結論</h2>\n<p>從 <code class=\"language-text\">Observable</code> 的 <code class=\"language-text\">subscribe()</code> 中，可以了解到，<code class=\"language-text\">Obsrevable</code>的 <code class=\"language-text\">subscribe()</code> 要發出的值有兩個來源：要馬是你 new 一個 Observable，並且把 <code class=\"language-text\">subscribe</code>、及 <code class=\"language-text\">unsubscribe</code> 的邏輯傳入；要馬是使用 <code class=\"language-text\">Operator</code> 來發出值。</p>\n<p>使用情境來看，後者應該是更常見的情境。</p>\n<p>另外，內部會將<code class=\"language-text\">Observer</code>轉成 <code class=\"language-text\">Subscriber</code>，是非常重要的一步。有了它，它有辦法實作 <code class=\"language-text\">pipe</code>。</p>\n<p> <code class=\"language-text\">觀察者模式</code>，通常是異步的，也不會有 <code class=\"language-text\">Observable</code> 、<code class=\"language-text\">Operator</code>等物件。因此我開頭才說，最好不要用 <code class=\"language-text\">觀察者模式</code> 對應了解Rxjs的實作，否則只會越看越糊塗。</p>\n<p> 以目前看到的行為來說，<code class=\"language-text\">Observable</code> 更接近 <code class=\"language-text\">疊代器模式</code>。</p>","frontmatter":{"title":"rxjs source trace","date":"May 30, 2020","description":"trace rxjs source。","tags":["achieve","javascript"],"template":"post"}}},"pageContext":{"slug":"/2020-05-31-rxjs-src/Rxjs/","previous":{"node":{"fields":{"slug":"/2020-05-28/"},"frontmatter":{"date":"28 May, 2020","title":"RXJS運算子-mergeMap、switchMap","tags":["rxjs","archive"]}}},"next":{"node":{"fields":{"slug":"/2020-10-16--Ref_note.md/2020-10-16--Ref_note/"},"frontmatter":{"date":"16 October, 2020","title":"rust RefCell、Cell筆記","tags":["rust","archive"]}}}}},"staticQueryHashes":["2841359383","3810545343","916993862"]}