30 天精通 RxJS(20): Observable Operators - window, windowToggle

前幾天我們講完了能把 Higher Order Observable 轉(zhuǎn)成一般的 Observable 的 operators找爱,今天我們要講能夠把一般的 Observable 轉(zhuǎn)成 Higher Order Observable 的 operators梗顺。

其實前端不太有機會用到這類型的 Operators,都是在比較特殊的需求下才會看到车摄,但還是會有遇到的時候寺谤。

Operators

window

window 是一整個家族,總共有五個相關(guān)的 operators

  • window
  • windowCount
  • windowTime
  • windowToggle
  • windowWhen

這裡我們只介紹 window 跟 windowToggle 這兩個方法吮播,其他三個的用法相對都簡單很多变屁,大家如果有需要可以再自行到官網(wǎng)查看。

window 很類似 buffer 可以把一段時間內(nèi)送出的元素拆出來意狠,只是 buffer 是把元素拆分到陣列中變成

Observable<T> => Observable<Array<T>>

而 window 則是會把元素拆分出來放到新的 observable 變成

Observable<T> => Observable<Observable<T>>

buffer 是把拆分出來的元素放到陣列并送出陣列粟关;window 是把拆分出來的元素放到 observable 并送出 observable,讓我們來看一個例子

var click = Rx.Observable.fromEvent(document, 'click');
var source = Rx.Observable.interval(1000);
var example = source.window(click);

example
  .switch()
  .subscribe(console.log);
// 0
// 1
// 2
// 3
// 4
// 5 ...

首先 window 要傳入一個 observable环戈,每當(dāng)這個 observable 送出元素時闷板,就會把正在處理的 observable 所送出的元素放到新的 observable 中并送出,這裡看 Marble Diagram 會比較好解釋

click  : -----------c----------c------------c--
source : ----0----1----2----3----4----5----6---..
                    window(click)
example: o----------o----------o------------o--
         \          \          \
          ---0----1-|--2----3--|-4----5----6|
                    switch()
       : ----0----1----2----3----4----5----6---... 

這裡可以看到 example 變成發(fā)送 observable 會在每次 click 事件發(fā)送出來后結(jié)束院塞,并繼續(xù)下一個 observable遮晚,這裡我們用 switch 才把它攤平。

當(dāng)然這個范例只是想單存的表達 window 的作用拦止,沒什麼太大的意義县遣,實務(wù)上 window 會搭配其他的 operators 使用,例如我們想計算一秒鐘內(nèi)觸發(fā)了幾次 click 事件

var click = Rx.Observable.fromEvent(document, 'click');
var source = Rx.Observable.interval(1000);
var example = click.window(source)

example
  .map(innerObservable => innerObservable.count())
  .switch()
  .subscribe(console.log);

JSBin | JSFiddle

注意這裡我們把 source 跟 click 對調(diào)了,并用到了 observable 的一個方法 count()萧求,可以用來取得 observable 總共送出了幾個元素括蝠,用 Marble Diagram 表示如下

source : ---------0---------1---------2--...
click  : --cc---cc----c-c----------------...
                    window(source)
example: o--------o---------o---------o--..
         \        \         \         \
          -cc---cc|---c-c---|---------|--..
                    count()
       : o--------o---------o---------o--
         \        \         \         \
          -------4|--------2|--------0|--..
                    switch()
       : ---------4---------2---------0--... 

從 Marble Diagram 中可以看出來,我們把部分元素放到新的 observable 中饭聚,就可以利用 Observable 的方法做更靈活的操作

windowToggle

windowToggle 不像 window 只能控制內(nèi)部 observable 的結(jié)束忌警,windowToggle 可以傳入兩個參數(shù),第一個是開始的 observable秒梳,第二個是一個 callback 可以回傳一個結(jié)束的 observable法绵,讓我們來看范例

var source = Rx.Observable.interval(1000);
var mouseDown = Rx.Observable.fromEvent(document, 'mousedown');
var mouseUp = Rx.Observable.fromEvent(document, 'mouseup');

var example = source
  .windowToggle(mouseDown, () => mouseUp)
  .switch();

example.subscribe(console.log);

JSBin | JSFiddle

一樣用 Marble Diagram 會比較好解釋

source   : ----0----1----2----3----4----5--...

mouseDown: -------D------------------------...
mouseUp  : ---------------------------U----...

        windowToggle(mouseDown, () => mouseUp)

         : -------o-------------------------...
                  \
                   -1----2----3----4--|
                   switch()
example  : ---------1----2----3----4---------...                                     

