npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

frequency-manager

v1.0.0

Published

Provide centralised frequency-shown management service about Badges, Tooltips, Dialogs, etc...

Downloads

2

Readme

Frequency Manager

对于前端系统中普遍存在的红点、气泡、弹窗、步骤引导等交互性展示元素,基于它们与业务逻辑低耦和、和按照特定频率出现的两个共有特点,提供一个通用的中心化的频率展示管理工具。

Installation

npm install frequency-manager

Usage

这里有一个基于 React 应用的例子

Document

背景

  • 频率展示元素大量存在,但缺乏有效的统一管理,分别独立控制比较繁琐且重复工作较多;
  • 部分场景下多个元素相互竞争展示的逻辑比较麻烦;
  • 与业务逻辑耦合严重;

本工具主要功能点有:

  1. 提供基本的频率管理功能,包括展示次数、展示间隔、展示周期,以及额外的自定义逻辑;
  2. 对于多个元素竞争展示的场景,提供基于优先级、最大展示数目、延时间隔等的调度功能;
  3. 提供默认的展示记录本地持久化功能(基于 LocalStorage),也支持自定义扩展持久化;
  4. 预设配置化,接口切面化,调用灵活。

概念

  • Element:频率控制的基本单位,一个红点、气泡、弹窗等都可以是一个元素。单独使用 Element 类时需实现其中的 getCurrentTime、getStorage、setStorage 方法;
  • Bucket:竞争逻辑的基本单位,多个元素参与相同的竞争逻辑,则它们共同组成一个分桶。单独使用 Bucket 类时需实现其中的 getCurrentTime、getElementClass 方法;
  • FrequencyManager:管理器,可以包括多个分桶(默认只有一个),提供统一的 API 以让使用者在合适的时机主动调用。使用时需实现其中的 resetTime、getStorage、setStorage 方法;
  • LocalFrequencyManager:FrequencyManager 基于 LocalStorage 的持久化方案实现。

配置

  • Element
{
  // 元素的 key,使用者需保证其唯一性
  key,

  // 元素需要被展示的次数,默认1次
  showCount,

  // 元素距上次出现的最小时间间隔(单位:ms),默认300ms
  delayInterval,

  // 一个展示周期的起始时间(时间戳)
  startTime,

  // 一个展示周期的长度(单位:ms)
  // 若 startTime 存在则以 startTime 为准,若 startTime 和 duration 都不存在,则表示展示周期为永久
  duration,

  // 自定义的判断是否可展示的方法,接受当前的存储记录作为参数,返回结果表示是否展示
  frequency,

  // 默认为 true,表示 frequency 逻辑与 showCount、delayInterval、startTime、duration 等配合使用
  // 若 frequency 为 false,则表示元素是否展示仅以 frequency 的返回结果为准
  combinative,
}
  • Bucket
{
  // 分桶的 Id,默认为 __DEFAULT_BUCKET_ID__,即变量 DEFAULT_BUCKET_ID 的值
  bucketId,

  // 元素列表
  elements,

  // 可同时展示的最大元素数目,默认无限制
  maxShowNum,

  // 每个批次的元素(maxShowNum 个)展示的最小时间间隔,默认为 0
  minInterval,
}
  • FrequencyManager
{
  // 除默认分桶外是否还有额外的自定义分桶,默认为 false
  useBucket,
}

需要注意的是,FrequencyManger 对于配置对象有一定的解析规则以方便使用者。

  1. 配置对象是一个数组,此时该数组应当是一个元素配置列表。显然,此时只有默认分桶,且无竞争性逻辑。
const freqManager = new FrequencyManager([
  {
    // 无任何额外配置,即:展示一次后永不再出现
    key: 'badge_a',
  },
  {
    // 展示3次
    key: 'badge_e',
    showCount: 3,
  },
  {
    // 每7天(时间段)内最多展示3次,且两次展示间隔至少12个小时
    key: 'badge_i',
    duration: 7 * 24 * 60 * 60 * 1000,
    delayInterval: 12 * 60 * 60 * 1000,
    showCount: 3,
  },
  {
    // 每天(自然日)最多展示2次,且总次数不超过5次,且最晚展示时间不超过 2022/01/01-零时
    key: 'badge_f',
    showCount: 2,
    startTime: new Date().setHours(0, 0, 0, 0),
    frequency(storage) {
      const {
        count = 0, // 已展示的次数
        lastTime = 0, // 最近一次展示的时间
        times = [], // 最近一个周期内的历次展示时间
        value, // 额外的自定义存储的值
      } = storage || {};
      return count < 5 && Date.now() < new Date('2022/01/01').getTime();
    },
  },
]);
  1. 配置对象包含了竞争性元素,但未开启 useBucket,即只有默认分桶。
