*不是我沒學(xué)弧腥,我只是懶得不想把Raw筆記轉(zhuǎn)碼了而已。~~懶得要死~~
注:本文學(xué)習(xí)環(huán)境為RxJs5.x版本革半,目前使用環(huán)境為RxJs6砂蔽,故部分聲明代碼不同
例如:大部分operator將不需要前置的Rx.Observable,直接調(diào)用即可署惯。
分割線-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Observable可以同時(shí)處理同步與異步傳來的信息
var observable = Rx.Observable? ? // 1.創(chuàng)建一個(gè)observable對象左驾,新版應(yīng)改為直接使用Observable?
? ? .create(function(observer) {
? ? ? ? observer.next('Jerry'); // 同步部分
? ? ? ? observer.next('Anna');?
? ? ? ? setTimeout(() => {? ? ? // 異步部分
? ? ? ? ? ? observer.next('RxJS 30 days!');
observer.complete();? //停止observable,此后部分不會(huì)被顯示极谊。
observer.next("not work");
? ? ? ? }, 30)
? ? })
console.log('start');
observable.subscribe(function(value) {? // 2.訂閱這個(gè)observable對象诡右,并為其設(shè)置觀察者方法。
? ? console.log(value);
});
console.log('end');
輸出:
start
Jerry
Anna
end
RxJS 30 days!
對于subscribe方法來說轻猖,可以為其設(shè)定針對不同情況的不同處理帆吻,例如針對complete與異常拋出
var observer = {
next: function(value) {? ? ? //.next()走這里
console.log(value);
},
error: function(error) {? ? ? // 出現(xiàn)異常走這里
console.log('Error: ', error)
},
complete: function() {? ? ? ? //.complete()走這里
console.log('complete')
}
}
observable.subscribe(observer)? ? // 而后進(jìn)行訂閱
以上可以簡化為傳三個(gè)function參數(shù):
observable.subscribe(
? ? v => { console.log(v); },
? ? e => { console.log('Error: ', e); },
? ? () => { console.log('complete') }
)
訂閱函數(shù)subscribe()具有自己的返回值,是一個(gè)subscription對象
該對象可以用來停止某些不會(huì)complete()的訂閱過程咙边,即unsubscribe();
observable的常用creation operator
這些操作符都是用來創(chuàng)建實(shí)例的操作符:
of()傳入多個(gè)參數(shù)猜煮,observer將會(huì)將其依次next()傳出,完成時(shí)則傳出complete()
var source = Rx.Observable.of('Jerry', 'Anna');
from()與of()很相似败许,只不過傳入的是一個(gè)可以被枚舉的參數(shù)王带,例如array,set市殷,iterator甚至是promise(可以使用fromPromise)等等(object和string應(yīng)該能被傳入)
var source = Rx.Observable.from(['Jerry', 'Anna']);
fromEvent()用于監(jiān)聽事件愕撰,在next中傳回的將是被觸發(fā)的事件對象
var source = Rx.Observable.fromEvent(document.body, 'click');
fromEventPattern()傳入一個(gè)事件的觸發(fā)與取消,監(jiān)聽一次?
var source = Rx.Observable
? ? .fromEventPattern(
? ? ? ? (handler) => egghead.addListener(handler),
? ? ? ? (handler) => egghead.removeListener(handler)
? ? );
empty()傳入一個(gè)空的觀測序列搞挣,被訂閱后立刻輸出complete
var source = Rx.Observable.empty();
never()傳入一個(gè)永遠(yuǎn)不會(huì)結(jié)束但什么也不干的觀測序列带迟,被訂閱后什么都不會(huì)發(fā)生
var source = Rx.Observable.never();
throw()傳入一個(gè)立刻回拋出異常的觀測序列,被訂閱后立刻拋出這個(gè)錯(cuò)誤
var source = Rx.Observable.throw('Oop!');
interval()傳入一個(gè)按interval傳入?yún)?shù)(單位為ms)間隔發(fā)出next(從0開始)的觀測序列,其中next()傳出的值為次數(shù)囱桨,由0開始
var source = Rx.Observable.interval(1000);
timer()與之類似仓犬,當(dāng)傳入一個(gè)參數(shù)時(shí)類似于setTimeout,當(dāng)設(shè)定兩個(gè)參數(shù)時(shí)蝇摸,第一個(gè)參數(shù)表示第一次next拋出的時(shí)間婶肩,第二個(gè)參數(shù)表示每次next的間隔
var source = Rx.Observable.timer(1000, 5000);
var source = Rx.Observable.timer(1000);
分割線-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operator:
map()將原有observable按一定規(guī)則映射成為一個(gè)新的observable
var source = Rx.Observable.interval(1000);
var newest = source.map(x => x + 2);
mapTo()將原有observable按映射成為一個(gè)傳出定值的observable
var source = Rx.Observable.interval(1000);
var newest = source.mapTo(2);
filter()將原有的observable根據(jù)規(guī)則過濾成為一個(gè)新的observable
var source = Rx.Observable.interval(1000);
var newest = source.filter(x => x % 2 === 0);
take()取原有的observable的前n項(xiàng),并傳出complete()
var source = Rx.Observable.interval(1000);
var example = source.take(3);
first()等同于take(1)
takeLast()指去最后n個(gè)貌夕,順序依然是正序
var source = Rx.Observable.interval(1000).take(6);
var example = source.takeLast(2);? ? ? ? ? // 輸出4,5
last()等同于takeLast(1)
skip()跳過n個(gè)next
var source = Rx.Observable.interval(1000);
var example = source.skip(3);
takeUntil()在某件事發(fā)生時(shí)律歼,出發(fā)observable的complete()
var source = Rx.Observable.interval(1000);
var click = Rx.Observable.fromEvent(document.body, 'click');
var example = source.takeUntil(click);
concat()把多個(gè)Observable合并成一個(gè)
var source = Rx.Observable.interval(1000).take(3);
var source2 = Rx.Observable.of(3)
var source3 = Rx.Observable.of(4,5,6)
var example = source.concat(source2, source3);
startWith()是在原observable發(fā)送之前添加一些不是observable但是需要被發(fā)送的元素
var source = Rx.Observable.interval(1000);
var example = source.startWith(0);
concatAll()將一個(gè)內(nèi)含Observable的Observable中的所有Observable合并成為一個(gè)Observable
var obs1 = Rx.Observable.interval(1000).take(5);
var obs2 = Rx.Observable.interval(500).take(2);
var obs3 = Rx.Observable.interval(2000).take(1);
var source = Rx.Observable.of(obs1, obs2, obs3);
var example = source.concatAll();
concat和concatAll會(huì)嚴(yán)格按順序執(zhí)行,如上文例子輸出為0,1,2,3,4,0,1,0
merge()與concat類似啡专,但是最大的區(qū)別在于多個(gè)observable會(huì)并發(fā)進(jìn)行险毁,任意一個(gè)observable發(fā)送next時(shí)都會(huì)對之進(jìn)行處理
var source = Rx.Observable.interval(500).take(3);
var source2 = Rx.Observable.interval(300).take(6);
var example = source.merge(source2);
一個(gè)簡單的RxJs拖拽代碼
const dragDOM = document.getElementById('drag');
const body = document.body;
const mouseDown = Rx.Observable.fromEvent(dragDOM, 'mousedown');
const mouseUp = Rx.Observable.fromEvent(body, 'mouseup');
const mouseMove = Rx.Observable.fromEvent(body, 'mousemove');
mouseDown
.map(event => mouseMove.takeUntil(mouseUp))? ? ? ? ? ? ? ? ? ? //這兩行比較精髓個(gè)人感覺
? .concatAll()
? .map(event => ({ x: event.clientX, y: event.clientY }))
? .subscribe(pos => {
? dragDOM.style.left = pos.x + 'px';
? ? dragDOM.style.top = pos.y + 'px';
? })
分割線-------------------------------------------------------------------------------------------------------------------------------------------------------------------
combineLatest()每當(dāng)一個(gè)observable輸出數(shù)據(jù)時(shí)則調(diào)用回調(diào)函數(shù),若另一個(gè)observable并沒有數(shù)據(jù)輸出則不調(diào)用回調(diào)函數(shù)。
var source = Rx.Observable.interval(500).take(3);
var newest = Rx.Observable.interval(300).take(6);
var example = source.combineLatest(newest, (x, y) => x + y);
source : ----0----1----2|
newest : --0--1--2--3--4--5|
combineLatest(newest, (x, y) => x + y);
example: ----01--23-4--(56)--7|
輸出拆分為 0+0们童, 1+0畔况, 2+0,1+2慧库,3+1跷跪,4+1,2+4齐板,5+2吵瞻;
withLatestFrom()與combineLastest類似,但是只有主函數(shù)輸出時(shí)才會(huì)執(zhí)行回調(diào)函數(shù)
var main = Rx.Observable.from('hello').zip(Rx.Observable.interval(500), (x, y) => x);
var some = Rx.Observable.from([0,1,0,0,0,1]).zip(Rx.Observable.interval(300), (x, y) => x);
var example = main.withLatestFrom(some, (x, y) => {
? ? return y === 1 ? x.toUpperCase() : x;
});
訂閱后輸出helLO
zip()則是把每個(gè)observable相同發(fā)送次數(shù)的值放在一次進(jìn)行操作
var source = Rx.Observable.interval(500).take(3);
var newest = Rx.Observable.interval(300).take(6).takeLast(4);
var example = source.zip(newest, (x, y) => x + y);
source : ----0----1----2|
newest : --2--3--4--5|
? ? zip(newest, (x, y) => x + y)
example: ----2----4----6|
輸出拆分為:0+2,1+3,2+4
利用zip我們能很方便的將同步的一些observable變成異步的甘磨,比如
var source = Rx.Observable.from('hello');
var source2 = Rx.Observable.interval(100);
var example = source.zip(source2, (x, y) => x);
這個(gè)例子就能將hello的字母每經(jīng)過100ms輸出一個(gè)橡羞。
分割線-------------------------------------------------------------------------------------------------------------------------------------------------------------------
scan()類似于js的reduce方法,即會(huì)保留上一次next的結(jié)果值并傳入下一次計(jì)算的回調(diào)函數(shù)济舆,作為第一個(gè)參數(shù)
var source = Rx.Observable.from('hello')
? ? ? ? ? ? .zip(Rx.Observable.interval(600), (x, y) => x);
var example = source.scan((origin, next) => origin + next, '');
source : ----h----e----l----l----o|
? ? scan((origin, next) => origin + next, '')
example: ----h----(he)----(hel)----(hell)----(hello)|
buffer()會(huì)將一個(gè)observable的next輸出暫存起來卿泽,直到另一個(gè)observable傳出next時(shí)將緩存區(qū)內(nèi)的所有數(shù)據(jù)通過數(shù)組形式傳出。
var source = Rx.Observable.interval(300);
var source2 = Rx.Observable.interval(1000);
var example = source.buffer(source2);
source : --0--1--2--3--4--5--6--7..
source2: ---------0---------1--------...
? ? ? ? ? ? buffer(source2)
example: ---------([0,1,2])---------([3,4,5])
bufferTime()則是設(shè)定一個(gè)緩存周期滋觉,每經(jīng)過這一個(gè)周期則將緩存內(nèi)的數(shù)據(jù)通過數(shù)組傳出签夭。
var source = Rx.Observable.interval(300);
var example = source.bufferTime(1000);
bufferCount()則設(shè)定一個(gè)緩存大小,每當(dāng)緩存達(dá)到大小時(shí)將數(shù)據(jù)輸出
var source = Rx.Observable.interval(300);
var example = source.bufferCount(3);
bufferToggle()傳入一個(gè)Open Observable和一個(gè)Close Observable以及一個(gè)source Observable椎瘟,每當(dāng)Close傳出一個(gè)
next時(shí)覆致,查找Open的上一個(gè)next(),則將這兩個(gè)next()區(qū)間內(nèi)的所有source的next傳出肺蔚。
const source$ = Rx.Observable.interval(500);
const open$ = Rx.Observable.interval(1500);
const close$ = Rx.Observable.interval(1000);
const foo$ = source$.bufferToggle(open$, ( ) => {
? return close$;
});
/**
---0---1---2---3---4---5---6---7---8---9----....? ? (source)
-----------1-----------2-----------3--------...? ? ? (open)
? ? ? ? ? --- ---x? ? --- ---x? ? --- ---x...? ? ? (close)
? ? ? ? bufferToggle(open$, () => close$)
------------------([2,3])-----([5.6])-----([8,9])--...
*/
bufferWhen()類似與buffer()煌妈,不過bufferWhen的參數(shù)是一個(gè)function,他的返回值為關(guān)閉buffer的observable
const open$ = Rx.Observable.interval(1000);
const click$ = Rx.Observable.fromEvent(document, 'click');
var w = open$.bufferWhen(( ) => click$);
w.subscribe(x => console.log(x))
// 每次點(diǎn)擊都能進(jìn)行一次分組
// 第二秒點(diǎn)擊第一次:[0, 1, 2]
// 第六秒點(diǎn)擊第二次:[3, 4, 5, 6]
分割線-------------------------------------------------------------------------------------------------------------------------------------------------------------------
delay()可以延遲observable一開始發(fā)送next的時(shí)間,也可以傳遞毫秒數(shù),也可以傳遞一個(gè)時(shí)間璧诵。
var source = Rx.Observable.interval(300).take(5);
var example = source.delay(500);
var example2 = source.delay(new Date(Date.now() + 500)); //此二式結(jié)果相同
source : --0--1--2--3--4|
? ? ? ? delay(500)
example: -------0--1--2--3--4|
delayWhen()和delay相似汰蜘,但是最大的不同是他會(huì)延時(shí)每一個(gè)next(),而不像delay只會(huì)延時(shí)第一個(gè)next()
var source = Rx.Observable.interval(300).take(5);
var example = source
? ? ? ? ? ? ? .delayWhen(
? ? ? ? ? ? ? ? ? x => Rx.Observable.empty().delay(100 * x * x)
? ? ? ? ? ? ? );
source : --0--1--2--3--4|
? ? .delayWhen(x => Rx.Observable.empty().delay(100 * x * x));
example: --0---1----2-----3-----4|
debounce()傳入一個(gè)debounce observable,每當(dāng)source observable傳出next時(shí)之宿,不會(huì)立刻將之直接傳出族操,而是將之緩存,
如果在收到debounce傳出的next之前沒有收到其他source傳出的next比被,那么將此次緩存的next傳出色难,否則則將新的source next存入緩存,并等待下一次debounce的來臨等缀。
debounceTime()則是一個(gè)debounce的簡化版枷莉,他接收一個(gè)時(shí)間參數(shù),等同于一個(gè)interval Operator創(chuàng)建的observable尺迂。
//疑問:complete是否與next效果相同笤妙,在下面例子中在觀測前記錄Date.now()并在送出next后幾率Date.now()會(huì)發(fā)現(xiàn)時(shí)間相差會(huì)1.
var source = Rx.Observable.interval(300).take(5);
var oDebounce = Rx.Observable.interval(1000);
var example = source.debounceTime(1000);
var example2 = source.debounce(() => oDebounce);? //此二式效果相同
source : --0--1--2--3--4|
? ? ? ? debounceTime(1000)
example: --------------4|?