Skip to Content
LaunchExt | Chrome 扩展开发平台 (Next.js + Plasmo) 🚀 Read more → 
博客浏览器扩展开发:waitForAnyElement 的多次调用真的有必要吗?

浏览器扩展开发:waitForAnyElement 的多次调用真的有必要吗?

作者 esx_ai

最近在做微博自动填充功能的时候,有个小伙伴问我:为啥你的 handleWeiboFill 里要反复调用 waitForAnyElement,看起来好像有点重复劳动啊?

这问题问得挺好!表面上看确实像是在重复调用同一个函数,但仔细分析就会发现,每次调用其实都在干不同的事儿,各有各的用处。

四次调用都在干嘛

第一次:快速检查编辑器是否存在

let editorResult = await waitForAnyElement(selectors, { visibleOnly: true, timeout: 15000 })

这是在干嘛:先看看编辑器是不是已经在那儿了(比如用户手快已经点开了发微博框)

为啥要这么干:这是最快的路子,要是能找到就直接开始填充,省得再点按钮了

第二次:点击按钮后等编辑器加载

editorResult = await waitForAnyElement(selectors, { visibleOnly: true, timeout: 5000 })

这是在干嘛:点完”发微博”按钮后,等着编辑器真正加载到页面上

为啥要这么干:光点按钮不行,得确认编辑器确实出来了才能操作

第三次:兜底方案找编辑器

editorResult = await waitForAnyElement(universalSelectors, { visibleOnly: true, timeout: 5000 })

这是在干嘛:要是前面两种方法都找不到,就用通用的选择器再试试

为啥要这么干:微博说不定哪天就改版了,class名一变原来的选择器就废了,得有个备选方案

第四次:确认编辑器能正常用

const visible = await waitForAnyElement(selectors, { visibleOnly: true, timeout: 2000 }) if (!visible || !isVisibleStrict(editor)) { throw new Error("微博编辑器不可交互") }

这是在干嘛:就算编辑器在页面上,也可能被遮住或者没激活,得再确认一下

为啥要这么干:很多网站都是先把DOM挂上去,要用户点一下才能真正用,不检查这个容易填充失败

为啥不能只调用一次

看起来好像是在重复调用同一个函数,但其实每次都在检查不同的东西:

  • 第一次:看看编辑器是不是已经打开了
  • 第二次:点了按钮后等着编辑器加载
  • 第三次:前面都找不到的话用备用方案
  • 第四次:确认编辑器真的能用

waitForAnyElement 这个函数挺智能的,既能马上返回已经存在的元素,也能等着异步加载的元素。每次调用虽然函数一样,但等的目标完全不一样。

要是只调用一次,可能会漏掉很多情况:

  • 用户点按钮后新加载的编辑器抓不到
  • 编辑器虽然找到了但是被遮住了,填充了也没用
  • 网站改版后原来的选择器失效了

怎么让代码更好看

现在这样写逻辑挺清楚的,但看起来确实有点重复。可以试试这两个优化思路:

方案一:封装成状态机

async function getEditorForWeibo() { // 快速路径 → 点击按钮 → 兜底方案 → 确认可用 // 内部自动处理所有等待逻辑 return await findEditorWithRetry() }

外面调用的时候只需要一次:

const editor = await getEditorForWeibo()

方案二:增强等待函数

// 增加模式参数,一个函数搞定所有情况 await waitForAnyElement(selectors, { modes: ["exist", "interactive", "fallback"], timeout: 15000 })

最后说几句

多次调用 waitForAnyElement 不是为了凑数,而是每个阶段都需要确认不同的状态。写浏览器扩展就是这样,得考虑到各种可能的情况,代码才能稳定可靠。

不过为了代码看起来更舒服,确实可以把它封装得更好一些。我自己就更喜欢状态机的方案,把复杂的等待逻辑藏在里面,外面用起来简单明了。

大家在写类似功能的时候,不妨也想想自己的等待逻辑是不是覆盖了所有可能的情况。有时候多等一次,就能少很多莫名其妙的bug。

最后更新于