const freqManager = new FrequencyManager({
  maxShowNum: 2,
  elements: [
    // 没有指定 priority,即认为不参与竞争的元素
    {
      key: 'badge_a',
    },

    // 参与竞争的元素
    {
      key: 'tooltip_b',
      priority: 1,
    },
    // 最多曝光3次(但若点击则永远隐藏),且相邻两次展示间隔至少1小时
    {
      key: 'tooltip_f',
      showCount: 3,
      priority: 2,
      delayInterval: 60 * 60 * 1000,
    },
    {
      // 每天(自然日)最多展示2次,且总次数不超过5次,且最晚展示时间不超过 2022/01/01 零时
      key: 'tooltip_g',
      priority: 5,
      startTime: new Date().setHours(0, 0, 0, 0),
      showCount: 2,
      frequency(storage) {
        // frequency 返回结果与其它条件都成立时才展示
        const { count = 0 } = storage || {};
        return count < 5 && Date.now() < new Date('2022/01/01').getTime();
      },
    },
    {
      // 完全自定义展示
      // 默认展示4次,且相邻两次展示间隔依次至少为 1天、3天、7天
      // 若用户触发了标记(marked),则改为永久每7天出现一次
      key: 'tooltip_d',
      priority: 9,
      combinative: false,
      frequency(storage) {
        const { count = 0, lastTime = 0, value } = storage || {};
        const intervals = [1, 3, 7];
        const unit = 24 * 60 * 60 * 1000;
        if (count === 0) {
          return true;
        } else if (value && value.marked) {
          return Date.now() - lastTime >= 7 * unit;
        } else {
          return (
            count < 4 && Date.now() - lastTime >= intervals[count - 1] * unit
          );
        }
      },
    },
  ],
});
  1. 配置对象包含了 useBucket: true。此时除 useBucket、maxShowNum、elements、minInterval 之外的其余属性都将被认为是自定义的分桶。
const freqManager = new FrequencyManager({
  {
    useBucket: true,

    // 默认分桶
    maxShowNum: 1,
    elements: [
      {
        key: 'tooltip_a',
        priority: 1,
      },
      {
        key: 'tooltip_b',
        priority: 2,
      },
    ]

    // 自定义分桶
    // 逐个展示弹框,展示间隔为至少10分钟
    dialogBucket: {
      maxShowNum: 1,
      minInterval: 10 * 60 * 1000,
      elements: [
        {
          key: 'dialog_1',
          priority: 1,
        },
        {
          key: 'dialog_2',
          priority: 2,
        },
        {
          key: 'dialog_3',
          priority: 3,
        },
      ],
    },
  },
})

API

  • checkShow:巡检指定范围的元素是否显示

    • 无参数:巡检所有分桶(或默认分桶)中的所有元素;

    • Object:巡检指定的一个分桶(或默认分桶):

    // 检测指定分桶中的所有元素
    checkShow({ bucketId: 'bucket_1' });
    
    // 检测指定分桶中的所有竞争元素
    checkShow({
      bucketId: 'bucket_2',
      onlyCompete: true, // 默认 false
    });
    
    // 检测指定分桶中的所有非竞争元素
    checkShow({
      bucketId: 'bucket_3',
      excludeCompete: true, // 默认 false
    });
    
    // 检测指定分桶中的一个非竞争元素
    checkShow({
      bucketId: 'bucket_4',
      key: 'badge_a',
    });
    
    // 检测指定分桶中的一批非竞争元素
    checkShow({
      bucketId: 'bucket_5',
      includes: ['badge_a', 'badge_b'],
    });
    
    // 检测指定分桶中除特定一批元素之外的所有非竞争元素
    checkShow({
      bucketId: 'bucket_6',
      excludes: ['badge_a', 'badge_b'],
    });
    
    // 注意:若未指定 bucketId,在上述示例同样可作用于默认分桶
    // 如,检测默认分桶中指定的一个元素
    checkShow({ key: 'badge_a' });
    
    // 另外:
    // onlyCompete 与 excludeCompete 不能同时为 true;
    // key、includes、excludes 不能同时生效,且优先级 key > includes > excludes;
    • Array:巡检指定的一批分桶,其中每一个分桶的参数都可以是上述示例之一。
    checkShow([
      {
        key: 'badge_a',
      },
      {
        bucketId: 'custom_bucket',
        excludeCompete: true,
      },
    ]);
  • hide:隐藏指定的某个元素

    // 隐藏指定分桶中的指定元素
    // key 是必需的
    // 若未指定 bucketId,则作用于默认分桶
    hide({
      bucketId: 'bucket_1',
      key: 'badge_a',
    });
    
    // 有可选的额外参数
    hide({
      bucketId: 'bucket_2',
      key: 'badge_a',
      // 仅标记为隐藏,实际上等下一次 checkShow 的时候才真正消失
      immediate: false, // 默认 true
      // 将该元素已展示的次数直接记为 3
      count: 3,
      // 其它需要存储的自定义数据
      value: { marked: true },
    });

License

MIT License