You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firefox扩展:快速获取所有书签文件夹的高效方法

快速获取Firefox扩展中书签文件夹的优化方案

原代码的核心问题

  1. 全量数据加载:browser.bookmarks.getTree()会获取整个书签树(包含所有书签项和文件夹),书签数量大时,数据加载和遍历成本极高。
  2. 遍历终止不彻底:当结果数量达到max时,仅退出当前递归调用,上层循环仍会继续遍历剩余节点。
  3. 无效节点遍历:未过滤书签项,遍历了大量非目标节点,拖慢整体速度。

最优实现方案(基于API查询)

利用Firefox书签API的browser.bookmarks.search()直接查询文件夹,这是效率最高的方式——该API由浏览器底层优化,无需加载全量书签数据,且能直接过滤文件夹类型。

App.get_bookmark_folders = async (title = "") => {
  const max = App.get_setting(`max_bookmark_folders`);
  const max_depth = 3;
  const titleLower = title.toLowerCase();

  // 1. 一次性获取所有文件夹,API层面过滤类型
  const allFolders = await browser.bookmarks.search({ type: "folder" });

  // 2. 构建映射表,用于快速计算文件夹深度
  const folderMap = new Map();
  const parentMap = new Map();
  allFolders.forEach(folder => {
    folderMap.set(folder.id, folder);
    if (folder.parentId) {
      parentMap.set(folder.id, folder.parentId);
    }
  });

  // 3. 缓存深度计算结果,避免重复递归
  const depthMap = new Map();
  const calculateDepth = (folderId) => {
    if (depthMap.has(folderId)) return depthMap.get(folderId);
    // 根目录子节点(书签菜单、工具栏等)深度为1
    if (!parentMap.has(folderId)) {
      depthMap.set(folderId, 1);
      return 1;
    }
    const parentDepth = calculateDepth(parentMap.get(folderId));
    const depth = parentDepth + 1;
    depthMap.set(folderId, depth);
    return depth;
  };

  // 4. 过滤符合条件的文件夹,取前max个结果
  const filteredFolders = allFolders
    .filter(folder => {
      // 匹配标题(若有输入)
      if (title && !folder.title?.toLowerCase().includes(titleLower)) return false;
      // 检查深度是否符合要求
      return calculateDepth(folder.id) <= max_depth;
    })
    .slice(0, max);

  return filteredFolders;
};

优化后的递归遍历方案(适合提前终止场景)

如果需要在收集到足够数量的文件夹后立即停止遍历,可采用该方案——仅遍历文件夹节点,且用全局标志彻底中断所有递归:

App.get_bookmark_folders = async (title = "") => {
  const folders = [];
  const max = App.get_setting(`max_bookmark_folders`);
  const titleLower = title.toLowerCase();
  const max_depth = 3;
  let stopTraversal = false; // 终止遍历的全局标志

  // 获取根目录的子文件夹(仅书签菜单、工具栏、其他书签三个节点)
  const rootTree = await browser.bookmarks.getTree();
  const rootFolders = rootTree[0].children;

  const traverse = async (nodes, currentDepth) => {
    if (currentDepth > max_depth || stopTraversal) return;

    for (const node of nodes) {
      if (stopTraversal) break;

      // 仅处理文件夹类型节点
      if (node.type === "folder") {
        // 标题匹配则加入结果集
        if (node.title?.toLowerCase().includes(titleLower)) {
          folders.push(node);
          // 达到数量上限,立即终止所有遍历
          if (folders.length >= max) {
            stopTraversal = true;
            return;
          }
        }

        // 递归遍历子文件夹
        if (node.children) {
          await traverse(node.children, currentDepth + 1);
        }
      }
    }
  };

  await traverse(rootFolders, 1);
  return folders;
};

方案优势说明

  • API查询方案:借助浏览器原生查询能力,避免加载全量书签数据,深度计算用缓存减少重复操作,在书签数量大时性能提升尤为明显。
  • 递归遍历方案:仅遍历目标文件夹节点,跳过所有书签项,且通过全局标志彻底终止遍历,不会在达到数量上限后执行无用操作。

内容的提问来源于stack exchange,提问作者madprops

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 22:34:57