标题中有一个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?
答案 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
中添加您的代码。