
我們在昨天day31有介紹到startWith及endWith的用法,也建議大家將startWith放置於pipe底下,避免不可預期的情形發生。
今天我們來寫一個範例,並進一步驗證startWith擺在不同地方會發生什麼情形!
startWith及endWith擺放順序的重要性,我們來寫個例子
- 這裡我們定義一個變數
countDownMaxNum,來提供scan的初始值及startWith使用。- 可參考day12-scan複習如何寫一個倒數計時器。
...
<body>
<button id="start">start</button>
<button id="stop">stop</button>
<h1 id="number">-</h1>
</body>
...
import {
endWith,
from,
fromEvent,
interval,
map,
startWith,
scan,
takeUntil,
takeWhile,
switchMap,
tap,
throwError,
} from 'rxjs';
//elems
const start = document.getElementById('start');
const stop = document.getElementById('stop');
const num = document.getElementById('number');
// RxJS
const start$ = fromEvent(start, 'click');
const stop$ = fromEvent(stop, 'click');
const timer$ = interval(1000);
// === Step1: 建置一個倒數計時器,並宣告一個變數countDownMaxNum提供給scan及startWith使用 ===
const countDownMaxNum = 10;
const countDown$ = timer$.pipe(
map(() => -1),
scan((accu, current) => accu + current, countDownMaxNum),
takeWhile((d) => d > 0),
takeUntil(stop$)
);
// === Step2: 設定click to start,並觀察不同位置的startWith有什麼不同 ===
console.log('=== startWith放在pipe的底部 ===');
const clickStart$ = start$
.pipe(
// 觀察看看startWith放位置(1)及(2)有什麼不同
// startWith(countDownMaxNum), //<-- (1)
switchMap(() => countDown$),
startWith(countDownMaxNum) //<--(2) 現在測試這個位置
)
.subscribe((d) => (num.innerHTML = `${d}`));

startWith就先拋出初始值countDownMaxNum,提供顯示在num.innerHTML之中,所以從頁面可以看到初始值是10。start,開始倒數,中途按下stop,數字靜止。start,數字從9開始,而不是我們預期的10??
startWith在observable開始之前,會優先發送一個數值給observer.next(),因此我們可以如期在頁面初始狀態上,看到10這個數字。
在那之後,startWith就不會再發送,也因此,當你再度按下start,數字會直接從9開始,也就是直接跑scan送出的值。
...
console.log('=== startWith放在pipe的 "最上層" ===');
const clickStart$ = start$
.pipe(
// 觀察看看startWith放位置(1)及(2)有什麼不同
startWith(countDownMaxNum), //<-- (1) 現在測試這個位置
switchMap(() => countDown$)
// startWith(countDownMaxNum) //<--(2)
)
.subscribe((d) => (num.innerHTML = `${d}`));

startWith擺在switchMap之前,startWith在點擊之前發出訊號10,間接觸發了switchMap開始計數,才會還沒點擊就先偷跑計數啦!
startWith擺放的位置,確實會影響,因為他會優先於observable訂閱運作之前,先行發出訊號,如果後方有其他的operator,自然會將數值傳遞過去,提前運作,造成不可預期的現象。
接下來我會不定期的持續發佈RxJS的學習心得,也請大家繼續支持! ![]()