如何在淘汰赛自定义绑定中使用segment.io的analytics.js

时间:2016-04-07 21:00:45

标签: javascript knockout.js

我正在使用knockout为analytics.track制作自定义绑定,但它似乎遇到了麻烦。似乎analytics.track嵌套在两个以上的函数中,跟踪调用无声地失败。它没有点击回调,也没有在段调试器中报告。我在这里提供了两个证明问题的例子:

没有关闭(工作):

function sendTrack(event, props) {
  console.log("Enter sendTrack");
  analytics.track('Signed Up', {
    plan: 'Enterprise'
  }, {}, function () {
    console.log('track callback logged');
  });
}

ko.bindingHandlers.segmentTrack = {
  init: function (element, valueAccessor) {
    console.log("Init");
    var value = ko.unwrap(valueAccessor());
    ko.applyBindingsToNode(element, { click: sendTrack });
  }
};
ko.applyBindings({});

关闭(不起作用):

(function(ko, $, analytics){
  'use strict';
  function sendTrack(event, props) {
    console.log("Enter sendTrack");
    analytics.track('Signed Up', {
      plan: 'Enterprise'
      }, {}, function () {
        console.log('track callback logged');
      });
  }

  ko.bindingHandlers.segmentTrack = {
    init: function (element, valueAccessor) {
      console.log("Init");
      var value = ko.unwrap(valueAccessor());
      ko.applyBindingsToNode(element, { click: sendTrack });
    }
  };

  ko.applyBindings({});
})(window.ko, window.jQuery, window.analytics);

Edit1:另请注意,如果我将analytics.track移动到init:

,则可以使用
(function(ko, $, analytics){
  'use strict';
  ko.bindingHandlers.segmentTrack = {
    init: function (element, valueAccessor) {
      console.log("Init");
      analytics.track('Signed Up', {
      plan: 'Enterprise'
      }, {}, function () {
        console.log('track callback logged');
      });
    }
  };

  ko.applyBindings({});
})(window.ko, window.jQuery, window.analytics);

请告知

2 个答案:

答案 0 :(得分:0)

这很可能是因为在window对象上加载/初始化了订单。因为iife会立即执行 ,所以analytics变量将设置为浏览器遇到生命时的window.analytics 。在第一种情况下,代码运行时将解析window.analytics

换句话说:在生命执行时,闭包在范围window.analytics变量中捕获analytics

这是一个显示问题的演示。

没有关闭:

function sendTrack() {
  console.log("Tracking...");
  analytics.track("stuff");
}

ko.bindingHandlers.segmentTrack = { 
  init: function(element) {
    console.log("Init");
    ko.applyBindingsToNode(element, { click: sendTrack });
  }
}

ko.applyBindings({ });

// Simulate loading analytics now:
window.analytics = { track: function(txt) { console.log("Tracking " + txt); } };
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<div data-bind="segmentTrack: true">CLICK ME</div>

vs with closure:

(function(ko, analytics) {
  function sendTrack() {
    console.log("Tracking...");
    analytics.track("stuff");
  }

  ko.bindingHandlers.segmentTrack = {
    init: function(element) {
      console.log("Init");
      ko.applyBindingsToNode(element, { click: sendTrack });
    }
  }

  ko.applyBindings({});
})(window.ko, window.analytics); // window.analytics isn't quite okay yet!

// Simulate loading analytics now:
window.analytics = { track: function(txt) { console.log("Tracking " + txt); } };
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<div data-bind="segmentTrack: true">CLICK ME</div>

是的,在我的例子中,第二个场景引发了一个错误,而你在问题中提到没有发生,但是这个问题再次没有包含一个真正的复制品,所以很难说出这个差异在哪里所在。

答案 1 :(得分:0)

所以analytics.js在页面中异步加载自己。同时,它使用对象的snub版本对API的所有调用进行排队。一旦analytics.js加载,它就会执行队列中的所有调用。然后重新定义它的自我,打破所有的refs到原来的window.analytics。因此,任何遇到足够快速的调用我的唯一解决方法是使我的曝光器成为一个函数调用,返回当前版本的window.analytics。

(function (ko, $, analytics) {

    function sendTrack(event, props) {
        analytics().track(event, props);
    }

    ko.bindingHandlers.segmentTrack = {
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            var value = ko.unwrap(valueAccessor());
            ko.applyBindingsToNode(element, { click: function () { sendTrack(value.event, value.options) }});
        }
    }
})(window.ko, window.jQuery, function () { return window.analytics; });