為避免 User 產生重複 API Request,將 Button Disabled 是一種方式,也可改用 exhaustMap()
實現。
Version
macOS Catalina 10.15.4
WebStorm 2020.1
Vue 2.6.11
RxJS 6.5.5
switchMap()
未使用 disabled button,因此 user 的每一個 click 都會產生新的 API request。
<template>
<div>
<button v-stream:click="{ subject: click$, data: 1 }">Show book</button>
<h1>{{ title$ }}</h1>
<img :src="image$">
</div>
</template>
<script>
import { ajax } from 'rxjs/ajax'
import { delay, map, pluck, share, switchMap } from 'rxjs/operators'
let fetchBook$ = x => ajax(`http://localhost:3000/books/${x}`).pipe(
delay(10000),
pluck('response')
)
let subscriptions = function() {
let book$ = this.click$.pipe(
pluck('data'),
switchMap(fetchBook$),
share()
)
let title$ = book$.pipe(pluck('title'))
let image$ = book$.pipe(
pluck('image'),
map(x => `/images/${x}`)
)
return { title$, image$ }
}
export default {
name: 'app',
domStreams: ['click$'],
subscriptions,
}
</script>
13 行
let fetchBook$ = x => ajax(`http://localhost:3000/books/${x}`).pipe(
delay(10000),
pluck('response')
)
Delay 10 秒鐘模擬慢速網路。
19 行
let book$ = this.click$.pipe(
pluck('data'),
switchMap(fetchBook$),
share()
)
直覺會使用 switchMap()
實現。
exhaustMap()
當 API 尚未完全回傳資料時,無論 user 按幾次 click 都不會產生新的 API request,這才是我們所要的。
<template>
<div>
<button v-stream:click="{ subject: click$, data: 1 }">Show book</button>
<h1>{{ title$ }}</h1>
<img :src="image$">
</div>
</template>
<script>
import { ajax } from 'rxjs/ajax'
import { delay, map, pluck, share, exhaustMap } from 'rxjs/operators'
let fetchBook$ = x => ajax(`http://localhost:3000/books/${x}`).pipe(
delay(10000),
pluck('response')
)
let subscriptions = function() {
let book$ = this.click$.pipe(
pluck('data'),
exhaustMap(fetchBook$),
share()
)
let title$ = book$.pipe(pluck('title'))
let image$ = book$.pipe(
pluck('image'),
map(x => `/images/${x}`)
)
return { title$, image$ }
}
export default {
name: 'app',
domStreams: ['click$'],
subscriptions,
}
</script>
19 行
let book$ = this.click$.pipe(
pluck('data'),
exhaustMap(fetchBook$),
share()
)
從 swtichMap()
換成 exhaustMap()
問題就解決了。
1
、3
、5
可視為每次 user click,10
、10
、10
可視為每次 API 回傳資料,要傳 3 個 10
才算回傳完全。
關鍵在第三次按 5
是在第二次 API 尚未回傳完全時按下,switchMap()
會取消原本傳輸而發起新的 API request,這就是 switchMap()
造成重複 API request 主因,且第二次傳輸的資料不完全也是錯的。
exhaustMap()
則不然,因為第二次 API 尚未回傳完全,因此拒絕了 user 第三次按 5
所發起的新 API request,所以不會有重複 API request,且資料都是完整的。
Conclusion
exhaustMap()
在實務上經常使用,除了不會造成重複 API request 外,也能確保每次都是回傳完整資料,不會中途放棄而造成資料錯誤