JavaScript加载订单导致问题

时间:2012-09-05 22:53:16

标签: javascript jquery

标题中有一个JS文件(适用于Google DFP广告管理系统),另一个JS文件位于</body>

之前

我发现如果标题JS文件在底部之前没有加载我在Chrome控制台中收到此错误:

 Uncaught TypeError: Object #<Object> has no method 'defineSlot' 

defineSlot在第一个脚本中定义。此问题仅发生在大约每10页刷新一次,因此大部分时间都可以。

我想就如何处理这个问题提出建议。以下是2个脚本:

标题脚本:

<script type='text/javascript'>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
(function() {
    var gads = document.createElement('script');
    gads.async = true;
    gads.type = 'text/javascript';
    var useSSL = 'https:' == document.location.protocol;
    gads.src = (useSSL ? 'https:' : 'http:') + 
    '//www.googletagservices.com/tag/js/gpt.js';
    var node = document.getElementsByTagName('script')[0];
    node.parentNode.insertBefore(gads, node);
})();
</script>

<script type='text/javascript'>
googletag.cmd.push(function() {
    googletag.pubads().enableAsyncRendering();
    slot1 = googletag.defineSlot('/21848415/GoneGlobal_Square', [250, 250], 'doubleClickSquareIndex-250-250').addService(googletag.pubads());
    slot2 = googletag.defineSlot('/21848415/GoneGlobal_Skyscraper', [160, 600], 'doubleClickSkyscraperIndex-160-600').addService(googletag.pubads());
    slot3 = googletag.defineSlot('/21848415/GoneGlobal_Leaderboard', [728, 90], 'doubleClickLeaderboardIndex-728-90').addService(googletag.pubads());
    slot4 = googletag.defineSlot('/21848415/GoneGlobal_Leaderboard', [728, 90], 'doubleClickLeaderboardHeaderInternal-728-90').addService(googletag.pubads());
    slot5 = googletag.defineSlot('/21848415/GoneGlobal_SmallSquare', [200, 200], 'doubleClickSmallSquareHeaderExternal-200-200').addService(googletag.pubads());
    googletag.enableServices();
});
</script>

下面是第二个脚本 - 这只是它的一部分(很长):

$(function() {
    ///////////////////////// Double Click AD Variables
    var slot1 = googletag.defineSlot('/21848415/GoneGlobal_Square', [250, 250], 'doubleClickSquareIndex-250-250');
    var slot2 = googletag.defineSlot('/21848415/GoneGlobal_Skyscraper', [160, 600], 'doubleClickSkyscraperIndex-160-600');
    var slot3 = googletag.defineSlot('/21848415/GoneGlobal_Leaderboard', [728, 90], 'doubleClickLeaderboardIndex-728-90');
    var slot4 = googletag.defineSlot('/21848415/GoneGlobal_Leaderboard', [728, 90], 'doubleClickLeaderboardHeaderInternal-728-90');
    var slot5 = googletag.defineSlot('/21848415/GoneGlobal_SmallSquare', [200, 200], 'doubleClickSmallSquareHeaderExternal-200-200');
)};

有没有办法停止运行另一个方法/函数的脚本?

我可以创建某种依赖吗?

如何确保在底部之前加载顶级JS?

3 个答案:

答案 0 :(得分:5)

此处的其他解决方案可能有效,但真正的问题与您使用DFP的方式有关。

DFP广告管理系统是异步加载的,因此在执行导致错误的脚本时,页面上不存在defineSlot方法。

所有DFP广告管理系统代码都应包含在googletag.cmd.push包装器中,该包装器将存储命令,直到加载DFP广告管理系统,然后按照正确的顺序执行它们。

只需包装任何类似的DFP广告管理系统代码,都应该修复错误:

googletag.cmd.push(function() {
    // Double Click AD Variables

});

答案 1 :(得分:4)

将脚本存储在单独的文件中。那么类似下面的东西应该有效:

function loadScript(pathToScript, callback) {
    var head = document.getElementsByTagName("head")[0];
    var script = document.createElement("script");

    script.type = "text/javascript";
    script.src = pathToScript + "?t=" + new Date().getTime(); //prevent caching

    if (callback) {
        script.onload = callback;
    }

    head.appendChild(script);
}

loadScript函数加载驻留在“pathToScript”的脚本,一旦加载完脚本,它就会调用提供的回调。您需要回调,因为加载外部资源是异步操作。这意味着在完成加载外部资源时,您基本上需要“通知”。这基本上就是回调的作用。如果依赖于来自异步操作的数据,则无法启动操作,然后继续尝试使用数据或资源,因为数据将无法完成加载。所以任何依赖于资源的代码,都放在回调中。为什么我们这样做会在以后更清楚。

var scripts = ["/path/to/first/script.js", "/path/to/second/script.js"];    
function load(i) {
    if (i < scripts.length) {
        loadScript(scripts[i], function () {
            load(++i);
        });
    } else {
        //all your scripts have loaded, so go ahead and do what you need to do
    }
}

load(0);

scripts数组包含要加载的脚本数组。数组中脚本的位置暗示了顺序。因此,scripts[0]处的脚本将在scripts[1]的脚本之前加载。

load函数可确保您按所需顺序加载脚本。我们知道加载操作是异步的。我们还知道一旦操作完成就会调用回调。使用该信息,我们可以在第一个脚本完成加载后加载第二个脚本。 load有一个参数,表示scripts数组的当前索引。我们最初将索引i设置为0,这意味着我们将首先在索引0加载脚本。然后我们看看i的价值。如果它小于数组的长度,则意味着我们没有完成所有脚本(将其视为循环)。因此,如果i低于长度,我们会调用loadScript函数,其值为scripts[i]。然后在我们的回调中,我们再次调用load函数,但这次我们增加i的当前值。因此,当脚本加载完毕后,我们最终会使用递增的索引调用load,因此我们现在可以加载下一个脚本。

如果i等于scripts.length,则表示我们已经加载了所有脚本,因此我们将进入else块,这就是您放置代码的地方你需要在加载所有脚本后运行。

最后一行是对load的实际调用,其参数为0,它从第一个脚本的路径开始整个过程​​,该脚本位于索引0 scripts数组。

如果您愿意,也可以将load功能重写为IIFE:

(function load(i) {
    if (i < resources.length) {
        loadResource(resources[i], function () {
            load(++i);
        });
    }
})(0);

这里有一个“自调用”函数,它在回调中调用自身。它在功能上等同于上面那种不那么奇特的版本。

答案 2 :(得分:0)

您可以创建自己的事件,例如first_script_loaded,当加载第一个脚本时,您可以在最后$(document).trigger("first_script_loaded")添加,您可能还想设置全局boolean这个,在开头设置为false,加载第一个脚本时,将其设置为true

在第二个脚本中,检查boolean是否为true,这意味着在开始加载第二个脚本之前已经加载了第一个脚本,但是如果它是假的,那么请听事件$(document).on("first_script_loaded")并在callback方法的on中添加您的代码。