前端优化方案

924 阅读5分钟

前言

本文多数经验来自H5游戏(three.js + dom)开发。

我认为优化不单是代码写的更好,任务调度更合理。优化的目的是让使用者觉得更快、更流畅、更自然。

优化方案

js代码压缩

道理都懂,减少体积,减少解析时间。一般发布版使用压缩后的代码。推荐库 UglifyJS

配置表

配置表一般都有较强的结构和语义,我们可以生成结构配置,极大减少无用重复字节。比如武将表

export default {
    10001:{
        name: '@name10001',
        sid: 10001,
        country: 1,
        hp: 3000,
        buff: '@buff201',
        price: 30000,
        chip: 80,
        icon: 'texture/hero/10001.png',
        module: '@module10001',
        favor: 86,
        attr1: 40001,
        attr2: 40002,
        ...
    },
    10002:{
        name: '@name10002',
        sid: 10002,
        country: 1,
        hp: 3000,
        buff: '@buff202',
        price: 30000,
        chip: 80,
        icon: 'texture/hero/10002.png',
        module: '@module10002',
        favor: 86,
        attr1: 40011,
        attr2: 40012,
        ...
    }
    ...
}

下面是简单处理。使用class生成实例更好,性能更好,效率更高

const attrs = ['name','sid','country','hp','buff','price','chip','icon','module',...]
const hero = {
    10001:['@name10001', 10001, 1, 3000, '@buff201', 30000, 80, 'texture/hero/10001.png', '@module10001', 86, 40001, 40002,...],
    10002:['@name10002', 10002, 1, 3000, '@buff202', 30000, 80, 'texture/hero/10002.png', '@module10002', 86, 40011, 40012,...],
    ...
}
const heroMap = new Map();
export const getInfo = function(sid) {
    if(heroMap.has(sid)) {
        return heroMap.get(sid);
    }
    const info = {};
    for(let i = 0;i<attrs.length;i++){
        info[attrs[i]] = hero[sid][i]
    }
    heroMap.set(sid,info);
    return info;
}

css压缩

我们开始并没有对css做处理,但后来我们的界面全部采用工具生成,重复属性极多,比如position:absolute, flex-wrap:wrap等。如果建立映射,则只需要[p,1]就可替代。当然需要底层配合修改。

图片压缩

先推荐一下 imagemin 这个库。imagemin github

针对不同平台最好使用不同压缩方式。或者说如果浏览器支持 webp ,就优先使用它(png-webp减少80%)。

  • jpeg,png -> webp: imagemin-webp webp的压缩基本都一样,没什么好选的。
  • jpeg: imagemin-mozjpeg 记得做调研时发现squoosh在线转换使用的mozjpeg 压缩质量/体积比更高(-20%以上),忘记了为什么最终没用这个。有兴趣的可以去扒一下他们的代码。
  • png: imagemin-optipng imagemin-pngquant 前者较均衡(画质几乎看不到损失的情况下占用存储更小),推荐使用。后者压缩体积效果更佳,但渐变色的地方会出现条纹。

项目未使用gif,故不作建议。

图片尽可能都压缩一遍,以防出现一个icon几十M的情况。

字体精简

使用 fontcreator 打开一个字体文件,你会发现字体库是有限个字符的矢量图构成,这也就意味着:

  • 用不到的文字会占用多余的空间。
  • 字库越个性占用空间越大。

第一个可以优化的点就是删除无用字符,比如伤害的漂字,我们只需要数字,剔除除 012345789. 外的字符占用仅几kb。

精简工具:fontmin

第二个可以优化的点是尽量选用选用轮廓较少的字(横平竖直的一般会少一些)。这一条主要针对的是常用字库,因为量大,一般5000字+

另外,使用woff 而非 ttf。见 developer.mozilla.org/zh-CN/docs/…

音频压缩

可以合并声道,一定范围内降低音质。

减请求数

我们的下载是将当前所需文件打包成一个文件下载,然后根据打包时的信息分割,减少下载时间。但是后来我注意到,进入游戏后在network面板依然看到800多个请求!原来我们对js和图片预加载使用的 blobURL 受请求数量限制,而每一个请求的发起都有等待时间,查看详细请求时间的描述

  • 代码合并加载:可以在打包时就分割模块,合并到同一文件,也可以加载js前将多个Buffer合并在创建blobUrl。
  • 图片合并:可使用图片合并的库,将较小图片合并,并生成uv映射表。

这一条是相当重要,也是不容易优化的地方。上面提到的仅仅是我们的开发环境,针对各自的环境,可根据上面的链接查看请求耗时的地方进行优化。

避免有交互和更新时对磁盘的操作

这里的磁盘操作是指向 IndexDB 中写入数据。不过这个呢,取决于磁盘性能,现在市面上新发布的手机在这点上倒是不用担心了。

其他字节数据

约定格式,剔除无用数据。

分配用户时间

举个很简单的例子:

游戏loading界面一张图加一个读条本就算完成了,但策划会让加些tips和特效,这就是转移用户注意力,不会想着等了多少秒。

进入首界面,只加载核心内容,可以先闪一个log(1s),一个跑得飞快的进度条(1s),进度条结束等待0.5s,时间过去了快3s,但用户不觉得有等待。然后弹一个公告,手速再快关闭也需要1s,重要信息高亮提示,增加用户停留时间。再点击登录(0.5s),再给一个正常的读条。实际游戏加载已经过去了6s,而用户不会觉得有等待,但若是黑屏6s呢?

分配不是占用,尽量少让读条占用时间,因为用户并不需要读条。

优化内存

待续