RxJS筆記

RxJS

《深入淺出RxJS》讀書筆記

遺留問題

  1. Observable的HOT與COLD對應的實際場景,以及在編碼中的體現

chapter1

html部分

測試你對時間的感覺按住我一秒鐘然后松手你的時間:毫秒
  1. jquery實現

    var time = new Date().getTime();
    $("#hold-me").mousedown(function(event) {time = new Date().getTime();}).mouseup(function(event) {if (time) {var elapse = new Date().getTime() - time;$("#hold-time").text(elapse);// 重置time 避免直接觸發mouseup事件,例如在A處點擊然后在B處uptime = null;}});
  2. RxJS實現

    const holdMeButton = document.getElementById("hold-me");const mouseDown$ = Rx.Observable.fromEvent(holdMeButton,"mousedown");const mouseUp$ = Rx.Observable.fromEvent(holdMeButton,"mouseup");// 獲取間隔時間const holdTime$ = mouseUp$.timestamp().withLatestFrom(mouseDown$.timestamp(),(mouseUpEvent,mouseDownEvent)=>{return mouseUpEvent.timestamp - mouseDownEvent.timestamp});holdTime$.subscribe(ms=>{document.getElementById("hold-time").innerText = ms;})holdTime$.flatMap(ms=>{return Rx.Observable.ajax('https://timing-sense-score-board.herokuapp.com/score/'+ms)}).map(e=>e.response).subscribe(res=>{document.getElementById("rank").innerText = `你超過了${res.rank}% 的用戶`})

chapter2

Koa2的使用

主要用來加載靜態資源,所以使用到了 koa,koa-static
const path = require("path");
const koa = require("koa");
const serve = require("koa-static");
const app = new koa();app.use(async function (ctx,next) {console.log("收到請求...")await next()console.log(`"${ctx.path}"請求 已處理...`)
})app.use(serve(path.resolve(__dirname, "../src"))).listen(3001,function(err){if(err) throw err;console.log("程序啟動成功")
});

ObservableObserver

Observable 可被觀察的對象,Observer觀察者,Observer通過subscribe來觀察Observable對象

RxJS的數據流就是Observable對象:

  1. 觀察者模式
  2. 迭代器模式

舉個栗子

// 使用 deep-link方式引入函數
const Observable = require("rxjs").Observable;/** 定義Observable對象的行為,會產生數據,調用訂閱者的next方法* 1. 此處的Observer與訂閱者行為 theObserver并不是同一個對象,而是對theObserver的包裝* 2. 如果observer.error被調用,之后的complete或者next就不會被調用啦,同理,complete被調用之后,也不會*    再調用next或者error* 3. 如果error或者complete一直未調用,則observer就一直在內存中等待被調用
*/
const onSubscribe = observer =>{observer.next(1);observer.error(2);observer.complete(3);
}
// 產生一個Observable對象
const source$ = new Observable(onSubscribe);
// 定義觀察者的行為 消費Observable對象產生的數據
const theObserver = {next:item => console.log(item),error:item => console.error(item),complete:item => console.log("已完成"),
}
// 建立Observable與Observer的關系
source$.subscribe(theObserver)

退訂subscribe

在訂閱一段事件之后observer不再響應吐出的信息了,這時可以退訂,但是Observeable還會一直產生數據
const Observable = require("rxjs").Observable;const onSubscribe = observer =>{let n = 1;const handle = setInterval(()=>{console.log(`in onSubscribe ${n}`)// if(n>3){//     observer.complete()// }observer.next(n++);},1000)return {unsubscribe(){// clearInterval(handle)}}
}const source$ = new Observable(onSubscribe);const theObserver = {next:item => console.log(item)
}let subscription = source$.subscribe(theObserver)setTimeout(()=>{// 此處的unsubscribe也是封裝過的subscription.unsubscribe()
},3500)

node中執行,會一直打印 in onSubscribe *,但是source$不會再響應

Chapter3 操作符基礎

const Observable = require("rxjs/Observable").Observable;
const of = require("rxjs/observable/of").of;
const map = require("rxjs/operator/map").map;
// 新建一個操作符
// 此處this是外部變量,導致此operator不再是純函數
Observable.prototype.double = function(){// return this::map(x=>x*2)return map.call(this,x=>x*2)
}const source$ = of(1,3,4);
const result$ = source$.double();result$.subscribe(value=>console.log(value))

lettable/pipeable操作符

解決需要使用call或者bind改變this的操作,這樣是依賴外部環境的,不屬于純函數,也會喪失TS的類型檢查優勢
  • lettableObservable對象傳遞給下文,避免使用this

    const Observable = require("rxjs/Observable").Observable;
    require("rxjs/add/observable/of").of;
    require("rxjs/add/operator/map").map;
    require("rxjs/add/operator/let").let;const source$ = Observable.of(1,2,3);
    const double$ = obs$ => obs$.map(v=>v*2);
    // 接受上文,傳遞到下文
    const result$ = source$.let(double$);result$.subscribe(console.log)
    
不引入`map`補丁,開發**lettable**寫法的操作符

// ES5實現
function map(project){

return function(obj$){// 通過上面的Observable生成一個新Observablereturn new Observable(observer=>{return obj$.subscribe({next:value=>observer.next(project(value)),error:err=>observer.error(err),complete:()=>observer.complete()})})
}

}
// 添加操作符
var result$ = source$.let(map(x => x * 3));

// ES6實現
const map6 = fn => obj$ =>

  new Observable(observer =>obj$.subscribe({next: value => observer.next(fn(value)),error: err => observer.error(err),complete: () => observer.complete()}));

// 添加操作符
var result$ = source$.let(map6(x => x * 4));


`pipeable`是`lettable`的別稱,方便對于`lattable`的理解,V6以上才支持## Chapter4 創建數據流> 大多數的操作符是靜態操作符### 基礎操作符1.  `create`簡單的返回一個Observable對象
Observable.create = function(subscribe){return new Observable(subscribe)
}
```
  1. of列舉數據

    import {Observable} from "rxjs/Observable";
    import "rxjs/add/observable/of"
    // 依次吐出數據,一次性emit
    const source$ = Observable.of(1,2,3);
    // 訂閱
    // 第一個參數是next,第二個參數是error回調,第三個參數是complete回調
    source$.subscribe(console.log,null,()=>{console.log("Complete")})
  2. range產生指定范圍的數據

    const sourc$ = Observable.range(/*初始值*/1,/*個數*/100);
    // 每次只能步進 1
  3. generate循環創建

    相當于for循環
    const source$ = Observable.generate(// 初始值2,// 判斷條件value=> value < 10,// 步進value=> value+0.5,// 函數體,產生的結果value=> value*value
    )

    使用generate代替range

    const range = function(min,count){const max = min + count;return Observable.generate(min,v=>vv+1,v=>v*v)
    }
  4. repeat重復數據的數據流

    實例操作符,通過import 'rxjs/add/operator/repeat'引入

    1. V4版本中repeat是靜態屬性,這樣在使用Observable.repeat(1,2)重復1兩次,這樣數據就夠靈活
    2. V5版本中改為實例屬性之后,Observable.of(1,2,4).repeat(2),將產生的1,2,3重復兩次,功能更加強大
    const Observable = require("rxjs").Observable;
    require("rxjs/add/operator/repeat");const source$ = Observable.create(observer => {setTimeout(() => {observer.next(1);}, 1000);setTimeout(() => {observer.next(2);}, 2000);setTimeout(() => {observer.next(3);}, 3000);setTimeout(() => {observer.complete(1);}, 4000);return {unsubscribe(){console.log("on Unsubscribe")}}
    });const repeat$ = source$.repeat(2)repeat$.subscribe(console.log,null,()=>{console.log("Complete")})// 1
    // 2
    // 3
    // on Unsubscribe
    // 1
    // 2
    // 3
    // Complete
    // on Unsubscribe
    • 如果沒有observer.complete()repeat不會被調用

      repeat以complete為契機會再次執行數據源,如果上游一直沒有complete下游就不會執行
    • 因為repeat的存在,第一次數據源執行完(以complete為契機)后并不會執行observer的complete回調
  5. empty,throw,never

創建異步數據的Observable對象

  1. intervaltimer

    interval類似于setInterval

    require('rxjs/add/observable/interval')
    // 每隔1000ms產生一個數據,初始值為0,步進為1
    Observable.interval(1000)'

    timer 是setTimeout的超集

    // 1000ms后開始產生數據,之后每隔1000ms產生一個數據,功能相當于interval
    Observable.timer(1000,1000)
    // 指定日期
    Observable.time(new Date(new Date().getTime() + 12000))
  2. from 把一切轉化為Observable

    1. 將所有的Iterable的對象都轉化為Observable對象
    2. 可以將Promise對象轉化為Observable對象,功能與fromPromise相同
  3. fromPromise異步處理的對接

    const Observable = require("rxjs").Observable;
    require("rxjs/add/observable/fromPromise");const promise = Promise.resolve(123);
    Observable.fromPromise(promise).subscribe(console.log, null, () =>console.log("Complete")
    );
    //123
    //Complete
    const promise1 = Promise.reject("error");
    Observable.from(console.log,err => console.log("catch", err),() => console.log("Complete!")
    );
    // 未捕獲的Promise錯誤
    // (node:765) UnhandledPromiseRejectionWarning: error
    // (node:765) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing
    // inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (
    // rejection id: 1)
    // (node:765) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
  4. fromEvent連接DOM與RxJS的橋梁

    const event$ = Observable.fromEvent(document.getElementById("btn"),"click");
    event$.subscribe(event=>{// Do something
    })

    在NodeJs中可以與EventEmitter交互

    const Observable = require("rxjs").Observable;
    const EventEmitter = require("events");
    require("rxjs/add/observable/fromEvent")const emitter = new EventEmitter();const source$ = Observable.fromEvent(emitter,"msg");
    source$.subscribe(console.log,null,()=>console.log("Complete"))emitter.emit("msg",1)
    // 1
    emitter.emit("msg","haha")
    // haha
    emitter.emit("a-msg","haha")
    //
    emitter.emit("msg",'nihao')
    // nihao

    fromEventHot Observable,也就是數據的產生和訂閱無關,對于fromEvent來說,數據源是外部產生的,不受RxJS控制,這是Hot Observable對象的特點

  5. fromEventPattern針對不規范的事件源

    規范的事件源:DOM事件,EventEmitter事件
  6. ajax見最上面的例子
  7. repeatWhen

    例如 在上游事件結束之后的一段時間再重新訂閱
    const Observable = require("rxjs").Observable;
    require("rxjs/add/operator/repeatWhen")const notifier = ()=>{return Observable.interval(1000);
    }const source$ = Observable.of(1,2,3);
    // const source$ = Observable.create(observer=>{
    //     observer.next(111);
    //     return {
    //         unsubscribe(){
    //             console.log("on Unsubscribe")
    //         }
    //     }
    // });
    const repeat$ = source$.repeatWhen(notifier);repeat$.subscribe(console.log,null,()=>console.log("Complete"))
    // 每隔一秒產生一次
    // 1
    // 2
    // 3
    // 1
    // 2
    // 3
    // 1
    // 2
    // 3
    // 1
    // 2
    // 3
    // 1
    // 2
    // 3
    // ^C
  8. defer延遲創建Observable

    針對Observable占用內存比較大的情況,懶加載
    const Observable = require("rxjs").Observable;
    require("rxjs/add/observable/defer");
    require("rxjs/add/observable/of");const observableFactory = ()=>Observable.of(1,2,3);
    const source$ = Observable.defer(observableFactory)

合并數據流

功能需求操作符
把多個數據流以首尾相連的方式合并 concat,concatAll
把多個數據流以先到先得的方式合并 merge,mergeAll
把多個數據流中的數據以一一對應的方式合并 zipzipAll
持續合并多個數據流中最新產生的數據 combineLatest,combineAll,withLatestFrom
從多個數據流中選取第一個產生內容的數據流race
在數據流前面添加一個指定數據startWith
只獲取多個數據流最后產生的數據forkJoin
高階數據流中切換數據源 switch,exhaust
  1. concat

    1. 實例方法
    2. 靜態方法,如果兩個數據沒有先后關系,推薦使用此方法
    • 實例方法

      const Observable = require("rxjs").Observable;
      require("rxjs/add/operator/of")
      require("rxjs/add/operator/concat")const source$1 = Observable.of(1,2,3);
      const source$2 = Observable.of(4,5,6);source$1.concat(source$2).subscribe(console.log,null,()=>console.log("Complete"))
    • 靜態方法

      const Observable = require("rxjs").Observable;
      require("rxjs/add/operator/of")
      require("rxjs/add/observable/concat")const source$1 = Observable.of(1,2,3);
      const source$2 = Observable.of(4,5,6);Observable.concat(source$1,source$2).subscribe(console.log,null,()=>console.log("Complete"))
`concat`在將上一個數據源傳遞下去的時候會調用上一個`Observable`的`unsubscribe`,如果上一個`Observable`一直為完結,后續的都不會被調用```javascript
const source$1 = Observable.internal(1000);
const source$2 = Observable.of(1);
const concated$ = Observable.concat(source$1,source$2);
// 此時 source$2永遠不會被調用
```在此推測:`rxjs/add/operator/*`下的屬性都是實例屬性,`rxjs/add/observable/*`下的屬性都是實例屬性
  1. merge先到先得

    merge用在同步數據的情況下和concat表現只,不建議使用
    const Observable = require("rxjs").Observable;
    require("rxjs/add/operator/merge");
    require("rxjs/add/operator/map");
    require("rxjs/add/observable/timer");const source$1 = Observable.timer(0, 1000).map(x => x + "A");
    const source$2 = Observable.timer(500, 1000).map(x => x + "B");
    const source$3 = Observable.timer(1000, 1000).map(x => x + "C");// 此時 source$1與source$2永遠不會停止,所以
    source$1.merge(source$2, source$3, /*此參數限制了合并的Observable的個數*/ 2).subscribe(console.log, null, () => console.log("Complete"));// 0A
    // 0B
    // 1A
    // 1B
    // 2A
    // 2B
    // 3A
    // 3B
    // 4A
    // 4B
    // ^C
    

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/390102.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/390102.shtml
英文地址,請注明出處:http://en.pswp.cn/news/390102.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

滾動一定的高度底色遞增

$(window).scroll(function() {var swipeHeight 200;//完全變色高度var scrollTop $(document).scrollTop();//頁面滾動高度var x scrollTop/swipeHeight;$(".head-bg").css({"opacity":x}); }) 轉載于:https://www.cnblogs.com/lhj-blog/p/8521525.htm…

@hot熱加載修飾器導致static靜態屬性丟失(已解決)

react開發的時候&#xff0c;引入熱加載&#xff0c;用了修飾器的引入方式&#xff0c;發現了一個很有意思的問題&#xff0c;網上并沒有相關文章&#xff0c;所以拋出來探討下。 一段很簡單的測試代碼。但是經過babel編碼后&#xff0c;變得很有意思。假設編碼成es2016&#x…

49. 字母異位詞分組

49. 字母異位詞分組 給你一個字符串數組&#xff0c;請你將 字母異位詞 組合在一起。可以按任意順序返回結果列表。 字母異位詞 是由重新排列源單詞的字母得到的一個新單詞&#xff0c;所有源單詞中的字母都恰好只用一次。 示例 1: 輸入: strs [“eat”, “tea”, “tan”…

python 入門程序_非Python程序員的Python速成課程-如何快速入門

python 入門程序This article is for people who already have experience in programming and want to learn Python quickly.本文適用于已經有編程經驗并希望快速學習Python的人們。 I created this resource out of frustration when I couldnt find an online course or a…

cmd命令操作Oracle數據庫

//注意cmd命令執行的密碼字符不能過于復雜 不能帶有特殊符號 以免執行不通過 譬如有&#xff01;#&#xffe5;%……&*之類的 所以在Oracle數據庫設置密碼是不要太復雜 /String Database "ORCL"; 不指向地址程序只能安裝在數據庫服務器上才能執行到命令String …

OpenCV學習(7.16)

寫了個實現攝像頭上畫線并輸出角度的東西……雖然很簡單&#xff0c;但腦殘的我還是debug了很長時間。 1 // 圓和直線.cpp : 定義控制臺應用程序的入口點。2 //3 4 #include "stdafx.h"5 6 using namespace std;7 using namespace cv;8 9 void onMouse(int event, in…

學習vue.js的自我梳理筆記

基本語法格式&#xff1a; <script> new Vue({ el: #app, data: { url: http://www.runoob.com } }) </script> 指令 【指令是帶有 v- 前綴的特殊屬性。】 判斷 <p v-if"seen">現在你看到我了</p> 參數 <a v-bind:href"url"&…

722. 刪除注釋

722. 刪除注釋 給一個 C 程序&#xff0c;刪除程序中的注釋。這個程序source是一個數組&#xff0c;其中source[i]表示第i行源碼。 這表示每行源碼由\n分隔。 在 C 中有兩種注釋風格&#xff0c;行內注釋和塊注釋。 字符串// 表示行注釋&#xff0c;表示//和其右側的其余字符…

如何創建一個自記錄的Makefile

My new favorite way to completely underuse a Makefile? Creating personalized, per-project repository workflow command aliases that you can check in.我最喜歡的完全沒用Makefile的方法&#xff1f; 創建個性化的按項目存儲庫工作流命令別名&#xff0c;您可以檢入。…

【BZOJ3262】陌上花開

CDQ分治模板 注意三元組完全相等的情況 1 #include<bits/stdc.h>2 using namespace std;3 const int N100010,K200010;4 int n,k,cnt[N],ans[N];5 struct Node{6 int a,b,c,id;7 bool operator<(const Node& k)const{8 if(bk.b&&ck.c) re…

Spring+jpaNo transactional EntityManager available

2019獨角獸企業重金招聘Python工程師標準>>> TransactionRequiredException: No transactional EntityManager availableEntityManager執行以下方法(refresh, persist, flush, joinTransaction, remove, merge) 都需要需要事務if (transactionRequiringMethods.cont…

python項目構建_通過構建4個項目來學習Python網絡

python項目構建The Python programming language is very capable when it comes to networking. Weve released a crash course on the freeCodeCamp.org YouTube channel that will help you learn the basics of networking in Python.當涉及到網絡時&#xff0c;Python編程…

164. 最大間距

164. 最大間距 給定一個無序的數組&#xff0c;找出數組在排序之后&#xff0c;相鄰元素之間最大的差值。 如果數組元素個數小于 2&#xff0c;則返回 0。 示例 1: 輸入: [3,6,9,1] 輸出: 3 解釋: 排序后的數組是 [1,3,6,9], 其中相鄰元素 (3,6) 和 (6,9) 之間都存在最大差…

10.32/10.33 rsync通過服務同步 10.34 linux系統日志 screen工具

通過后臺服務的方式在遠程主機上建立一個rsync的服務器&#xff0c;在服務器上配置好rsync的各種應用&#xff0c;然后將本機作為rsync的一個客戶端連接遠程的rsync服務器。在128主機上建立并配置rsync的配置文件/etc/rsyncd.conf,把你的rsyncd.conf編輯成以下內容&#xff1a;…

01_Struts2概述及環境搭建

1.Struts2概述&#xff1a;Struts2是一個用來開發MVC應用程序的框架。Struts2提供了web應用程序開發過程中一些常見問題的解決方案;對用戶輸入的數據進行合法性驗證統一的布局可擴展性國際化和本地化支持Ajax表單的重復提交文件的上傳和下載... ...2.Struts2相對于Struts1的優勢…

315. 計算右側小于當前元素的個數

315. 計算右側小于當前元素的個數 給定一個整數數組 nums&#xff0c;按要求返回一個新數組 counts。數組 counts 有該性質&#xff1a; counts[i] 的值是 nums[i] 右側小于 nums[i] 的元素的數量。 示例&#xff1a; 輸入&#xff1a;nums [5,2,6,1] 輸出&#xff1a;[2,1…

IOS上傳文件給java服務器,返回報錯unacceptable context-type:text/plain

IOS上傳文件給java服務器&#xff0c;返回報錯unacceptable context-type&#xff1a;text/plain response返回類型不對 RequestMapping(value "uploadMultiFiles", method RequestMethod.POST, produces"application/json;charsetUTF-8") 使用produces指…

Python爬蟲框架Scrapy學習筆記原創

字號scrapy [TOC] 開始 scrapy安裝 首先手動安裝windows版本的Twisted https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted pip install Twisted-18.4.0-cp36-cp36m-win_amd64.whl 安裝scrapy pip install -i https://pypi.douban.com/simple/ scrapy windows系統額外需要…

600. 不含連續1的非負整數

600. 不含連續1的非負整數 給定一個正整數 n&#xff0c;找出小于或等于 n 的非負整數中&#xff0c;其二進制表示不包含 連續的1 的個數。 示例 1:輸入: 5 輸出: 5 解釋: 下面是帶有相應二進制表示的非負整數< 5&#xff1a; 0 : 0 1 : 1 2 : 10 3 : 11 4 : 100 5 : 101…

高可用性、負載均衡的mysql集群解決方案

2019獨角獸企業重金招聘Python工程師標準>>> 一、為什么需要mysql集群&#xff1f; 一個龐大的分布式系統的性能瓶頸中&#xff0c;最脆弱的就是連接。連接有兩個&#xff0c;一個是客戶端與后端的連接&#xff0c;另一個是后端與數據庫的連接。簡單如圖下兩個藍色框…