如何使用segment.io's analystics.js在一个敲除自定义绑定中

How to use segment.io's analytics.js in a knockout custom bindings

本文关键字:一个 绑定 自定义 io segment 何使用 js analystics      更新时间:2024-03-22

我正在使用knockout为analytics.track创建自定义绑定,但它似乎遇到了问题。如果analytics.track嵌套在2个以上的函数中,那么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);

第1版:另外请注意,如果我将analysis.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);

请告知

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

换句话说:闭包在iife执行时捕获作用域analytics变量中的window.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>

与关闭:

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

的确,在我的例子中,第二个场景抛出了一个错误,而你在问题中提到什么都没有发生,但问题中又没有包含实际的repo,所以很难判断差异在哪里。

因此analytics.js在页面中异步加载其自身。与此同时,它将所有对API的调用与对象的怠慢版本一起排队。一旦analytics.js加载,它就会执行队列中的所有调用。然后重新定义它自己,破坏对原始window.analytics的所有引用。因此,我遇到的任何调用都足够快。我唯一的解决办法是让我的exposer成为一个函数调用,返回window.analystics的当前版本。

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