<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Loker&#39;s blog</title>
  
  
  <link href="http://example.com/atom.xml" rel="self"/>
  
  <link href="http://example.com/"/>
  <updated>2021-02-21T08:31:00.827Z</updated>
  <id>http://example.com/</id>
  
  <author>
    <name>Loker</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>C++_内存管理</title>
    <link href="http://example.com/2021/02/21/c-memory-manage/"/>
    <id>http://example.com/2021/02/21/c-memory-manage/</id>
    <published>2021-02-21T06:39:41.000Z</published>
    <updated>2021-02-21T08:31:00.827Z</updated>
    
    <content type="html"><![CDATA[<h1 id="C-内存管理"><a href="#C-内存管理" class="headerlink" title="C++内存管理"></a>C++内存管理</h1><p>C++ 内存分区：栈、堆、全局/静态存储区、常量存储区、代码区。</p><p><strong>栈</strong>：存放函数的局部变量、函数参数、返回地址等，由编译器自动分配和释放。<br><strong>堆</strong>：动态申请的内存空间，就是由 malloc 分配的内存块，由程序员控制它的分配和释放，如果程序执行结束还没有释放，操作系统会自动回收。<br><strong>全局区/静态存储区</strong>（.bss 段和 .data 段）：存放全局变量和静态变量，程序运行结束操作系统自动释放，在 C 语言中，未初始化的放在 .bss 段中，初始化的放在 .data 段中，C++ 中不再区分了。<br><strong>常量存储区</strong>（.data 段）：存放的是常量，不允许修改，程序运行结束自动释放。<br><strong>代码区</strong>（.text 段）：存放代码，不允许修改，但可以执行。编译后的二进制文件存放在这里。</p><a id="more"></a><h2 id="栈和堆的区别"><a href="#栈和堆的区别" class="headerlink" title="栈和堆的区别"></a>栈和堆的区别</h2><p>栈是由操作系统自动创建，堆是可以由程序员来进行控制</p><p>通常在程序中声明一个变量 如 </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">int fun1()</span><br><span class="line">&#123;</span><br><span class="line">    int a &#x3D; 0;</span><br><span class="line">    int *b &#x3D; new int[];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这个变量a就是被创建在栈上，而这个变量b就是被创建在堆上。</p><p>栈是由大小限制的，一般来说编译器的默认大小是1M，如果申请的变量过大，有可能造成栈溢出，即StackOverFlow，不过这个大小可以通过配置修改扩大。堆一般就是内存的大小，一般创建在堆上的变量在使用完成后需要程序员自行进行回收，否则会出现不可预知的错误。</p><h1 id="内存对齐"><a href="#内存对齐" class="headerlink" title="内存对齐"></a>内存对齐</h1><p>C++内存按照编译器的设置，按照内存块来存储的，这个内存块大小的取值，就是内存对齐。</p><p>如</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><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">struct foo</span><br><span class="line">&#123;</span><br><span class="line">    char a; &#x2F;&#x2F;1 byte</span><br><span class="line">    int b ; &#x2F;&#x2F; 4 byte</span><br><span class="line">    short c; &#x2F;&#x2F; 2 byte</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>sizeof(foo)的大小是12,编译器会将char和short的大小和int的大小进行对齐。</p><p>1、第一个数据成员放在offset为0的地方，以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中，比较小的那个进行。</p><p>2、在数据成员完成各自对齐之后，类(结构或联合)本身也要进行对齐，对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中，比较小的那个进行。</p><p>很明显#pragma pack(n)作为一个预编译指令用来设置多少个字节对齐的。值得注意的是，n的缺省数值是按照编译器自身设置，一般为8，合法的数值分别是1、2、4、8、16。<br>即编译器只会按照1、2、4、8、16的方式分割内存。若n为其他值，是无效的。</p><p>所以如果</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><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">#pragma pack(1)&#x2F;&#x2F;设定为 1 字节对齐</span><br><span class="line">struct foo</span><br><span class="line">&#123;</span><br><span class="line">    char a; &#x2F;&#x2F;1 byte</span><br><span class="line">    int b ; &#x2F;&#x2F; 4 byte</span><br><span class="line">    short c; &#x2F;&#x2F; 2 byte</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这时sizeof(foo)的大小就是7字节</p>]]></content>
    
    
    <summary type="html">&lt;h1 id=&quot;C-内存管理&quot;&gt;&lt;a href=&quot;#C-内存管理&quot; class=&quot;headerlink&quot; title=&quot;C++内存管理&quot;&gt;&lt;/a&gt;C++内存管理&lt;/h1&gt;&lt;p&gt;C++ 内存分区：栈、堆、全局/静态存储区、常量存储区、代码区。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;栈&lt;/strong&gt;：存放函数的局部变量、函数参数、返回地址等，由编译器自动分配和释放。&lt;br&gt;&lt;strong&gt;堆&lt;/strong&gt;：动态申请的内存空间，就是由 malloc 分配的内存块，由程序员控制它的分配和释放，如果程序执行结束还没有释放，操作系统会自动回收。&lt;br&gt;&lt;strong&gt;全局区/静态存储区&lt;/strong&gt;（.bss 段和 .data 段）：存放全局变量和静态变量，程序运行结束操作系统自动释放，在 C 语言中，未初始化的放在 .bss 段中，初始化的放在 .data 段中，C++ 中不再区分了。&lt;br&gt;&lt;strong&gt;常量存储区&lt;/strong&gt;（.data 段）：存放的是常量，不允许修改，程序运行结束自动释放。&lt;br&gt;&lt;strong&gt;代码区&lt;/strong&gt;（.text 段）：存放代码，不允许修改，但可以执行。编译后的二进制文件存放在这里。&lt;/p&gt;</summary>
    
    
    
    <category term="面试" scheme="http://example.com/categories/%E9%9D%A2%E8%AF%95/"/>
    
    <category term="内存管理" scheme="http://example.com/categories/%E9%9D%A2%E8%AF%95/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/"/>
    
    
    <category term="C++ memory" scheme="http://example.com/tags/C-memory/"/>
    
  </entry>
  
  <entry>
    <title>C++编译过程</title>
    <link href="http://example.com/2021/02/18/c-1-compile/"/>
    <id>http://example.com/2021/02/18/c-1-compile/</id>
    <published>2021-02-18T04:59:36.000Z</published>
    <updated>2021-02-21T06:38:04.321Z</updated>
    
    <content type="html"><![CDATA[<h1 id="C-编译过程"><a href="#C-编译过程" class="headerlink" title="C++编译过程"></a>C++编译过程</h1><p>一般的C++程序在编译过程中需要进行如下四步：</p><p><strong>预处理(Preprocessing)</strong><br>预处理用于将所有的#include头文件以及宏定义替换成其真正的内容，预处理之后得到的仍然是文本文件，但文件体积会大很多</p><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">gcc -E -I.&#x2F;inc test.c -o test.i</span><br></pre></td></tr></table></figure><p>上述命令中-E是让编译器在预处理之后就退出，不进行后续编译过程；-I指定头文件目录，这里指定的是我们自定义的头文件目录；-o指定输出文件名。<br><strong>编译(Compilation)</strong><br>编译不是指程序从源文件到二进制程序的全部过程，而是指将经过预处理之后的程序转换成特定汇编代码(assembly code)的过程。编译的指定如下：</p><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">gcc -S -I.&#x2F;inc test.c -o test.s</span><br></pre></td></tr></table></figure><p>上述命令中-S让编译器在编译之后停止，不进行后续过程。编译过程完成后，将生成程序的汇编代码test.s，这也是文本文件，内容如下：<br><strong>汇编(Assemble)</strong><br>汇编过程将上一步的汇编代码转换成机器码，产生的文件叫做目标文件，是二进制格式。gcc汇编过程通过as命令完成：</p><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">as test.s -o test.o</span><br></pre></td></tr></table></figure><p>等价于</p><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">gcc -c test.s -o test.o</span><br></pre></td></tr></table></figure><p><strong>链接(Linking)</strong><br>链接过程将多个目标文件以及所需的库文件(.so等)链接成最终的可执行文件</p><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">ld -o test.out test.o inc&#x2F;mymath.o ...libraries...</span><br></pre></td></tr></table></figure><a id="more"></a><h1 id="为啥是a-out-？"><a href="#为啥是a-out-？" class="headerlink" title="为啥是a.out ？"></a>为啥是a.out ？</h1><p>如果你编写完hello.cpp后，直接使用 gcc hello.c进行编译，你会得到一个a.out程序。<br>那是由于a.out是”assembler output”的缩写格式，代表汇编程序输出。在较早版本的类unix系统中，a.out是一种输出格式，用于可执行文件，目标文件和共享库。早期的 PDP-7系统上没有链接器，程序的创建过程是先把所有源文件连接成一个文件，然后进行汇编，产生的汇编程序保存在a.out中。这样a.out是名副其实的汇编输出，但到PDP-11之后，人们为其编写了链接器，程序的创建是先编译然后链接输出保存到a.out中，这时a.out其实已经是链接输出了，但输出的可执行文件仍然延续这个命名习惯。<br>Unix中的可执行文件用一种特殊的方式加上标签，这样便于系统确认它们的属性。普遍采用的方式是使用独特的数字，这些数字也被称为“神秘”数字。一个例子是，Unix文件系统中的superblock就是用下面的数字做标签：<br>后来，因为构建a.out的复杂性，a.out格式被现在普遍使用的ELF格式所替代，但输出文件名仍旧是a.out。现在我们看到的a.out只是一个可执行文件，而不再是文件格式。ELF可执行文件的第一个字节是八进制177也就是16进制的7F，紧跟其后的2,3,4字节是ELF三个字母。你可以输入od -c a.out | head查看。</p><h1 id="链接-Linking"><a href="#链接-Linking" class="headerlink" title="链接(Linking)"></a>链接(Linking)</h1><p>最终链接分为 <strong>静态链接</strong> 和 <strong>动态链接</strong><br>静态链接：代码从其所在的静态链接库中拷贝到最终的可执行程序中，在该程序被执行时，这些代码会被装入到该进程的虚拟地址空间中。<br>动态链接：代码被放到动态链接库或共享对象的某个目标文件中，链接程序只是在最终的可执行程序中记录了共享对象的名字等一些信息。在程序执行时，动态链接库的全部内容会被映射到运行时相应进行的虚拟地址的空间。</p><p>参考文档：<br><a href="https://www.cnblogs.com/ericling/articles/11736681.html">https://www.cnblogs.com/ericling/articles/11736681.html</a><br><a href="https://zhidao.baidu.com/question/199934360.html">https://zhidao.baidu.com/question/199934360.html</a><br><a href="https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html">https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html</a></p>]]></content>
    
    
    <summary type="html">&lt;h1 id=&quot;C-编译过程&quot;&gt;&lt;a href=&quot;#C-编译过程&quot; class=&quot;headerlink&quot; title=&quot;C++编译过程&quot;&gt;&lt;/a&gt;C++编译过程&lt;/h1&gt;&lt;p&gt;一般的C++程序在编译过程中需要进行如下四步：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;预处理(Preprocessing)&lt;/strong&gt;&lt;br&gt;预处理用于将所有的#include头文件以及宏定义替换成其真正的内容，预处理之后得到的仍然是文本文件，但文件体积会大很多&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;gcc -E -I.&amp;#x2F;inc test.c -o test.i&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;上述命令中-E是让编译器在预处理之后就退出，不进行后续编译过程；-I指定头文件目录，这里指定的是我们自定义的头文件目录；-o指定输出文件名。&lt;br&gt;&lt;strong&gt;编译(Compilation)&lt;/strong&gt;&lt;br&gt;编译不是指程序从源文件到二进制程序的全部过程，而是指将经过预处理之后的程序转换成特定汇编代码(assembly code)的过程。编译的指定如下：&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;gcc -S -I.&amp;#x2F;inc test.c -o test.s&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;上述命令中-S让编译器在编译之后停止，不进行后续过程。编译过程完成后，将生成程序的汇编代码test.s，这也是文本文件，内容如下：&lt;br&gt;&lt;strong&gt;汇编(Assemble)&lt;/strong&gt;&lt;br&gt;汇编过程将上一步的汇编代码转换成机器码，产生的文件叫做目标文件，是二进制格式。gcc汇编过程通过as命令完成：&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;as test.s -o test.o&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;等价于&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;gcc -c test.s -o test.o&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;链接(Linking)&lt;/strong&gt;&lt;br&gt;链接过程将多个目标文件以及所需的库文件(.so等)链接成最终的可执行文件&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;ld -o test.out test.o inc&amp;#x2F;mymath.o ...libraries...&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;</summary>
    
    
    
    <category term="面试" scheme="http://example.com/categories/%E9%9D%A2%E8%AF%95/"/>
    
    
    <category term="c++" scheme="http://example.com/tags/c/"/>
    
  </entry>
  
  <entry>
    <title>RxJS 入门</title>
    <link href="http://example.com/2016/12/19/rxjs/"/>
    <id>http://example.com/2016/12/19/rxjs/</id>
    <published>2016-12-19T12:01:24.000Z</published>
    <updated>2021-02-19T11:59:44.150Z</updated>
    
    <content type="html"><![CDATA[<h1 id="RxJS-介绍"><a href="#RxJS-介绍" class="headerlink" title="RxJS 介绍"></a>RxJS 介绍</h1><p>RxJS 是一个通过使用observable序列来组合异步和时间驱动程序的库。它提供了一个核心类型，<strong>Observable</strong>, 还有其他类型(Observer, Schedulers, Subjects)，和类似Array中的<br>操作符, 如(map, filtr, resuce, every, etc)，通过这些来像处理集合一样来处理异步时间。</p><blockquote><p>Think of RxJS as Lodash for events(可以认为RxJS是时间处理中的lodash)</p></blockquote><p>ReactiveX 结合了观察者模式和迭代器模式和集合的函数式编程来满足管理序列化时间的理想方式。</p><p>在RxJS中的重要概念主要有：</p><ol><li><strong>Observable</strong>: 代表了一种异步的值或事件的可调用的集合</li><li><strong>Observer</strong>: 是一个知道如何监听通过Observable传递值的回调函数集合</li><li><strong>Subscription</strong>: 代表了Observable和执行, 主要用来取消Observable的执行</li><li><strong>Operators</strong>: 是一种纯函数，使得能够用像map，filter，concat，flatmap等函数操作符来处理集合</li><li><strong>Subject</strong>: 和EventEmitter相同，而且是唯一的方式能够像多个Observer广播值或事件</li><li><strong>Schedulers</strong>: 是用于控制并发的集中调度器， 并允许我们来协调计算比如在使用setTimeout或者requestAnimationFrame时</li></ol><h2 id="第一个例子"><a href="#第一个例子" class="headerlink" title="第一个例子"></a>第一个例子</h2><p>通常我们这样注册事件</p><figure class="highlight plain"><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">var button &#x3D; document.querySelector(&#39;button&#39;);</span><br><span class="line">button.addEventListener(&#39;click&#39;, () &#x3D;&gt; console.log(&#39;Clicked!&#39;));</span><br></pre></td></tr></table></figure><p>如果使用RxJS的话我们可以这么写</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></pre></td><td class="code"><pre><span class="line">var button &#x3D; document.querySelector(&#39;button&#39;);</span><br><span class="line">Rx.Observable.fromEvent(button, &#39;click&#39;)</span><br><span class="line">    .subscribe(() &#x3D;&gt;console.log(&#39;Clicked!&#39;));</span><br></pre></td></tr></table></figure><a id="more"></a><h3 id="纯函数"><a href="#纯函数" class="headerlink" title="纯函数"></a>纯函数</h3><p>RxJS采用纯函数来产出数据，这意味着有更少的代码错误。</p><p>通常你会创造一个不纯的函数来扰乱你的状态。</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></pre></td><td class="code"><pre><span class="line">var count &#x3D; 0;</span><br><span class="line">var button &#x3D; document.querySelector(&#39;button&#39;);</span><br><span class="line">button.addEventListener(&#39;click&#39;, () &#x3D;&gt; console.log(&#96;Clicked! $&#123;++count&#125; times&#96;));</span><br></pre></td></tr></table></figure><p>在RxJS中你可以隔离状态</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></pre></td><td class="code"><pre><span class="line">var button &#x3D; document.querySelector(&#39;button&#39;);</span><br><span class="line">Rx.Observable.fromEvent(button, &#39;click&#39;)</span><br><span class="line">    .scan(count &#x3D;&gt; count+1,0)</span><br><span class="line">    .subscribe(count &#x3D;&gt;console.log(&#96;Clicked $&#123;count&#125; times!&#96;));</span><br></pre></td></tr></table></figure><p>scan操作符就像是array的reduce操作。</p><h3 id="事件流"><a href="#事件流" class="headerlink" title="事件流"></a>事件流</h3><p>RxJS 有许多操作符来帮助你控制observables中的事件流</p><p>如果用纯JS来控制一个按钮在1s内只能按一次</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><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">var count &#x3D; 0;</span><br><span class="line">var rate &#x3D; 1000;</span><br><span class="line">var lastClick &#x3D; Date.now() - rate;</span><br><span class="line">var button &#x3D; document.querySelector(&#39;button&#39;);</span><br><span class="line">button.addEventListener(&#39;click&#39;, () &#x3D;&gt; &#123;</span><br><span class="line">    if(Date.now() - lastClick &gt;&#x3D; rate)&#123;</span><br><span class="line">        console.log(&#96;Clicked $&#123;++count&#125; times&#96;);</span><br><span class="line">        lastClick &#x3D; Date.now();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>而是使用RxJS的话</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">var button &#x3D; document.querySelector(&#39;button&#39;);</span><br><span class="line">Rx.Observable.fromEvent(button,&#39;click&#39;)</span><br><span class="line">    .throttleTime(1000)</span><br><span class="line">    .scan(count &#x3D;&gt; count+1， 0)</span><br><span class="line">    .subscribe(count &#x3D;&gt; console.log(&#96;Clicked $&#123;count&#125; time&#96;));</span><br></pre></td></tr></table></figure><h3 id="流式传值"><a href="#流式传值" class="headerlink" title="流式传值"></a>流式传值</h3><p>你能够通过observables来传递值<br>下面是一个可以通过纯JS来为每一次点击添加鼠标的X坐标</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><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">var count &#x3D; 0;</span><br><span class="line">var rate &#x3D; 1000;</span><br><span class="line">var lastClick &#x3D; Date.now() - rate;</span><br><span class="line">var button &#x3D; document.querySelector(&#39;button&#39;);</span><br><span class="line">button.addEventListener(&#39;click&#39;, () &#x3D;&gt; &#123;</span><br><span class="line">    if(Date.now() - lastClick &gt;&#x3D; rate)&#123;</span><br><span class="line">        console.log(++count + event.clientX);</span><br><span class="line">        lastClick &#x3D; Date.now();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>使用RxJS</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><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">var button &#x3D; document.querySelector(&#39;button&#39;);</span><br><span class="line">Rx.Observable.fromEvent(button,&#39;click&#39;)</span><br><span class="line">    .throttleTime(1000)</span><br><span class="line">    .map(event &#x3D;&gt; event.clientX)</span><br><span class="line">    .scan((count, clientX) &#x3D;&gt; count+clientX, 0)</span><br><span class="line">    .subscribe(count &#x3D;&gt; console.log(count));</span><br></pre></td></tr></table></figure><h1 id="Observable"><a href="#Observable" class="headerlink" title="Observable"></a>Observable</h1><p>Observables是一种懒加载能够提供多值的集合<br>可以看下面的表</p><table><thead><tr><th align="left"></th><th align="center">Single</th><th align="center">Multiple</th></tr></thead><tbody><tr><td align="left">Pull</td><td align="center">Function</td><td align="center">Itetator</td></tr><tr><td align="left">Push</td><td align="center">Promise</td><td align="center">Observable</td></tr></tbody></table><p>下面的这个例子是一个Observable 在被订阅的时候立刻输出1，2，3 然后在订阅后1s后输出4，然后结束。</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><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">var observable &#x3D; Rx.Observable.create(function (observer) &#123;</span><br><span class="line">    observer.next(1);</span><br><span class="line">    observer.next(2);</span><br><span class="line">    observer.next(3);</span><br><span class="line">    setTimeout(() &#x3D;&gt; &#123;</span><br><span class="line">        observer.next(4);</span><br><span class="line">        observer.complete();</span><br><span class="line">    &#125;,1000);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>为了调用Observable 我们需要订阅它:</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><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">console.log(&#39;just before subscribe&#39;);</span><br><span class="line">observable.subscribe(&#123;</span><br><span class="line">    next: x &#x3D;&gt; console.log(&#39;got value&#39;+ x),</span><br><span class="line">    error: err &#x3D;&gt; console.error(&#39;something wrong occurred:&#39; + err),</span><br><span class="line">    complete: () &#x3D;&gt; consoelg.log(&#39;done&#39;);</span><br><span class="line">&#125;);</span><br><span class="line">console.log(&#39;just after subscribe&#39;);</span><br></pre></td></tr></table></figure><p>这个执行结果会是</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><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">just before subscribe</span><br><span class="line">got value 1</span><br><span class="line">got value 2</span><br><span class="line">got value 3</span><br><span class="line">just after subscribe</span><br><span class="line">got value 4</span><br><span class="line">done</span><br></pre></td></tr></table></figure><h2 id="Pull-vs-Push"><a href="#Pull-vs-Push" class="headerlink" title="Pull vs Push"></a>Pull vs Push</h2><p>Pull和Push是两种不同的协议用于在数据生产者和数据消费者之间。<br><strong>什么是Pull?</strong> 在Pull系统中由消费者来决定何时来获取数据，每一个jS函数都是一个Pull系统，函数是一个数据生产者，通过调用函数来获取数据。<br><strong>什么是Push?</strong> 在Push系统中，由数据生产者来决定什么时候来向消费者提供数据。Promises 是现在JavaScript中最普遍的Push系统。<br>RxJS引入了Observable，一种新的push系统，一个Observable是一种多个值的生产者，向Observers(消费者)推送数据。</p><h2 id="Observable-和一般化的函数进行比较"><a href="#Observable-和一般化的函数进行比较" class="headerlink" title="Observable 和一般化的函数进行比较"></a>Observable 和一般化的函数进行比较</h2><p>和普遍声称的不同，Observables 既不像EventEmitters 也不像多值的Promise。Observables可能在某些情况下像EventEmitters,即当他们使用RxJS Subjects 来广播时，但是通常Observables和EventEmitters不同。</p><blockquote><p>Observables 就像是没有参数的函数，但是包括了那些允许多个值的函数</p></blockquote><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></pre></td><td class="code"><pre><span class="line">function foo() &#123;</span><br><span class="line">  console.log(&#39;Hello&#39;);</span><br><span class="line">  return 42;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">var x &#x3D; foo.call(); &#x2F;&#x2F; same as foo()</span><br><span class="line">console.log(x);</span><br><span class="line">var y &#x3D; foo.call(); &#x2F;&#x2F; same as foo()</span><br><span class="line">console.log(y);</span><br></pre></td></tr></table></figure><p>通过RxJS</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><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">var foo &#x3D; Rx.Observable.create(function(observer)&#123;</span><br><span class="line">    console.log(&#39;Hello&#39;);</span><br><span class="line">    observer.next(42);</span><br><span class="line">&#125;);</span><br><span class="line">foo.subscribe(function(x)&#123;</span><br><span class="line">    console.log(x);</span><br><span class="line">&#125;);</span><br><span class="line">foo.subcribe(function(y)&#123;</span><br><span class="line">    console.log(y);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>这两个的输出都是一样的:</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></pre></td><td class="code"><pre><span class="line">&quot;Hello&quot;</span><br><span class="line">&quot;42&quot;</span><br><span class="line">&quot;Hello&quot;</span><br><span class="line">&quot;42&quot;</span><br></pre></td></tr></table></figure><blockquote><p>向一个Observable进行订阅就像是调用一个一般的函数</p></blockquote><blockquote><p>Observables能够既能同步又能异步传递数据</p></blockquote><p>Observable可以 “return” 多个值。</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><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">var foo &#x3D; Rx.Observable.create(function(observer)&#123;</span><br><span class="line">    console.log(&#39;Hello&#39;);</span><br><span class="line">    observer.next(42);</span><br><span class="line">    observer.next(100);</span><br><span class="line">    observer.next(200);</span><br><span class="line">&#125;);</span><br><span class="line">console.log(&#39;before&#39;);</span><br><span class="line">foo.subscribe(function(x)&#123;</span><br><span class="line">    console.log(x);</span><br><span class="line">&#125;);</span><br><span class="line">console.log(&#39;after&#39;);</span><br></pre></td></tr></table></figure><p>可以输出</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><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&quot;before&quot;</span><br><span class="line">&quot;Hello&quot;</span><br><span class="line">42</span><br><span class="line">100</span><br><span class="line">200</span><br><span class="line">&quot;after&quot;</span><br></pre></td></tr></table></figure><p>总结</p><ul><li>func.call() 意味着 “给我一个同步的值”</li><li>observable.subscribe() 意味着“给我多个值不管是同步还是异步”</li></ul><h2 id="Observable的解析"><a href="#Observable的解析" class="headerlink" title="Observable的解析"></a>Observable的解析</h2><p>Observable 通过Rx.Observable.create来<strong>创建</strong>，通过Observer来<strong>订阅</strong>，<strong>执行</strong>来传递next/error/complete来通知观察者，而且这些执行操作可以取消，这就是一个Observable实例的4个方面。</p><h3 id="创建Observables"><a href="#创建Observables" class="headerlink" title="创建Observables"></a>创建Observables</h3><p>Rx.Observable.create 是Observable构造器的别名，它有一个参数就是subscribe函数<br>下面这个例子每隔1s产生一个’hi’给Observer，</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">var observable &#x3D; Rx.Observable.create(function subscribe(observer)&#123;</span><br><span class="line">    var id &#x3D; setInterval(() &#x3D;&gt; &#123;</span><br><span class="line">        observer.next(&#39;hi&#39;);</span><br><span class="line">    &#125;,1000)</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="订阅Observables"><a href="#订阅Observables" class="headerlink" title="订阅Observables"></a>订阅Observables</h3><p>上个例子中的observable可以这样订阅 <code>observable.subscribe(x =&gt; console.log(x));</code></p><h3 id="执行Observables"><a href="#执行Observables" class="headerlink" title="执行Observables"></a>执行Observables</h3><h3 id="处理Observable的执行"><a href="#处理Observable的执行" class="headerlink" title="处理Observable的执行"></a>处理Observable的执行</h3>]]></content>
    
    
    <summary type="html">&lt;h1 id=&quot;RxJS-介绍&quot;&gt;&lt;a href=&quot;#RxJS-介绍&quot; class=&quot;headerlink&quot; title=&quot;RxJS 介绍&quot;&gt;&lt;/a&gt;RxJS 介绍&lt;/h1&gt;&lt;p&gt;RxJS 是一个通过使用observable序列来组合异步和时间驱动程序的库。它提供了一个核心类型，&lt;strong&gt;Observable&lt;/strong&gt;, 还有其他类型(Observer, Schedulers, Subjects)，和类似Array中的&lt;br&gt;操作符, 如(map, filtr, resuce, every, etc)，通过这些来像处理集合一样来处理异步时间。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Think of RxJS as Lodash for events(可以认为RxJS是时间处理中的lodash)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ReactiveX 结合了观察者模式和迭代器模式和集合的函数式编程来满足管理序列化时间的理想方式。&lt;/p&gt;
&lt;p&gt;在RxJS中的重要概念主要有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Observable&lt;/strong&gt;: 代表了一种异步的值或事件的可调用的集合&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Observer&lt;/strong&gt;: 是一个知道如何监听通过Observable传递值的回调函数集合&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subscription&lt;/strong&gt;: 代表了Observable和执行, 主要用来取消Observable的执行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operators&lt;/strong&gt;: 是一种纯函数，使得能够用像map，filter，concat，flatmap等函数操作符来处理集合&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subject&lt;/strong&gt;: 和EventEmitter相同，而且是唯一的方式能够像多个Observer广播值或事件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Schedulers&lt;/strong&gt;: 是用于控制并发的集中调度器， 并允许我们来协调计算比如在使用setTimeout或者requestAnimationFrame时&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;第一个例子&quot;&gt;&lt;a href=&quot;#第一个例子&quot; class=&quot;headerlink&quot; title=&quot;第一个例子&quot;&gt;&lt;/a&gt;第一个例子&lt;/h2&gt;&lt;p&gt;通常我们这样注册事件&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;var button &amp;#x3D; document.querySelector(&amp;#39;button&amp;#39;);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;button.addEventListener(&amp;#39;click&amp;#39;, () &amp;#x3D;&amp;gt; console.log(&amp;#39;Clicked!&amp;#39;));&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;如果使用RxJS的话我们可以这么写&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;var button &amp;#x3D; document.querySelector(&amp;#39;button&amp;#39;);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;Rx.Observable.fromEvent(button, &amp;#39;click&amp;#39;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    .subscribe(() &amp;#x3D;&amp;gt;console.log(&amp;#39;Clicked!&amp;#39;));&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;</summary>
    
    
    
    
    <category term="RxJS" scheme="http://example.com/tags/RxJS/"/>
    
  </entry>
  
</feed>
