从零搭建博客之性能优化

从零搭建博客之性能优化

2020年08月09日 阅读:11 字数:972 阅读时长:2 分钟

小水管服务器,想要网站访问速度快,就得在性能优化方面下点功夫,像添加缓存、图片优化、CDN等等

由于是小水管服务器,想要网站访问速度快,就得在性能优化方面下点功夫

1.缓存

1.1数据库缓存

基于thinkjs的缓存框架,可以很容易扩展支持不同类型的缓存,比如存放到文件、内存、redis中

由于访问量不大,也不想用那么多中间件,所以暂时使用高速SSD+文件做缓存存储

比如把前台经常要查询的网站配置、栏目列表存储到缓存中

module.exports = class extends think.Model {
  /**
   * 获取栏目列表
   * @return {Array}
   */
  async getCacheCategory() {
    // 设置缓存 key 为 column,有效期为 30 天
    const field = 'id,name,keywords,description,filename,parent_id,type,level,is_nav,icon,version,link';
    const list = await this.cache('category', { timeout: 90 * 24 * 3600 * 1000 })
      .where({ is_show: 1 })
      .field(field)
      .order('no_order ASC')
      .select();

    return list;
  }
  /**
   * 获取系统配置
   * @return {Object} config表配置信息
   */
  async getCacheConfig() {
    const rows = await this.cache('config', { timeout: 90 * 24 * 3600 * 1000 }).select();
    const result = {};
    rows.forEach(item => {
      result[item.key] = item.value;
    });

    return result;
  }
}

2.图片优化

2.1减少资源大小

使用到 从零搭建博客之后台开发 里提到的图片处理服务

  • 图片裁剪
  • 格式转换 (目前主要用对象存储提供的智能返回webp格式的功能)

获取图片缩略图是在请求时进行而不是上传的时候,为了不影响访问速度,做了一层缓存,如果命中缓存则直接返回缩略图。

module.exports = class extends think.Service {
  /**
   * 获取缩略图
   * @param {String} src 原图地址
   * @param {Number} width 目标图片宽度
   * @param {Number} height 目标图片高度
   * @returns {String}
   */
  async getThumbnail({ src, width, height, fit }) {
    // 图片地址或宽高未提供
    if (think.isEmpty(src) || (!width && !height)) {
      return '';
    }

    const destDirname = `${path.dirname(src)}/thumb`;
    const fileSourceName = path.basename(src, path.extname(src));
    const dest = `${destDirname}/${fileSourceName}-w${width}-h${height}.jpg`;

    if (!this.thumbnailCache) {
      const cache = await think.cache('thumbnail');
      this.thumbnailCache = cache || {};
    }
    // 如果命中缓存则直接返回
    if (this.thumbnailCache[dest]) {
      return dest;
    }

    // 如果目标文件存在,则写入缓存
    const destAbsolutePath = path.join(think.RESOURCE_PATH, dest);
    if (think.isExist(destAbsolutePath)) {
      this.cacheQueue.push({ value: dest });
    } else {
      // 如果目标文件不存在,则进行裁剪生成
      const step = this.sharpService.resizeAndCrop({
        width: +width,
        height: +height,
        fit: +fit,
        src,
        dest,
        destAbsolutePath
      });
      this.promiseList.push(step);
    }

    return dest;
  }

  // 裁剪图片
  async handleCropImage() {
    let result = [];
    if (this.promiseList.length) {
      result = await Promise.allSettled(this.promiseList);
    }
    await this.addThumbnailCache([...this.cacheQueue, ...result]);

    this.promiseList = [];
    this.cacheQueue = [];
  }

  /**
   * 添加缩略图缓存
   * @param {String} url 缩略图地址
   */
  addThumbnailCache(caches) {
    if (!caches.length) return;

    const temp = caches.reduce((cur, next) => {
      if (next.value) {
        cur[next.value] = 1;
      }
      return cur;
    }, {});
    const thumbnailCache = {
      ...this.thumbnailCache,
      ...temp
    };

    return think.cache('thumbnail', thumbnailCache, { timeout: 90 * 24 * 3600 * 1000 });
  }
}

2.3.响应式图片

关于响应式图片,详情可以查看 web性能优化之图片处理

添加vue过滤器来设置图片的srcset属性

/**
 * 获取图片的srcset属性
 * @param {String} src 图片地址
 * @param {Number} width 图片宽度
 * @returns {String}
 */
export function getImageSrcSet (src, width = 576) {
  let result = ''
  const halfWidth = width / 2
  const smallWidth = halfWidth < 576 ? 576 : halfWidth
  if (src) {
    result = `${src}?imageMogr2/thumbnail/!50p ${smallWidth}w, ${src}`
  }
  return result
}

使用方法:

<img
  class="img-full"
  :width="680"
  :height="440"
  :src="imgurl"
  :srcset="imgurl | getImageSrcSet(680)"
  alt="名称"
/>

2.4懒加载

由于某些搜索引擎爬虫对图片懒加载支持还不够,文章内容添加懒加载可能会影响SEO优化。因此目前只对某些非关键内容添加图片懒加载。

如评论列表的头像和表情等,用了element-ui实现图片懒加载还是比较简单的,直接用el-image组件加上lazy属性就好

<div class="comment-avatar">
  <a
    rel="noopener noreferrer"
    :href="commentData.website ? commentData.website : 'javascript:;'"
    :target="commentData.website ? '__blank' : ''"
    :title="commentData.website"
  >
    <el-image class="comment-avatar__picture" :src="getAvatar(commentData)" lazy>
      <div slot="error" class="image-slot">
        <span class="el-icon-picture-outline" />
      </div>
    </el-image>
  </a>
</div>

3、DNS预解析

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <!--添加需要预解析的域名-->
    <link rel="preconnect" href="https://at.alicdn.com">
    <link rel="preconnect" href="https://cdn.timelessq.com">
    <link rel="dns-prefetch" href="https://at.alicdn.com">
    <link rel="dns-prefetch" href="https://cdn.timelessq.com">
  </head>
</html>

推荐阅读

恰饭区

评论区 (0)

0/500

还没有评论,快来抢第一吧