谷歌分析异步设计模式的名称是什么,它在哪里使用?

51

Google Analytics异步代码使用了一种非常独特的JavaScript代码执行设计模式。

该代码依赖于一个库,它不知道库是否已经加载。如果库还没有加载,它会将所有命令排队到一个数组对象中。当库加载完成后,它就创建_gaq对象并按照队列中的顺序执行所有命令。然后它覆盖push函数,以便后续命令可以立即执行。

其想法是在排队时让命令非常快速地运行。只有当库加载完成后,代码才会真正被评估。

他们还使用参数async=true加载库。这对实际页面加载时间几乎没有影响。

这些命令看起来就像同步版本的命令,但第一个字符串是函数名,后面的参数是函数参数。您还可以将函数推入此数组中,这些函数也将按顺序以null上下文执行。因此,如果您需要与库进行同步操作,可以将函数推入_gaq中执行。

我认为这是一种非常聪明的解决方案,但我以前从未见过它。除了Google Analytics跟踪代码之外,有人知道这种设计模式的名称或使用位置吗?

4个回答

50

我将其称为“异步函数排队”,但这并不是一个很吸引人的名称,也不是这种设计模式的正式名称。

有趣的是,虽然我之前没有见过这种特定的模式被使用,但自从谷歌采用它用于Google Analytics以来,它已经被广泛地采用了,许多平台都试图利用这种异步技术(例如Disqus)。

这篇博客文章是我读过的关于异步Google Analytics语法最深入的探讨,其中包括如何复制该模式的相当详细的解释:

引用博客文章中的内容:

var GoogleAnalyticsQueue = function () {

    this.push = function () {
        for (var i = 0; i < arguments.length; i++) try {
            if (typeof arguments[i] === "function") arguments[i]();
            else {
                // get tracker function from arguments[i][0]
                // get tracker function arguments from arguments[i].slice(1)
                // call it!  trackers[arguments[i][0]].apply(trackers, arguments[i].slice(1));
            }
        } catch (e) {}
    }

    // more code here…
};

// get the existing _gaq array
var _old_gaq = window._gaq;

// create a new _gaq object
window._gaq = new GoogleAnalyticsQueue();

// execute all of the queued up events - apply() turns the array entries into individual arguments
window._gaq.push.apply(window._gaq, _old_gaq);

它还指出,尽管不是所有浏览器都支持async属性,但使用的注入方式使得大多数浏览器可以异步加载脚本,并包含了一张有用的图表:

enter image description here


3

它的作用只是将数据推送到全局数组中。

var _qaq = _qaq || [];
_qaq.push(stuff);

这基本上允许您在库加载之前缓冲数据以进行处理。

该模式不常用的主要原因是其他库通常需要资源加载完毕才能执行任何操作。开始缓冲jQuery命令是没有意义的。

这不是一种模式,只是将数据存储在全局范围内,并说它是别人的工作来处理这个数据,我不关心你何时处理它。

然而,这是一种解决您不知道某些东西何时已经加载或已准备好的聪明方法,常见的替代方法是DOMReady块。


1
如果你想在jquery.js文件中使用async=true来减少页面加载时间,那么当代码运行时就无法知道它是否已经完成加载。把jQuery命令排队而不是并发执行会不会更好呢?或者将所有的代码放到一个函数中,等待jQuery完成加载后再执行该函数也是一种不错的选择。 - Eduardo
@eduardocereto 当然没问题。建议 jQuery 提供一个全局 _domReady 数组,用于存储和读取 DOM 就绪的函数。 - Raynos
1
这不是一个_domReady,更像是_jQueryReady,因为DOM不一定准备好。使用async=true标志,文件可能在DOM准备好之前或之后加载。即使在window.onload触发后,js文件仍然可以加载。 - Eduardo
@eduardocereto,你有没有任何备份证明onload事件能在异步脚本加载和执行之前触发? - Raynos
1
异步的jQuery肯定是一个有趣的项目,但问题在于你不想把它延迟太久,因为如果你的jQuery触发了DOM修改,那么这些修改可能会比你想象的要晚很多,导致加载后出现不美观的修改。 - Yahel
@yahelc 我同意有时候你想让代码先执行。无论如何。但是有时候为了页面加载时间,你可能想要延迟它的执行。 - Eduardo

3

2
它涉及实际脚本调用以及如何不延迟onload事件。我更感兴趣的是如何将函数调用排队到简单数组中。那就是我想要找类似设计的实际内容。 - Eduardo
Steve在他的帖子中直接指出,Google分析加载器是他与他们合作的结果。你说得对。 - vhs

1

2014年,Ilya Grigorik撰写了一篇名为Script-injected "async scripts" considered harmful的文章。该文章链接到这个问题,并使用“异步函数排队”这个短语作为Google Analytics所使用的设计模式的名称。

异步函数排队与更近期的设计模式(如Fetch Injection)不同,后者不需要或不需要全局定义的队列。以下是Fetch Injection的示例,实现在Fetch Inject module中,用于异步下载文档中的资源:

enter image description here

注意Fetch Injection设计模式能够并行加载CSS和JavaScript,消除了CSSOM和Web字体下载的阻塞行为,大大降低了感知延迟。使用易于理解的API完全保留了脚本执行顺序,使得管理加载复杂资源组具有完全的编程控制变得简单。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接