簡體   English   中英

棘手的蒸汽可觀察合並在rxjs中

[英]Tricky steam observable merge in rxjs

我可以使用一些幫助。 我正在嘗試一個實驗,我在按鈕的鼠標上啟動我的ajax請求,但是如果用戶點擊(或者如果用戶點擊時請求尚未完成,則消耗結果為盡快)。 如果用戶在未單擊的情況下離開按鈕,則應取消該請求。

我遇到的問題是如何將點擊流與請求流合並。 我不能使用withLatestFrom,因為如果請求在點擊后完成,它將不會被使用。 我也不能使用combineLatest,因為如果過去發生了任何點擊,那么請求將被消耗,即使我目前只是將鼠標移除。 會喜歡一些指導。 這是一個有趣的問題,但我被困住了

const fetchContent = (url) => {
  const timeDelay$ = Rx.Observable.timer(1000); // simulating a slow request
  const request$ =  Rx.Observable.create(observer =>
    fetch(url, { mode: 'no-cors' })
      .then(json => {
         observer.onNext('res')
         observer.onCompleted()
      })
      .catch(e => observer.onError())
  )
  return timeDelay$.concat(request$)
}
const hover$ = Rx.Observable.fromEvent(myButton, 'mouseenter')
const leave$ = Rx.Observable.fromEvent(myButton, 'mouseleave')
const click$ = Rx.Observable.fromEvent(myButton, 'click')

const hoverRequest$ = hover$
  .flatMap(e =>
    fetchContent(e.target.getAttribute('href'))
      .takeUntil(leave$.takeUntil(click$))
  )

const displayData$ = click$
  .combineLatest(hoverRequest$)

displayData$.subscribe(x => console.log(x))

你實際上並不是很遠。 你真的錯過了zip的包含。 既然你真正需要的是傳播兩個鼠標點擊來完成請求。 通過壓縮請求和鼠標單擊事件,您可以確保兩者都不會發出。

const hover$ = Rx.Observable.fromEvent(myButton, 'mouseenter');
const leave$ = Rx.Observable.fromEvent(myButton, 'mouseleave');
const click$ = Rx.Observable.fromEvent(myButton, 'click');


//Make sure only the latest hover is emitting requests
hover$.flatMapLatest(() => {

  //The content request
  const pending$ = fetchContent();

  //Only cancel on leave if no click has been made
  const canceler$ = leave$.takeUntil(click$);

  //Combine the request result and click event so they wait for each other
  return Rx.Observable.zip(pending$, click$, (res, _) => res)

               //Only need the first emission
               .take(1)

               //Cancel early if the user leaves the button
               .takeUntil(canceler$);

});

也許你可以把它概念化為三個事件(懸停,離開,點擊你調用它們)觸發三個動作(發出請求,取消請求,傳遞請求結果)修改狀態(請求?傳遞請求?)。

現在這是在周日晚上匆匆忙忙完成的,但運氣稍微好一點,這樣的事情可行:

function label(str) {return function(x){var obj = {}; obj[str] = x; return obj;}}
function getLabel(obj) {return Object.keys(obj)[0];}
const hover$ = Rx.Observable.fromEvent(myButton, 'mouseenter').map(label('hover'));
const leave$ = Rx.Observable.fromEvent(myButton, 'mouseleave').map(label('leave'));
const click$ = Rx.Observable.fromEvent(myButton, 'click').map(label('click'));

var initialState = {request : undefined, response : undefined, passResponse : false};

var displayData$ = Rx.Observable.merge(hover$, leave$, click$)
  .scan(function (state, intent){
          switch (getLabel(intent)) {
            case 'hover' : 
              if (!state.request) {
                state.request = someRequest;
                state.response$ = Rx.Observable.fromPromise(executeRequest(someRequest));
              }
            break;
            case 'leave' : 
              if (state.request && !state.passResponse) cancelRequest(someRequest);
              state.passResponse = false;
            break;
            case 'click' :
              if (!state.request) {
                state.response$ = Rx.Observable.fromPromise(executeRequest(someRequest));
              }
              state.passResponse = true;
          }
        }, initial_state)
  .filter(function (state){return state.passResponse;})
  .pluck('response$')
  .concatAll()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM