30 天精通 RxJS (13): Observable Operator - delay, delayWhen

在所有非同步中行為中柠衅,最麻煩的大概就是 UI 操作了烤黍,因?yàn)?UI 是直接影響使用者的感受漠吻,如果處理的不好對使用體驗(yàn)會大大的扣分赵誓!

UI 大概是所有非同步行為中最不好處理的打毛,不只是因?yàn)樗苯佑绊懥擞脩趔w驗(yàn),更大的問題是 UI 互動常常是高頻率觸發(fā)的事件俩功,而且多個(gè)元件間的時(shí)間序需要不一致幻枉,要做到這樣的 UI 互動就不太可能用 Promise 或 async/await,但是用 RxJS 仍然能輕易地處理诡蜓!

今天我們要介紹的兩個(gè) Operators熬甫,delay 跟 delayWhen 都是跟 UI 互動比較相關(guān)的。當(dāng)我們的網(wǎng)頁越來越像應(yīng)用程式時(shí)蔓罚,UI 互動就變得越重要椿肩,讓我們來試試如何用 RxJS 完成基本的 UI 互動瞻颂!

Operators

delay

delay 可以延遲 observable 一開始發(fā)送元素的時(shí)間點(diǎn),范例如下

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

var example = source.delay(500);

example.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});
// 0
// 1
// 2
// 3
// 4

JSBin | JSFiddle

當(dāng)然直接從 log 出的訊息看郑象,是完全看不出差異的

讓我們直接看 Marble Diagram

source : --0--1--2--3--4|
        delay(500)
example: -------0--1--2--3--4|

從 Marble Diagram 可以看得出來贡这,第一次送出元素的時(shí)間變慢了,雖然在這裡看起來沒什麼用厂榛,但是在 UI 操作上是非常有用的盖矫,這個(gè)部分我們最后示范。

delay 除了可以傳入毫秒以外击奶,也可以傳入 Date 型別的資料辈双,如下使用方式

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

var example = source.delay(new Date(new Date().getTime() + 1000));

example.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});

JSBin | JSFiddle

這好像也能用在預(yù)定某個(gè)日期,讓程式掛掉

delayWhen

delayWhen 的作用跟 delay 很像柜砾,最大的差別是 delayWhen 可以影響每個(gè)元素湃望,而且需要傳一個(gè) callback 并回傳一個(gè) observable,范例如下

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

var example = source
              .delayWhen(
                  x => Rx.Observable.empty().delay(100 * x * x)
              );

example.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});

JSBin | JSFiddle

這時(shí)我們的 Marble Diagram 如下

source : --0--1--2--3--4|
    .delayWhen(x => Rx.Observable.empty().delay(100 * x * x));
example: --0---1----2-----3-----4|

這裡傳進(jìn)來的 x 就是 source 送出的每個(gè)元素局义,這樣我們就能對每一個(gè)做延遲喜爷。

這裡我們用 delay 來做一個(gè)小功能冗疮,這個(gè)功能很簡單就是讓多張照片跟著滑鼠跑萄唇,但每張照片不能跑一樣快!

首先我們準(zhǔn)備六張大頭照术幔,并且寫進(jìn) HTML

<img src="https://res.cloudinary.com/dohtkyi84/image/upload/c_scale,w_50/v1483019072/head-cover6.jpg" alt="">
<img src="https://res.cloudinary.com/dohtkyi84/image/upload/c_scale,w_50/v1483019072/head-cover5.jpg" alt="">
<img src="https://res.cloudinary.com/dohtkyi84/image/upload/c_scale,w_50/v1483019072/head-cover4.jpg" alt="">
<img src="https://res.cloudinary.com/dohtkyi84/image/upload/c_scale,w_50/v1483019072/head-cover3.jpg" alt="">
<img src="https://res.cloudinary.com/dohtkyi84/image/upload/c_scale,w_50/v1483019072/head-cover2.jpg" alt="">
<img src="https://res.cloudinary.com/dohtkyi84/image/upload/c_scale,w_50/v1483019072/head-cover1.jpg" alt="">

用 CSS 把 img 改成圓形另萤,并加上邊筐以及絕對位置

img{
  position: absolute;
  border-radius: 50%;
  border: 3px white solid;
  transform: translate3d(0,0,0);
}

再來寫 JS,一樣第一步先抓 DOM

var imgList = document.getElementsByTagName('img');

第二步建立 observable

var movePos = Rx.Observable.fromEvent(document, 'mousemove')
.map(e => ({ x: e.clientX, y: e.clientY }))

第三步撰寫邏輯

function followMouse(DOMArr) {
  const delayTime = 600;
  DOMArr.forEach((item, index) => {
    movePos
      .delay(delayTime * (Math.pow(0.65, index) + Math.cos(index / 4)) / 2)
      .subscribe(function (pos){
        item.style.transform = 'translate3d(' + pos.x + 'px, ' + pos.y + 'px, 0)';
      });
  });
}

followMouse(Array.from(imgList))

這裡我們把 imgList 從 Collection 轉(zhuǎn)成 Array 后傳入 followMouse()诅挑,并用 forEach 把每個(gè) omg 取出并利用 index 來達(dá)到不同的 delay 時(shí)間四敞,這個(gè) delay 時(shí)間的邏輯大家可以自己想,不用跟我一樣拔妥,最后 subscribe 就完成啦忿危!

最后完整的范例在這裡

今日小結(jié)

今天我們介紹了兩個(gè) operators 并帶了一個(gè)小范例,這兩個(gè) operators 在 UI 操作上都非常的實(shí)用没龙,我們明天會接著講幾個(gè) operators 可以用來做高頻率觸發(fā)的事件優(yōu)化铺厨!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市硬纤,隨后出現(xiàn)的幾起案子解滓,更是在濱河造成了極大的恐慌,老刑警劉巖筝家,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洼裤,死亡現(xiàn)場離奇詭異,居然都是意外死亡溪王,警方通過查閱死者的電腦和手機(jī)腮鞍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進(jìn)店門值骇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缕减,你說我怎么就攤上這事雷客。” “怎么了桥狡?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵搅裙,是天一觀的道長。 經(jīng)常有香客問我裹芝,道長部逮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任嫂易,我火速辦了婚禮兄朋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘怜械。我一直安慰自己颅和,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布缕允。 她就那樣靜靜地躺著峡扩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪障本。 梳的紋絲不亂的頭發(fā)上教届,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天,我揣著相機(jī)與錄音驾霜,去河邊找鬼案训。 笑死,一個(gè)胖子當(dāng)著我的面吹牛粪糙,可吹牛的內(nèi)容都是我干的强霎。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼蓉冈,長吁一口氣:“原來是場噩夢啊……” “哼城舞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起洒擦,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤椿争,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后熟嫩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秦踪,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了椅邓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柠逞。...
    茶點(diǎn)故事閱讀 40,865評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖景馁,靈堂內(nèi)的尸體忽然破棺而出板壮,到底是詐尸還是另有隱情,我是刑警寧澤合住,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布绰精,位于F島的核電站,受9級特大地震影響透葛,放射性物質(zhì)發(fā)生泄漏笨使。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一僚害、第九天 我趴在偏房一處隱蔽的房頂上張望硫椰。 院中可真熱鬧,春花似錦萨蚕、人聲如沸靶草。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奕翔。三九已至,卻和暖如春寒随,著一層夾襖步出監(jiān)牢的瞬間糠悯,已是汗流浹背帮坚。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工妻往, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人试和。 一個(gè)月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓讯泣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親阅悍。 傳聞我的和親對象是個(gè)殘疾皇子好渠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評論 2 361

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