RxJS,如何轮询API以使用动态时间戳持续检查更新的记录

时间:2015-12-31 10:46:34

标签: javascript rxjs

我是RxJS的新手,我正在尝试编写一个可以完成以下任务的应用程序:

  1. 在加载时,为了简单起见,发出一个AJAX请求(伪造为fetchItems())以获取项目列表。
  2. 在此之后的每一秒,发出一个AJAX请求来获取项目。
  3. 检查新项目时,仅返回最近时间戳后更改的项目。
  4. 不应该是观察者外部的任何状态。
  5. 我的first attempt非常直接,达到了目标1,2和4。

    var data$ = Rx.Observable.interval(1000)
      .startWith('run right away')
      .map(function() { 
        // `fetchItems(modifiedSince)` returns an array of items modified after `modifiedSince`, but
        // I am not yet tracking the `modifiedSince` timestamp yet so all items will always be returned
        return fetchItems(); 
      });
    

    现在我很兴奋,这很容易,要达到目标3要困难得多......几个小时之后这就是where I am at

    var modifiedSince = null;
    var data$ = Rx.Observable.interval(1000)
      .startWith('run right away')
      .flatMap(function() { 
        // `fetchItems(modifiedSince)` returns an array of items modified after `modifiedSince`
        return fetchItems(modifiedSince);
      })
      .do(function(item) {
        if(item.updatedAt > modifiedSince) {
          modifiedSince = item.updatedAt;
        }
      })
      .scan(function(previous, current) {
        previous.push(current);
        return previous;
      }, []);
    

    这解决了目标3,但在目标4上倒退。我现在将状态存储在可观察目标之外。

    我假设全局modifiedSince.do()块不是实现此目标的最佳方式。任何指导都将不胜感激。

    编辑:希望通过这个问题澄清我在寻找什么。

3 个答案:

答案 0 :(得分:3)

这是另一个不使用闭包或“外部状态”的解决方案。

我做了以下假设:

  • fetchItems会返回Rx.Observable个项目,即不是项目数组

它使用expand运算符,它允许发出遵循类型x_n+1 = f(x_n)的递归关系的值。您通过返回发出该值的observable来传递x_n+1,例如Rx.Observable.return(x_n+1),您可以通过返回Rx.Observable.empty()来完成递归。这似乎你没有结束条件所以这将永远运行。

scan还允许在递归关系(x_n+1 = f(x_n, y_n))之后发出值。区别在于scan强制您使用同步函数(因此x_n+1y_n同步),而使用expand则可以使用异步函数一个可观察的。

代码未经过测试,如果有效,请及时通知我。

相关文档:expandcombineLatest

var modifiedSinceInitValue = // put your date here
var polling_frequency = // put your value here
var initial_state = {modifiedSince: modifiedSinceInitValue, itemArray : []}
function max(property) {
  return function (acc, current) {
    acc = current[property] > acc ? current[property] : acc;
  }
}    
var data$ = Rx.Observable.return(initial_state)
  .expand (function(state){
             return fetchItem(state.modifiedSince)
                   .toArray()
                   .combineLatest(Rx.Observable.interval(polling_frequency).take(1), 
                     function (itemArray, _) {
                       return {
                         modifiedSince : itemArray.reduce(max('updatedAt'), modifiedSinceInitValue), 
                         itemArray : itemArray
                       }
                     }

  })

答案 1 :(得分:1)

这个怎么样:

var interval = 1000;
function fetchItems() {
    return items;
}

var data$ = Rx.Observable.interval(interval)
  .map(function() { return fetchItems(); })
  .filter(function(x) {return x.lastModified > Date.now() - interval}
  .skip(1)
  .startWith(fetchItems());

那应该只为新项目过滤来源,再加上完整的集合。只需编写适合您的数据源的过滤器功能。

或者通过将参数传递给fetchItems:

var interval = 1000;
function fetchItems(modifiedSince) {
    var retVal = modifiedSince ? items.filter( function(x) {return x.lastModified > modifiedSince}) : items
    return retVal;
}

var data$ = Rx.Observable.interval(interval)
  .map(function() { return fetchItems(Date.now() - interval); })
  .skip(1)
  .startWith(fetchItems());

答案 2 :(得分:1)

您似乎意味着modifiedSince是您所携带的州的一部分,因此它应该出现在scan中。为什么不将do中的操作移动到扫描中呢?那么你的种子就是{modifiedSince: null, itemArray: []}

错误,我只是认为这可能不起作用,因为您需要将modifiedSince反馈给上游的fetchItem函数。你不在这里骑自行车吗?这意味着你必须使用一个主题来打破这个循环。或者,您可以尝试将modifiedSince封装在闭包中。像

这样的东西
function pollItems (fetchItems, polling_frequency) {
var modifiedSince = null;
var data$ = Rx.Observable.interval(polling_frequency)
  .startWith('run right away')
  .flatMap(function() { 
    // `fetchItems(modifiedSince)` returns an array of items modified after `modifiedSince`
    return fetchItems(modifiedSince);
  })
  .do(function(item) {
    if(item.updatedAt > modifiedSince) {
      modifiedSince = item.updatedAt;
    }
  })
  .scan(function(previous, current) {
    previous.push(current);
    return previous;
  }, []);

return data$;
}

我必须跑出去庆祝新的一年,如果这不起作用,我可以稍后再尝试(可能使用expand运算符,scan的其他版本。)