记解决AI流式对话中图片闪烁的问题

361 阅读3分钟

背景

在对接AI对话中大多数都是返回纯文本,但是联网搜索会有返回图片的情况,我也是偶然间才发现的,在AI的一顿输出中屏幕里的图片一闪一闪的,像是扔了个闪光弹。所以得想个法子处理一下。

分析原因

不断的回流和重绘

因为在AI对话中,SSE返回数据了,前端就得拿到content+=,由于AI返回的都是markdown格式的字符串,前端还得用第三方库把markdown解析成html去渲染,所以每次content变动都会重新解析成html,然后就是重新渲染了

布局跳动

因为AI返回的markdown字符串中图片是没有尺寸大小,如果自己没有去定义样式规定大小布局,浏览器在重新渲染时就得去计算,可能本地的其它样式也互相影响

频繁请求

还是在不断的重新渲染中遇到图片就请求,在浏览器的网络面板中可以观察到,连续重复的对同一图片请求

解决方案

一开始想到的肯定是问AI怎么办啦。当然我也问了,AI给了一些方案,但是试过了效果还是不好,但是解决了布局跳动,没解决图片闪烁的问题。

先简单说一下AI给的方案

  1. 给图片加上行内样式,规定宽高可以解决布局跳动的问题。【这个可以的】
  2. Map预加载,把图片预加载和缓存起来。【没有什么效果】
  3. 给图片加透明度opacity:0,等loaded后再把opacity:1。【没有什么效果,不过我试了visibility:hidden/show这种还彳亍,就是页面留白,会让人不知道是什么】

走过的一些弯路

  1. 监听content变化,再用正则替换img加上样式。再几次尝试后发现console没有打印,意识到content里是markdown格式的字符串,用正则去匹配html字符串是一丶用没有。
  2. 就是听信AI,上样式opacity和监听onload过渡。不过起码发现了visibility:show/hidden这东西好使。

最终方案

  1. 自定义marked的图片解析器,在解析图片时包上一层div,但是记得把href,title这些设置为data-方便后续处理,里面放一个本地的svg占位图,不是真实的网络图片。
  2. 监听对话是否完成,完成对话时,找到富文本里刚才包裹的所有div,这时候就可以清空div,再把真实的img挂载进去就大功告成了。但是我做了小优化,我利用vue中的hrender函数,把第三方组件的图片组件挂载到div了,可以实现预览。

自定义图片渲染器 image.png

对话完成后处理富文本里的图片 image.png

部分HTML结构 image.png

效果

回复中占位效果

wechat_2025-10-24_150124_038.png

对话完成后的效果

wechat_2025-10-24_113636_594.png