大家好,我是 luckySnail ,周五正当我和 AI 如胶似漆的时候,后端同事突然和我说有一个地方需要我优化一下,我就问他,什么快和我说,他打开一个项目页面,然后打开控制台和我说,你看,这个网页刚进入就把所有图片都请求了了一次,并且因为请求太多图片导致触发了我们设置的最大限制,导致后面的图片直接请求失败,从而导致左侧图片都是加载失败的样子
image-20241221181821017
好家伙,这都是老板白花花的银子呀!赶紧修复上线,可是怎么修复呢?
问题分析
解决问题前,我们可以先分析一下问题,就像我们看病一样,我们总得先挂号,让医生看看身体是怎么了。说回正题,问题分析:
-
页面首次加载时就请求所有图片资源
-
大量图片并发请求触发了服务器限制
-
导致部分图片加载失败
-
造成不必要的带宽消耗和性能浪费
知道了问题,我们看下解决方案:使用图片懒加载(Lazy Loading)技术。图片懒加载是一种网页性能优化技术,它可以延迟加载页面中不可见的图片,直到用户滚动到可见区域时才进行加载
其实大厂们也都是这么做的,不信我们看看掘金平台
image-20241221183028256
image-20241221183133520
我们可以看到当我们页面滚动到下面才加载对应的图片
解决问题
下面我们来解决一下我们教程中图片加载问题,由于我们项目使用 bytemd 作为内容渲染器,所以图片的渲染其实在 bytemd 内部完成的,那我们想要自定义渲染图片的逻辑,也就需要借助 bytemd 的自定义插件的能力了,通过查阅源码得知:插件也就是一个函数,用于扩展 Bytemd 编辑器和查看器的功能,返回指定的对象类型,返回对象类型已经定义好了,是 BytemdPlugin 。它包含五个属性:
-
remark:自定义 Markdown 解析
-
rehype:HTML 解析
-
actions:注册操作,也就是定义我们编辑框上面哪些小图标的
-
editorEffect :编辑器副作用
-
viewerEffect:查看器副作用
我们需要的是 viewerEffect ,然后我们只需要先获取到所有图片,然后为图片添加上懒加载的逻辑,具体的思路:
-
在 viewerEffect 中,拿到 markdownBody ,也就是 md 的内容,是一个 DOM 元素
-
通过 querySelectorAll 获取所有 img 标签,然后,我们有两个选择,
-
第一,使用游览器自带的图片懒加载
-
第二,使用 IntersectionObserver 来实现懒加载,这种方式可以设置一个占位图,这样体验更加好
最后,我们看一下具体代码:
import type { BytemdPlugin } from 'bytemd'export interface ImageLazyLoadOptions {// 是否使用原生懒加载useNativeLazy?: boolean;// 自定义加载占位图placeholderSrc?: string;// 自定义类名className?: string;
}export default function imageLazyLoad(options: ImageLazyLoadOptions = {}): BytemdPlugin {const {useNativeLazy = true,placeholderSrc = '',className = ''} = options;return {viewerEffect({ markdownBody }) {// 获取所有图片元素const images = markdownBody.querySelectorAll('img');images.forEach((img) => {// 保存原始srcconst originalSrc = img.getAttribute('src');if (useNativeLazy) {// 使用原生懒加载img.setAttribute('loading', 'lazy');} else {// 使用 Intersection Observer 实现懒加载const observer = new IntersectionObserver((entries) => {entries.forEach((entry) => {if (entry.isIntersecting) {const obImg = entry.target as HTMLImageElement;if (originalSrc) {obImg.src = originalSrc;}observer.unobserve(obImg);}});});// 设置占位图if (placeholderSrc) {img.src = placeholderSrc;}// 将原始图片地址存储在data属性中img.dataset.src = originalSrc || '';img.src = placeholderSrc;// 添加自定义类名if (className) {img.classList.add(className);}// 开始观察observer.observe(img);}});}}
}
我们看看效果吧!
image-20241221184754629
image-20241221184841801
image-20241221185043728
完美修复bug,也节省了开销
开源 tytemd 的图片懒加载插件
相信肯定也有其他小伙伴有同样的问题,那就开源吧,毕竟谁会拒绝直接拿来使用呢?
地址:https://www.npmjs.com/package/bytemd-plugin-image-lazy
如果你觉得写得不错,对你有帮助,点个赞再走吧!
哦对了,有人好奇如何从 0 发布一个 npm 包吗?