Javascript 实现Bacon.JS以查找每个用户在第三方小部件上花费的平均时间存在问题

Javascript 实现Bacon.JS以查找每个用户在第三方小部件上花费的平均时间存在问题,javascript,functional-programming,bacon.js,Javascript,Functional Programming,Bacon.js,我目前正在为在线出版商开发一个第三方小部件,并希望跟踪它在不同网站上的表现。我想实现Upworthy的代码()来计算每个用户在我的小部件上花费的平均时间。所以我决定分三步实施: 当我的小部件仅在视口中可见时启动我的“焦点”事件(我的小部件通常嵌入在文章的底部) 接下来,如Upworthy的方法所示,我将把自定义的“聚焦”事件与模糊事件合并,以开发一个isFocused事件 然后,我可以实现他们的recentlyActive方法,以确定用户是否在单击小部件,即他们是否在与我的小部件交互 我已经实现

我目前正在为在线出版商开发一个第三方小部件,并希望跟踪它在不同网站上的表现。我想实现Upworthy的代码()来计算每个用户在我的小部件上花费的平均时间。所以我决定分三步实施:

  • 当我的小部件仅在视口中可见时启动我的“焦点”事件(我的小部件通常嵌入在文章的底部)
  • 接下来,如Upworthy的方法所示,我将把自定义的“聚焦”事件与模糊事件合并,以开发一个isFocused事件
  • 然后,我可以实现他们的recentlyActive方法,以确定用户是否在单击小部件,即他们是否在与我的小部件交互
  • 我已经实现了上述功能,可以在这里找到源代码:

    但是,如果在底部向下滚动,您会发现花费的时间计算为0,并且不会像这里所示的Upworthy实现那样动态更新自身。 我对函数式反应式编程的概念非常陌生,仍在尝试了解Bacon.JS,所以我肯定我犯了一个非常愚蠢的概念性错误,但我在这里学习。非常感谢您的帮助。

    要重复这些步骤,请在小部件可见时启动焦点事件:

    function widgetFocus(){ 
      return $(window).scrollTop() + $(window).height() > $('.footer').offset().top;
    }
    
    为此,我们需要一个谓词来返回小部件是否可见:

    function widgetFocus(){ 
      return $(window).scrollTop() + $(window).height() > $('.footer').offset().top;
    }
    
    然后我们继续进行所有与滚动相关的事件,正如您所做的:

    function eventStream(eventName) {
      return $(window).asEventStream(eventName);
    }
    
    var EVENT_NAMES = ["focus", "click", "scroll", "mousemove", "touchstart", "touchend", "touchcancel", "touchleave", "touchmove"];
    var streams = _.map(EVENT_NAMES, eventStream);
    var scrollEvents = Bacon.mergeAll(streams)
      .debounceImmediate(50); // we debounce here, so we didn't get too much events
    
    接下来,您可以映射scrollEvents以获得一个Boolean流,该流指示是否显示小部件

    var isVisible$ = scrollEvents
      .map(function () {
        return widgetFocus();
      })
      .toProperty(false);
    
    var secondsVisible = isVisible$.changes()
      .map(function(isActive) {
        return {
          isActive: isActive,
          timestamp: new Date().getTime()
        };
      })
      .slidingWindow(2,2)
      .filter(function(span) { return span[0].isActive; })
      .map(function(span) { return span[1].timestamp - span[0].timestamp; })
      .scan(0, function(x,y) { return x + y;})
      .map(function(x) { return Math.floor(x / 1000); }); // milliseconds
    
    secondsVisible.log("visible: ");
    
    这是第一步,可能已经对你有用了

    下一步是创建一个属性或流,说明页面是否处于活动状态(Upworthy的简单版本):

    接下来,我们可以组合
    isActive$
    isVisible$
    属性。我们只对小部件可见和页面处于活动状态的时间感兴趣

    var secondsVisibleAndActive = isActive$.and(isVisible$).changes()
      .map(function(isActive) {
        return {
          isActive: isActive,
          timestamp: new Date().getTime()
        };
      })
      .slidingWindow(2,2)
      .filter(function(span) { return span[0].isActive; })
      .map(function(span) { return span[1].timestamp - span[0].timestamp; })
      .scan(0, function(x,y) { return x + y;})
      .map(function(x) { return Math.floor(x / 1000); }); // milliseconds
    
    secondsVisibleAndActive.log("active & visible: ");
    secondsVisibleAndActive.assign($("#seconds"), "text");
    
    一如既往,从简单开始


    或者,您可以举例说明Upworthy实现的优点:最后一行:

    var hasAttention = (recentlyActive.and(isFocused)).or(videoIsPlaying);
    
    在您的情况下,您可以将其更改为:

    var widgetHasAttention = recentlyActive.and(isFocused).and(widgetIsVisible);
    


    工作JSFIDLE:

    太棒了,感谢您详细解释。我必须承认,我应该想到Upworthy的实现。
    var widgetHasAttention = recentlyActive.and(isFocused).and(widgetIsVisible);