优化广告展现的整体思路

115 阅读3分钟

记录一下优化广告展现路程的总体思路。

前端本地缓存方案(旧版)

在项目初期,为了支持不同模块获取特定的 key 对应的 value(例如账号名、商品名等),我们采用了以下查找顺序:

localStorage -> IndexedDB -> 接口请求

示例核心代码:

const count = await getCommonAdvertActionFrequencyRecord(key, 'PC');
if (count > 0) {
  personalCache.set(key, '1');
  return;
}

存在问题:

展示商品名:
 └─ 查 localStorage
     └─ 没有?查 IndexedDB
         └─ 还没有?调接口
             └─ 接口返回后写入 localStorage + IndexedDB

每个 key 都重复以上流程
  • 缓存有效期不好控制,删除后用户可能再次看到广告。

  • 重复代码多,几乎每个页面都要写一遍获取逻辑。

  • 请求次数多,每个 key 可能都需要单独发请求。

  • localStorage 容量有限,容易爆仓

  • 多终端/多用户/多账号时不易同步

引入后端统一记录(新版)

我们将流程统一改造为:

一次性从后端获取所有 key-value -> 存入内存(内存 Map

核心改动点:

系统初始化时:
 └─ 一次性请求所有 key-value
     └─ 存入内存 Map(如:const dictMap = new Map())

使用时:
 └─ 直接 dictMap.get(key) 拿数据

关键点:

  • 后端通过两张表,支持子账号区分,返回完整 key-value 对应关系。
  • 前端统一请求一次后,将数据缓存到内存中(如 Map 结构)。
  • 所有需要展示 key 的模块直接从内存读取,无需再重复查找逻辑。

读取逻辑:

await initStroageFromDataBase(); // 一次性拉取全部记录
getStoageInfoByKey({ key }); // 判断当前广告是否展示过

设置逻辑:

setStoageInfoByKey({ key }); // 设置为“已展示”

前端逻辑:

操作方法说明
初始化initStroageFromDataBase()拉取并缓存在内存中
查询是否展示getStoageInfoByKey()判断是否设置过
设置展示过setStoageInfoByKey()调用后端 API 保存状态

后端逻辑:

表名作用
multiterminal_key_stroage_resource控制广告项配置,包括是否启用、是否按子账号区分、是否过期
multiterminal_key_stroage_info实际记录用户维度的“已展示”状态

通过前端内存 + 后端统一记录的迁移过程,实现了:

  • 广告展示记录的统一管理
  • 避免重复展示带来的用户骚扰
  • 支持账号、子账号粒度的记录
  • 实现了更安全、可控的系统架构

这个优化过程是一个经典的“从内存缓存 ➝ 后端状态同步”的升级路线,值得在中大型系统中推广。

优化后代码示例

初始化(一次请求所有 key)

// 初始化阶段调用
const dictMap = new Map<string, string>();

async function initDictMap() {
  const res = await fetch('/api/dict/all'); // 后端返回所有 key-value
  res.data.forEach(item => {
    dictMap.set(item.key, item.value);
  });
}

使用(统一查)

function getLabelByKey(key: string): string {
  return dictMap.get(key) || '--';
}

优势

  • 请求只需一次
  • 使用统一 Map 读取,代码简洁
  • 无 localStorage 容量限制问题

这样就完成了广告展现的优化,去除了之前繁琐的操作,重复代码一大堆的问题,提高开发效率,并且不会出现loacl爆仓的问题,同时功能还更齐全了,可以控制子账号的权限,嘎嘎好用。