Javascript rxjs中棘手的蒸汽可观测合并

Javascript rxjs中棘手的蒸汽可观测合并,javascript,rxjs,Javascript,Rxjs,我需要一些帮助。我正在尝试一个实验,在按钮的鼠标上启动ajax请求,但仅在用户单击时使用该请求的结果(或者如果用户单击时请求尚未完成,则尽快使用结果)。如果用户未单击就离开按钮,则应取消请求 我陷入困境的是如何将点击流与请求流合并。我不能使用withLatestFrom,因为如果在单击之后请求完成,它将不会被消费。我也不能使用CombineTest,因为如果以前有任何点击,请求的内容都会被使用,即使我现在只是在鼠标上移动。 我想要一些指导。这是一个很有趣的问题,但我被卡住了 const fetc

我需要一些帮助。我正在尝试一个实验,在按钮的鼠标上启动ajax请求,但仅在用户单击时使用该请求的结果(或者如果用户单击时请求尚未完成,则尽快使用结果)。如果用户未单击就离开按钮,则应取消请求

我陷入困境的是如何将点击流与请求流合并。我不能使用withLatestFrom,因为如果在单击之后请求完成,它将不会被消费。我也不能使用CombineTest,因为如果以前有任何点击,请求的内容都会被使用,即使我现在只是在鼠标上移动。 我想要一些指导。这是一个很有趣的问题,但我被卡住了

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))

也许您可以将其概念化为三个事件(悬停、离开、调用时单击),触发三个操作(发出请求、取消请求、传递请求结果)修改状态(请求?传递请求?)

现在,这是在周日晚上匆忙完成的,但如果运气好的话,像这样的事情可能会奏效:

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()

事实上,你离得并不太远。你真的错过了
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$);

});

听起来像是
trial.js
library所做的。查阅不知道他们是否使用rxjs。谢谢你的评论!我来看看。我更多的是把它作为一个实验。