繁体   English   中英

为什么Segment.io loader脚本将方法名称/ args推送到看似被覆盖的队列?

[英]Why does the Segment.io loader script push method names/args onto a queue which seemingly gets overwritten?

我一直在剖析以下代码片段,它用于异步加载Segment.io分析包装器脚本:

// Create a queue, but don't obliterate an existing one!
var analytics = analytics || [];

// Define a method that will asynchronously load analytics.js from our CDN.
analytics.load = function(apiKey) {

    // Create an async script element for analytics.js.
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.async = true;
    script.src = ('https:' === document.location.protocol ? 'https://' : 'http://') +
                  'd2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/' + apiKey + '/analytics.min.js';

    // Find the first script element on the page and insert our script next to it.
    var firstScript = document.getElementsByTagName('script')[0];
    firstScript.parentNode.insertBefore(script, firstScript);

    // Define a factory that generates wrapper methods to push arrays of
    // arguments onto our `analytics` queue, where the first element of the arrays
    // is always the name of the analytics.js method itself (eg. `track`).
    var methodFactory = function (type) {
        return function () {
            analytics.push([type].concat(Array.prototype.slice.call(arguments, 0)));
        };
    };

    // Loop through analytics.js' methods and generate a wrapper method for each.
    var methods = ['identify', 'track', 'trackLink', 'trackForm', 'trackClick',
                   'trackSubmit', 'pageview', 'ab', 'alias', 'ready'];

    for (var i = 0; i < methods.length; i++) {
        analytics[methods[i]] = methodFactory(methods[i]);
    }
};

// Load analytics.js with your API key, which will automatically load all of the
// analytics integrations you've turned on for your account. Boosh!
analytics.load('MYAPIKEY');

它评论很好,我可以看到它正在做什么,但是当涉及到methodFactory函数时,我感到困惑,因为它推动了在将主要analytics.js脚本加载到全局之前进行的任何方法调用的细节(方法名称和参数)。 analytics数组。

这是一切都很好,但随后如果/当主脚本执行负载,它似乎只是覆盖全球analytics变量(见这里最后一行 ),因此所有数据都将丢失。

我看到这是如何通过截断尚不存在的方法来防止网页中的脚本错误,但我不明白为什么存根不能只返回一个空函数:

var methods = ['identify', 'track', 'trackLink', 'trackForm', 'trackClick',
               'trackSubmit', 'pageview', 'ab', 'alias', 'ready'];

for (var i = 0; i < methods.length; i++) {
    lib[methods[i]] = function () { };
}

我错过了什么? 拜托,帮帮我理解!

Ian在这里,Segment.io的联合创始人 - 我实际上并没有写那个代码,Calvin做了,但是我可以告诉你它正在做什么。

你是对的, methodFactory正在删除这些方法,以便在脚本加载之前它们可用,这意味着人们可以调用analytics.track而不将这些调用包装在ifready()调用中。

但是这些方法实际上比“哑”存根更好,因为它们保存了被调用的方法,因此我们可以稍后重放这些操作。 这就是这个部分:

analytics.push([type].concat(Array.prototype.slice.call(arguments, 0)));

为了使其更具可读性:

var methodFactory = function (method) {
    return function () {
        var args = Array.prototype.slice.call(arguments, 0);
        var newArgs = [method].concat(args);
        analytics.push(newArgs);
    };
};

它取决于所调用方法的名称,这意味着如果我使用analytics.identify('userId') ,我们的队列实际上会得到一个类似于以下内容的数组:

['identify', 'userId']

然后,当我们的库加载时,它卸载所有排队的调用并将它们重放到真实的方法(现在可用)中,以便仍然保留在加载之前记录的所有数据。 这是关键部分,因为我们不想丢弃在我们的库有机会加载之前发生的任何调用。 看起来像这样:

// Loop through the interim analytics queue and reapply the calls to their
// proper analytics.js method.
while (window.analytics.length > 0) {
    var item = window.analytics.shift();
    var method = item.shift();
    if (analytics[method]) analytics[method].apply(analytics, item);
}

analytics是一个局部变量,在我们完成重放之后,我们将全局替换为本地analytics (这是真正的交易)。

希望有道理。 我们实际上会在我们的博客上有关于第三方Javascript的所有小技巧的系列文章,所以你很快就会挖掘它!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM