×

AdSlotManager ( googletag/Ad Manager系统高级广告加载类)

Falcon 2024-12-18 views:
自动摘要

正在生成中……

class AdSlotManager {
  static DEFAULT_SLOT = {
    adUnitPath: '/custom/adUnit',
    sizes: [1, 1],
    slotId: 'div-gpt-popup'
  };

  static REQUIRED_FIELDS = ['adUnitPath', 'sizes', 'slotId'];

  constructor(googletag, options = {}) {
    this.googletag = googletag;
    this.logger = options.logger || console;
    this.callbacks = {
      onSuccess: () => {},
      onError: () => {},
      onDestroy: () => {}
    };
  }

  // 参数验证
  validateSlotConfig(config) {
    try {
      AdSlotManager.REQUIRED_FIELDS.forEach(field => {
        if (!config[field]) {
          throw new Error(`Missing required field: ${field}`);
        }
      });

      if (!Array.isArray(config.sizes) || config.sizes.length !== 2) {
        throw new Error('Invalid sizes format');
      }

      return true;
    } catch (error) {
      this.handleError('Validation Error', error);
      return false;
    }
  }

  // 错误处理
  handleError(type, error) {
    const errorInfo = {
      type,
      message: error.message,
      timestamp: new Date().toISOString()
    };
    
    this.logger.error('[AdSlotManager Error]', errorInfo);
    this.callbacks.onError(errorInfo);
    
    // 可以选择抛出错误或返回false
    return false;
  }

  // 性能监控
  measurePerformance(action, callback) {
    const start = performance.now();
    
    const done = () => {
      const duration = performance.now() - start;
      this.logger.info(`[AdSlotManager Performance] ${action}: ${duration}ms`);
    };

    try {
      callback();
      done();
    } catch (error) {
      done();
      throw error;
    }
  }

  findSlotByAdUnit(adUnitPath) {
    try {
      const slots = this.googletag.pubads().getSlots();
      return slots.find(slot => slot.getAdUnitPath() === adUnitPath) || false;
    } catch (error) {
      this.handleError('Slot Search Error', error);
      return false;
    }
  }

  destroyExistingSlot(adUnitPath) {
    this.measurePerformance('destroySlot', () => {
      try {
        const matchingSlot = this.findSlotByAdUnit(adUnitPath);
        if (matchingSlot) {
          this.googletag.destroySlots([matchingSlot]);
          this.logger.info(`[AdSlotManager] Destroyed slot: ${adUnitPath}`);
          this.callbacks.onDestroy({ adUnitPath });
        }
      } catch (error) {
        this.handleError('Destroy Slot Error', error);
      }
    });
  }

  // 事件监听器设置
  on(event, callback) {
    if (typeof callback !== 'function') {
      throw new Error('Callback must be a function');
    }
    
    if (this.callbacks.hasOwnProperty(event)) {
      this.callbacks[event] = callback;
    } else {
      throw new Error(`Unknown event: ${event}`);
    }
  }

  loadAd(customSlot = {}) {
    return new Promise((resolve, reject) => {
      try {
        // 合并配置并验证
        const adSlot = { ...AdSlotManager.DEFAULT_SLOT, ...customSlot };
        
        if (!this.validateSlotConfig(adSlot)) {
          reject(new Error('Invalid slot configuration'));
          return;
        }

        const { adUnitPath, sizes, slotId } = adSlot;
        
        // 记录开始加载
        this.logger.info('[AdSlotManager] Starting ad load', { adUnitPath, slotId });

        // 销毁已存在的广告位
        this.destroyExistingSlot(adUnitPath);

        // 测量广告加载性能
        this.measurePerformance('loadAd', () => {
          this.googletag.cmd.push(() => {
            try {
              const slot = this.googletag
                .defineSlot(adUnitPath, sizes, slotId)
                .addService(this.googletag.pubads());

              // 添加广告加载事件监听
              this.googletag.pubads().addEventListener('slotRenderEnded', event => {
                if (event.slot === slot) {
                  const success = !event.isEmpty;
                  this.logger.info('[AdSlotManager] Slot render ended', {
                    success,
                    adUnitPath,
                    slotId
                  });
                  
                  this.callbacks.onSuccess({
                    success,
                    adUnitPath,
                    slotId,
                    event
                  });
                  
                  resolve({ success, adUnitPath, slotId, event });
                }
              });

              this.googletag.pubads().enableSingleRequest();
              this.googletag.enableServices();
              this.googletag.display(slotId);
              
            } catch (error) {
              this.handleError('Ad Load Error', error);
              reject(error);
            }
          });
        });

      } catch (error) {
        this.handleError('General Error', error);
        reject(error);
      }
    });
  }
}

// 使用示例:
async function ajaxLoadmoreAd(customSlot) {
  const adManager = new AdSlotManager(googletag, {
    logger: console // 可以替换为自定义logger
  });

  // 设置事件监听器
  adManager.on('onSuccess', (data) => {
    console.log('Ad loaded successfully:', data);
  });

  adManager.on('onError', (error) => {
    console.error('Ad load failed:', error);
  });

  adManager.on('onDestroy', (data) => {
    console.log('Ad slot destroyed:', data);
  });

  try {
    const result = await adManager.loadAd(customSlot);
    console.log('Ad load result:', result);
  } catch (error) {
    console.error('Ad load error:', error);
  }
}

主要增加的功能:

  1. 参数验证:

    • 必填字段检查
    • 参数格式验证
  2. 错误处理:

    • 统一的错误处理机制
    • 详细的错误信息记录
    • Promise 支持
  3. 事件回调:

    • onSuccess
    • onError
    • onDestroy
    • 支持自定义事件监听
  4. 日志记录:

    • 可配置的日志系统
    • 详细的操作记录
    • 支持自定义 logger
  5. 性能监控:

    • 操作耗时统计
    • 性能数据记录
  6. 其他改进:

    • Promise 化的异步操作
    • 更完善的类型检查
    • 更灵活的配置选项
    • 更好的代码组织

使用示例:

// 基础用法
ajaxLoadmoreAd();

// 高级用法
ajaxLoadmoreAd({
  adUnitPath: '/custom/path',
  sizes: [2, 2],
  slotId: 'custom-slot'
}).catch(error => {
  // 错误处理
});

这个版本的代码更加健壮和可维护,适合在生产环境中使用。

让我详细解释每个主要功能:

  1. 参数验证系统
class AdSlotManager {
  // 定义必需字段
  static REQUIRED_FIELDS = ['adUnitPath', 'sizes', 'slotId'];

  // 验证方法
  validateSlotConfig(config) {
    try {
      // 检查所有必需字段
      AdSlotManager.REQUIRED_FIELDS.forEach(field => {
        if (!config[field]) {
          throw new Error(`Missing required field: ${field}`);
        }
      });

      // 验证sizes格式
      if (!Array.isArray(config.sizes) || config.sizes.length !== 2) {
        throw new Error('Invalid sizes format');
      }

      return true;
    } catch (error) {
      this.handleError('Validation Error', error);
      return false;
    }
  }
}
  1. 错误处理系统
class AdSlotManager {
  handleError(type, error) {
    // 构建错误信息对象
    const errorInfo = {
      type,                           // 错误类型
      message: error.message,         // 错误消息
      timestamp: new Date().toISOString() // 时间戳
    };
    
    // 记录错误
    this.logger.error('[AdSlotManager Error]', errorInfo);
    
    // 触发错误回调
    this.callbacks.onError(errorInfo);
    
    return false;
  }
}
  1. 性能监控系统
class AdSlotManager {
  measurePerformance(action, callback) {
    // 记录开始时间
    const start = performance.now();
    
    // 定义完成函数
    const done = () => {
      const duration = performance.now() - start;
      this.logger.info(`[AdSlotManager Performance] ${action}: ${duration}ms`);
    };

    try {
      // 执行操作
      callback();
      done();
    } catch (error) {
      // 即使发生错误也要记录性能数据
      done();
      throw error;
    }
  }
}
  1. 事件系统
class AdSlotManager {
  constructor(googletag, options = {}) {
    // 初始化回调函数
    this.callbacks = {
      onSuccess: () => {},
      onError: () => {},
      onDestroy: () => {}
    };
  }

  // 添加事件监听器
  on(eventName, callback) {
    if (this.callbacks.hasOwnProperty(eventName)) {
      this.callbacks[eventName] = callback;
    }
  }
}

// 使用示例
const adManager = new AdSlotManager(googletag);
adManager.on('onSuccess', (data) => {
  console.log('广告加载成功:', data);
});
  1. Promise化的广告加载
class AdSlotManager {
  loadAd(customSlot = {}) {
    return new Promise((resolve, reject) => {
      try {
        // 合并和验证配置
        const adSlot = { ...AdSlotManager.DEFAULT_SLOT, ...customSlot };
        if (!this.validateSlotConfig(adSlot)) {
          reject(new Error('配置无效'));
          return;
        }

        // 加载广告
        this.googletag.cmd.push(() => {
          try {
            const slot = this.googletag
              .defineSlot(adSlot.adUnitPath, adSlot.sizes, adSlot.slotId)
              .addService(this.googletag.pubads());

            // 监听广告渲染完成事件
            this.googletag.pubads().addEventListener('slotRenderEnded', event => {
              if (event.slot === slot) {
                resolve({
                  success: !event.isEmpty,
                  adUnitPath: adSlot.adUnitPath,
                  slotId: adSlot.slotId,
                  event
                });
              }
            });

            // 显示广告
            this.googletag.display(adSlot.slotId);
          } catch (error) {
            reject(error);
          }
        });
      } catch (error) {
        reject(error);
      }
    });
  }
}

使用示例:

async function loadAd() {
  const adManager = new AdSlotManager(googletag);
  
  // 设置事件监听
  adManager.on('onSuccess', data => console.log('成功:', data));
  adManager.on('onError', error => console.error('错误:', error));
  
  try {
    // 加载广告
    const result = await adManager.loadAd({
      adUnitPath: '/custom/path',
      sizes: [1, 1],
      slotId: 'my-ad'
    });
    
    console.log('广告加载结果:', result);
  } catch (error) {
    console.error('广告加载失败:', error);
  }
}

这些功能的主要优点:

  1. 可靠性:通过参数验证和错误处理提高代码可靠性
  2. 可维护性:通过模块化和清晰的结构提高代码可维护性
  3. 可监控性:通过性能监控和日志系统提供运行时信息
  4. 灵活性:通过事件系统和Promise支持提供灵活的使用方式
  5. 可扩展性:通过面向对象设计便于future扩展
本文收录于