避免常见的植入错误

下面介绍了在实现 GPT 时观察到的一些最常见的错误。虽然此类实现在 GPT 的当前版本中看起来可能正常运行,但不能保证它们将来也会继续如此。在最极端的情况下,这些植入方式可能会导致广告投放以不可预知的方式中断。 它们被视为不受支持的实现。

每个场景都包含修复所示问题的建议方法。

请注意,此列表并不详尽列出潜在问题,只不过能起到帮助作用,帮助您确定可能需要解决的问题类型。

此外,根据您的实现情况,您可能需要查找网站中可能需要进行此类更改的所有位置。

常见错误

场景 1:使用 GPT JavaScript 库的非官方副本

使用场景概要说明 托管 gpt.js、pubads_impl.js 或其从您自己的服务器加载的任何库,或者从非官方来源加载这些文件。
出现错误的代码段示例
// Incorrect: Accessing these files from an unofficial source
<script async src="https://www.example.com/tag/js/gpt.js"></script>
修正错误的建议方法
// Correct: Access these files from a Google domain
<script async src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>
// Also correct, if using Limited Ads
<script async src="https://pagead2.googlesyndication.com/tag/js/gpt.js"></script>

场景 2:依赖 gpt.js 脚本代码监听器

使用场景概要说明 假设 GPT API 可在加载 JavaScript 文件 gpt.js 时调用是错误的,因为该 API 的某些部分由 pubads_impl.js 文件提供。因此,在附加到脚本标记的事件监听器内以任何方式依赖该 API(包括框架)是不正确的。
出现错误的代码段示例
var tag = document.createElement('script');
tag.type = 'text/javascript';
tag.src = (useSSL ? 'https:' : 'http:') +
        ‘//www.googletagservices.com/tag/js/gpt.js';
// Incorrect: Attaching a callback to the script’s onload event.
tag.onload = callback;
var node = document.getElementsByTagName('script')[0];
node.parentNode.insertBefore(tag, node);
修正错误的建议方法
// Make sure that googletag.cmd exists.
window.googletag = window.googletag || {};
googletag.cmd = googletag.cmd || [];
// Correct: Queueing the callback on the command queue.
googletag.cmd.push(callback);
修复的说明 / 说明 googletag.cmd 会维护一个命令列表,这些命令会在 GPT 准备就绪时立即运行。这是确保回调在 GPT 加载后运行的正确方式。

场景 3:通过检查 googletag 对象来了解 GPT 是否准备就绪

使用场景概要说明 在 JavaScript 文件 gpt.js 加载或定义 googletag 对象时,GPT API 可能尚未就绪,因此检查该对象以判断 GPT API 是否可用并不可靠。
出现错误的代码段示例
// Incorrect: Relying on the presence of the googletag object
// as a check for the GPT API.
if (typeof googletag != 'undefined') {
 functionProcessingGPT();
}
修正错误的建议方法
// Correct: Relying on googletag.apiReady as a check for the GPT API.
if (window.googletag && googletag.apiReady) {
 functionProcessingGPT();
}
修复的说明 / 说明 在可以调用 API 后,GPT 将立即填充布尔标记 googletag.apiReady,以便您做出可靠的断言。

场景 4:依赖混淆代码语法

使用场景概要说明 如果您需要使用经过缩减的 GPT 库代码的精确语法,您几乎肯定会遇到服务中断的情况。我们将不断改变 GPT 的内部运作方式,以便不断进行改进,因此建议您使用 API 参考指南中所述的 API。
例如,常见的要求是检测 PubAdsService 何时完全加载,以便调用 refresh()
出现错误的代码段示例
// Incorrect: Relying on an obfuscated property.
if (googletag.pubads().a != null) {
 functionProcessingGPT();
}
修正错误的建议方法
// Correct: Relying on public GPT API methods
// (i.e. googletag.pubadsReady in this case).
if(window.googletag && googletag.pubadsReady) {
 functionProcessingGPT();
}
修复的说明 / 说明 只能依赖于公共 API。为检测 PubAdsService 是否已完全加载,可使用布尔值 googletag.pubadsReady

场景 5:覆盖 GPT 的任何函数或变量

