摘要:深入淺出讀書筆記遺留問題的與對應(yīng)的實際場景,以及在編碼中的體現(xiàn)部分測試你對時間的感覺按住我一秒鐘然后松手你的時間毫秒實現(xiàn)重置避免直接觸發(fā)事件,例如在處點擊然后在處實現(xiàn)獲取間隔時間你超過了的用戶的使用主要用來加載靜態(tài)資源,所
RxJS
《深入淺出RxJS》讀書筆記遺留問題
Observable的HOT與COLD對應(yīng)的實際場景,以及在編碼中的體現(xiàn)
chapter1html部分
測試你對時間的感覺 按住我一秒鐘然后松手 你的時間:毫秒
jquery實現(xiàn)
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 避免直接觸發(fā)mouseup事件,例如在A處點擊然后在B處up time = null; } });
RxJS實現(xiàn)
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的使用
主要用來加載靜態(tài)資源,所以使用到了 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("程序啟動成功") });Observable 和 Observer
Observable 可被觀察的對象,Observer觀察者,Observer通過subscribe來觀察Observable對象
RxJS的數(shù)據(jù)流就是Observable對象:
觀察者模式
迭代器模式
舉個栗子// 使用 deep-link方式引入函數(shù) const Observable = require("rxjs").Observable; /* * 定義Observable對象的行為,會產(chǎn)生數(shù)據(jù),調(diào)用訂閱者的next方法 * 1. 此處的Observer與訂閱者行為 theObserver并不是同一個對象,而是對theObserver的包裝 * 2. 如果observer.error被調(diào)用,之后的complete或者next就不會被調(diào)用啦,同理,complete被調(diào)用之后,也不會 * 再調(diào)用next或者error * 3. 如果error或者complete一直未調(diào)用,則observer就一直在內(nèi)存中等待被調(diào)用 */ const onSubscribe = observer =>{ observer.next(1); observer.error(2); observer.complete(3); } // 產(chǎn)生一個Observable對象 const source$ = new Observable(onSubscribe); // 定義觀察者的行為 消費Observable對象產(chǎn)生的數(shù)據(jù) const theObserver = { next:item => console.log(item), error:item => console.error(item), complete:item => console.log("已完成"), } // 建立Observable與Observer的關(guān)系 source$.subscribe(theObserver)退訂subscribe
在訂閱一段事件之后observer不再響應(yīng)吐出的信息了,這時可以退訂,但是Observeable還會一直產(chǎn)生數(shù)據(jù)
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中執(zhí)行,會一直打印 in onSubscribe *,但是source$不會再響應(yīng)
Chapter3 操作符基礎(chǔ)const Observable = require("rxjs/Observable").Observable; const of = require("rxjs/observable/of").of; const map = require("rxjs/operator/map").map; // 新建一個操作符 // 此處this是外部變量,導致此operator不再是純函數(shù) 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的操作,這樣是依賴外部環(huán)境的,不屬于純函數(shù),也會喪失TS的類型檢查優(yōu)勢
lettable將Observable對象傳遞給下文,避免使用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`補丁,開發(fā)**lettable**寫法的操作符
// ES5實現(xiàn)
function map(project){
return function(obj$){ // 通過上面的Observable生成一個新Observable return 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實現(xiàn)
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 創(chuàng)建數(shù)據(jù)流 > 大多數(shù)的操作符是靜態(tài)操作符 ### 基礎(chǔ)操作符 1. `create`簡單的返回一個Observable對象
Observable.create = function(subscribe){ return new Observable(subscribe) } ```
of列舉數(shù)據(jù)
import {Observable} from "rxjs/Observable"; import "rxjs/add/observable/of" // 依次吐出數(shù)據(jù),一次性emit const source$ = Observable.of(1,2,3); // 訂閱 // 第一個參數(shù)是next,第二個參數(shù)是error回調(diào),第三個參數(shù)是complete回調(diào) source$.subscribe(console.log,null,()=>{console.log("Complete")})
range產(chǎn)生指定范圍的數(shù)據(jù)
const sourc$ = Observable.range(/*初始值*/1,/*個數(shù)*/100); // 每次只能步進 1
generate循環(huán)創(chuàng)建
相當于for循環(huán)
const source$ = Observable.generate( // 初始值 2, // 判斷條件 value=> value < 10, // 步進 value=> value+0.5, // 函數(shù)體,產(chǎn)生的結(jié)果 value=> value*value )
使用generate代替range
const range = function(min,count){ const max = min + count; return Observable.generate(min,v=>vv+1,v=>v*v) }
repeat重復數(shù)據(jù)的數(shù)據(jù)流
實例操作符,通過import "rxjs/add/operator/repeat"引入
V4版本中repeat是靜態(tài)屬性,這樣在使用Observable.repeat(1,2)重復1兩次,這樣數(shù)據(jù)就夠靈活
V5版本中改為實例屬性之后,Observable.of(1,2,4).repeat(2),將產(chǎn)生的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不會被調(diào)用
repeat以complete為契機會再次執(zhí)行數(shù)據(jù)源,如果上游一直沒有complete下游就不會執(zhí)行
因為repeat的存在,第一次數(shù)據(jù)源執(zhí)行完(以complete為契機)后并不會執(zhí)行observer的complete回調(diào)
empty,throw,never
創(chuàng)建異步數(shù)據(jù)的Observable對象
interval和timer
interval類似于setInterval
require("rxjs/add/observable/interval") // 每隔1000ms產(chǎn)生一個數(shù)據(jù),初始值為0,步進為1 Observable.interval(1000)"
timer 是setTimeout的超集
// 1000ms后開始產(chǎn)生數(shù)據(jù),之后每隔1000ms產(chǎn)生一個數(shù)據(jù),功能相當于interval Observable.timer(1000,1000) // 指定日期 Observable.time(new Date(new Date().getTime() + 12000))
from 把一切轉(zhuǎn)化為Observable
將所有的Iterable的對象都轉(zhuǎn)化為Observable對象
可以將Promise對象轉(zhuǎn)化為Observable對象,功能與fromPromise相同
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.
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
fromEvent是Hot Observable,也就是數(shù)據(jù)的產(chǎn)生和訂閱無關(guān),對于fromEvent來說,數(shù)據(jù)源是外部產(chǎn)生的,不受RxJS控制,這是Hot Observable對象的特點
fromEventPattern針對不規(guī)范的事件源
規(guī)范的事件源:DOM事件,EventEmitter事件
ajax見最上面的例子
repeatWhen
例如 在上游事件結(jié)束之后的一段時間再重新訂閱
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")) // 每隔一秒產(chǎn)生一次 // 1 // 2 // 3 // 1 // 2 // 3 // 1 // 2 // 3 // 1 // 2 // 3 // 1 // 2 // 3 // ^C
defer延遲創(chuàng)建Observable
針對Observable占用內(nèi)存比較大的情況,懶加載
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)合并數(shù)據(jù)流
功能需求 | 操作符 |
---|---|
把多個數(shù)據(jù)流以首尾相連的方式合并 | concat,concatAll |
把多個數(shù)據(jù)流以先到先得的方式合并 | merge,mergeAll |
把多個數(shù)據(jù)流中的數(shù)據(jù)以一一對應(yīng)的方式合并 | zip和zipAll |
持續(xù)合并多個數(shù)據(jù)流中最新產(chǎn)生的數(shù)據(jù) | combineLatest,combineAll,withLatestFrom |
從多個數(shù)據(jù)流中選取第一個產(chǎn)生內(nèi)容的數(shù)據(jù)流 | race |
在數(shù)據(jù)流前面添加一個指定數(shù)據(jù) | startWith |
只獲取多個數(shù)據(jù)流最后產(chǎn)生的數(shù)據(jù) | forkJoin |
從高階數(shù)據(jù)流中切換數(shù)據(jù)源 | switch,exhaust |
concat
實例方法
靜態(tài)方法,如果兩個數(shù)據(jù)沒有先后關(guān)系,推薦使用此方法
實例方法
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"))
靜態(tài)方法
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`在將上一個數(shù)據(jù)源傳遞下去的時候會調(diào)用上一個`Observable`的`unsubscribe`,如果上一個`Observable`一直為完結(jié),后續(xù)的都不會被調(diào)用 ```javascript const source$1 = Observable.internal(1000); const source$2 = Observable.of(1); const concated$ = Observable.concat(source$1,source$2); // 此時 source$2永遠不會被調(diào)用 ``` 在此推測:`rxjs/add/operator/*`下的屬性都是實例屬性,`rxjs/add/observable/*`下的屬性都是實例屬性
merge先到先得
merge用在同步數(shù)據(jù)的情況下和concat表現(xiàn)只,不建議使用
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, /*此參數(shù)限制了合并的Observable的個數(shù)*/ 2) .subscribe(console.log, null, () => console.log("Complete")); // 0A // 0B // 1A // 1B // 2A // 2B // 3A // 3B // 4A // 4B // ^C
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/96173.html
摘要:官網(wǎng)地址聊天機器人插件開發(fā)實例教程一創(chuàng)建插件在系統(tǒng)技巧使你的更加專業(yè)前端掘金一個幫你提升技巧的收藏集。我會簡單基于的簡潔視頻播放器組件前端掘金使用和實現(xiàn)購物車場景前端掘金本文是上篇文章的序章,一直想有機會再次實踐下。 2道面試題:輸入URL按回車&HTTP2 - 掘金通過幾輪面試,我發(fā)現(xiàn)真正那種問答的技術(shù)面,寫一堆項目真不如去刷技術(shù)文章作用大,因此刷了一段時間的博客和掘金,整理下曾經(jīng)被...
摘要:本文是響應(yīng)式編程第四章構(gòu)建完整的應(yīng)用程序這篇文章的學習筆記。涉及的運算符每隔指定時間將流中的數(shù)據(jù)以數(shù)組形式推送出去。中提供了一種叫做異步管道的模板語法,可以直接在的微語法中使用可觀測對象示例五一點建議一定要好好讀官方文檔。 本文是【Rxjs 響應(yīng)式編程-第四章 構(gòu)建完整的Web應(yīng)用程序】這篇文章的學習筆記。示例代碼托管在:http://www.github.com/dashnoword...
摘要:巧前端基礎(chǔ)進階全方位解讀前端掘金我們在學習的過程中,由于對一些概念理解得不是很清楚,但是又想要通過一些方式把它記下來,于是就很容易草率的給這些概念定下一些方便自己記憶的有偏差的結(jié)論。 計算機程序的思維邏輯 (83) - 并發(fā)總結(jié) - 掘金從65節(jié)到82節(jié),我們用了18篇文章討論并發(fā),本節(jié)進行簡要總結(jié)。 多線程開發(fā)有兩個核心問題,一個是競爭,另一個是協(xié)作。競爭會出現(xiàn)線程安全問題,所以,本...
摘要:巧前端基礎(chǔ)進階全方位解讀前端掘金我們在學習的過程中,由于對一些概念理解得不是很清楚,但是又想要通過一些方式把它記下來,于是就很容易草率的給這些概念定下一些方便自己記憶的有偏差的結(jié)論。 計算機程序的思維邏輯 (83) - 并發(fā)總結(jié) - 掘金從65節(jié)到82節(jié),我們用了18篇文章討論并發(fā),本節(jié)進行簡要總結(jié)。 多線程開發(fā)有兩個核心問題,一個是競爭,另一個是協(xié)作。競爭會出現(xiàn)線程安全問題,所以,本...
摘要:在函數(shù)式編程中,異步操作修改全局變量等與函數(shù)外部環(huán)境發(fā)生的交互叫做副作用通常認為這些操作是邪惡骯臟的,并且也是導致的源頭。 注:這篇是17年1月的文章,搬運自本人 blog... https://github.com/BuptStEve/... 零、前言 在上一篇中介紹了 Redux 的各項基礎(chǔ) api。接著一步一步地介紹如何與 React 進行結(jié)合,并從引入過程中遇到的各個痛點引出 ...
閱讀 1026·2021-11-24 10:42
閱讀 3576·2021-11-19 11:34
閱讀 2727·2021-09-29 09:35
閱讀 2609·2021-09-09 09:33
閱讀 750·2021-07-26 23:38
閱讀 2590·2019-08-30 10:48
閱讀 1453·2019-08-28 18:07
閱讀 482·2019-08-26 13:44