從 Marble Diagram 可以看得出來,我們用 windowToggle 拆分出來內(nèi)部的 observable 始于 mouseDown 終于 mouseUp酪碘。

groupBy

最后我們來講一個實務(wù)上比較常用的 operators - groupBy朋譬,它可以幫我們把相同條件的元素拆分成一個 Observable,其實就跟平常在下 SQL 是一樣個概念兴垦,我們先來看個簡單的例子

var source = Rx.Observable.interval(300).take(5);

var example = source
              .groupBy(x => x % 2);

example.subscribe(console.log);

// GroupObservable { key: 0, ...}
// GroupObservable { key: 1, ...}

JSBin | JSFiddle

上面的例子徙赢,我們傳入了一個 callback function 并回傳 groupBy 的條件,就能區(qū)分每個元素到不同的 Observable 中探越,用 Marble Diagram 表示如下

source : ---0---1---2---3---4|
             groupBy(x => x % 2)
example: ---o---o------------|
            \   \
            \   1-------3----|
            0-------2-------4|

在實務(wù)上狡赐,我們可以拿 groupBy 做完元素的區(qū)分后,再對 inner Observable 操作钦幔,例如下面這個例子我們將每個人的分數(shù)作加總再送出

var people = [
    {name: 'Anna', score: 100, subject: 'English'},
    {name: 'Anna', score: 90, subject: 'Math'},
    {name: 'Anna', score: 96, subject: 'Chinese' }, 
    {name: 'Jerry', score: 80, subject: 'English'},
    {name: 'Jerry', score: 100, subject: 'Math'},
    {name: 'Jerry', score: 90, subject: 'Chinese' }, 
];
var source = Rx.Observable.from(people)
                           .zip(
                             Rx.Observable.interval(300), 
                             (x, y) => x);

var example = source
  .groupBy(person => person.name)
  .map(group => group.reduce((acc, curr) => ({ 
        name: curr.name,
        score: curr.score + acc.score 
    })))
    .mergeAll();

example.subscribe(console.log);
// { name: "Anna", score: 286 }
// { name: 'Jerry', score: 270 }

JSBin | JSFiddle

這裡我們范例是想把 Jerry 跟 Anna 的分數(shù)個別作加總枕屉,畫成 Marble Diagram 如下

source : --o--o--o--o--o--o|

  groupBy(person => person.name)

       : --i--------i------|
           \        \
           \         o--o--o|
            o--o--o--|

       map(group => group.reduce(...))

       : --i---------i------|
           \         \
           o|        o|

             mergeAll()
example: --o---------o------|           

今日小結(jié)

今天講了兩個可以把元素拆分到新的 observable 的 operators,這兩個 operators 在前端比較少用到鲤氢,但在后端或是比較複雜了前端應(yīng)用才比較有機會用到搀擂。不知道讀者有沒有收穫呢? 如果有任何問題歡迎留言給我卷玉,謝謝哨颂。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市相种,隨后出現(xiàn)的幾起案子威恼,更是在濱河造成了極大的恐慌,老刑警劉巖蚂子,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沃测,死亡現(xiàn)場離奇詭異缭黔,居然都是意外死亡食茎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門馏谨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來别渔,“玉大人,你說我怎么就攤上這事“ッ模” “怎么了喇伯?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拨与。 經(jīng)常有香客問我稻据,道長,這世上最難降的妖魔是什么买喧? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任捻悯,我火速辦了婚禮,結(jié)果婚禮上淤毛,老公的妹妹穿的比我還像新娘今缚。我一直安慰自己,他們只是感情好低淡,可當(dāng)我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布姓言。 她就那樣靜靜地躺著,像睡著了一般蔗蹋。 火紅的嫁衣襯著肌膚如雪何荚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天猪杭,我揣著相機與錄音兽泣,去河邊找鬼。 笑死胁孙,一個胖子當(dāng)著我的面吹牛唠倦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涮较,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼稠鼻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了狂票?” 一聲冷哼從身側(cè)響起候齿,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎闺属,沒想到半個月后慌盯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡掂器,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年亚皂,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片国瓮。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡灭必,死狀恐怖狞谱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情禁漓,我是刑警寧澤跟衅,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站播歼,受9級特大地震影響伶跷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜秘狞,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一撩穿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谒撼,春花似錦食寡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至辩蛋,卻和暖如春呻畸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背悼院。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工伤为, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人据途。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓绞愚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親颖医。 傳聞我的和親對象是個殘疾皇子位衩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內(nèi)容