使用场景概要说明 基于覆盖 GPT 使用的任何函数或变量的用例可能会随时中断,因为这不是受支持的用例。GPT 内部构件中的计时变化可能会导致这种错误行为因损坏而出现。
出现错误的代码段示例
// Incorrect: Haphazardly overwriting a googletag.* property.
googletag.cmd = [];
修正错误的建议方法
// Correct: Never overwrite googletag.* properties if they already exist.
// Always check before assigning to them.
googletag.cmd = googletag.cmd || [];

场景 6:对 GPT 的调用顺序有误

使用场景概要说明 随着 GPT 内部功能的演变,竞态条件可能会造成中断。一组排序错误但因执行的具体时间原因而起作用的语句集在未来可能无法继续运行。
出现错误的代码段示例
// Incorrect: Setting page-level key-value targeting after calling
// googletag.enableServices().
googletag.enableServices();
googletag.defineSlot(...);
googletag.pubads().setTargeting(e, a);
修正错误的建议方法
// Correct: Setting page-level key-value targeting before calling
// googletag.enableServices().
googletag.pubads().setTargeting(e, a);
googletag.defineSlot(...);
googletag.enableServices();
修复的说明 / 说明 请务必遵循 GPT 的常规计时功能,以避免出现竞态条件。有效的部分排序的示例包括:
  • 定义-启用-显示
    1. 定义页面级设置
    2. 定义槽
    3. enableServices()
    4. 展示广告位
  • 启用-定义-显示
    1. 定义页面级设置
    2. enableServices()
    3. 定义槽
    4. 展示广告位

场景 7:滥用闭包和 JavaScript 变量范围

使用场景概要说明 对 JavaScript 变量作用域的假设不正确,以及在传递给 googletag.cmd.push 的函数中捕获的变量值。
出现错误的代码段示例
// Incorrect: Variable x is declared outside the anonymous function
// but referenced within it.
for (var x = 0; x < slotCount; x++) {
 window.googletag.cmd.push(
  function(){
    // If GPT is not yet loaded, this code will be executed subsequently when
    // the command queue is processed. Every queued function will use the last value
    // assigned to x (most likely slotCount).
    // This is because the function closure captures the reference to x,
    // not the current value of x.
    window.googletag.display(slot[x]);
  })
 }
}
修正错误的建议方法
window.googletag.cmd.push(
 function(){
  // Correct: We both declare and reference x inside the context of the function.
  for (var x = 0; x < slotCount; x++){
   window.googletag.display(slot[x]);
  }
 }
)
修复的说明 / 说明

在 JavaScript 中,闭包通过引用而不是值来捕获变量。这意味着,如果为变量重新赋值,则稍后执行捕获它的函数闭包时将使用其新值。因此,闭包中代码的行为可能会根据回调是立即执行还是延迟执行而发生变化。

如果是异步加载的 GPT,则取决于 GPT 加载命令队列上的回调的速度有多快、是否会立即执行。在上面的示例中,这会改变已加入队列的命令的行为。

为避免出现任何问题,在编写代码时不应假设放在命令队列中的函数会立即执行,而且应谨慎考虑 JavaScript 的范围规则。

场景 8:调用 display 后在 DOM 内移动槽容器

使用场景概要说明 在调用 display 后在 DOM 中移动或插入槽容器可能会导致 GPT 中出现意外的重排和不可预知的行为。
出现错误的代码段示例
// Incorrect: Moving slot containers after calling display
googletag.defineSlot("/1234/travel/asia", [728, 90], "div-gpt-ad-123456789-0");
googletag.enableServices();
googletag.display("div-gpt-ad-123456789-0");
...
// Inserting another element before the slot container, pushing the slot container down the page.
document.body.insertBefore(someOtherElement, document.getElementById("div-gpt-ad-123456789-0"));
修正错误的建议方法
// Correct: Make any DOM order changes before calling display

document.body.insertBefore(someOtherElement, document.getElementById("div-gpt-ad-123456789-0"));
...
googletag.defineSlot("/1234/travel/asia", [728, 90], "div-gpt-ad-123456789-0");
googletag.enableServices();
googletag.display("div-gpt-ad-123456789-0");