1. 性能优化

TCP

  1. ip负责找到
  2. tcp负责数据完整性和有序性,三次握手,粘包,滑动窗口等机制
  3. http 应用层,负责应用层数据,数据终止时机

需要UDP的场景:
直播,语音识别。
1、性能高,允许丢包
2、包本身特别小,不需要拆分数据,重发机制很好写,比较典型的就是dns

优化策略
1、长链接
2、减少文件体积,js打包,图片压缩,gizp压缩
3、减少请求次数,雪碧图。兰家早,js,css打包,缓存机制
4、减少用户和服务器距离,cdn

三次握手:

  1. 你在不
  2. 我在呢
  3. 那我开始发送数据了

http:

  1. 携带无状态的数据,比如header,cookie
  2. 合理利用缓存

前端代码到底怎么上线?
最早阶段,写完html,css,js直接拷贝到nginx的dist目录,问题是图片icon太多,文件重名的情况用户需要强刷
现在,使用webpack,比如雪碧图,文件名修改,利用hash值,gizp,nginx负载均衡
拆包的好处文件改变不是整个文件都发生改变

缓存

  1. http cache:协商缓存
  2. service worker cache: 离线缓存
  3. memory cache: 内存中的缓存
  4. push cache:http2的缓存

文件打包

分析文件大小

npm install lodash echarts moment --save-dev;

const BundleAnalayzerplugin = require('webpack-bundle-analyzer').BundleAnalayzerplugin;

module.exports = {
    configureWebpacl: {
        plugins: [
            new BundleAnalayzerplugin()
        ]
    }
}

输出代码

import monent from 'moment';
import _ from 'lodash';
Vue.config.productionTip = false;
console.log(moment());
console.log(_.max([5,4,1,6,8]));

或者执行vue ui

如果我们改成只引入lodash 需要的模块,moment换成更小的dayjs
打包后的大小从464kb下江城143kb

删除冗余代码的tree-shaking,和去除无效代码,我们webpack那里都介绍过,这里不赘述了,如果是个别页面使用了echats, 移动记得懒加载

图片优化

图片通常是占用流量的,PC端加载的平均图片大小时600k,简直比js打包后的文件还大了,所有针对图片的优化,也是收益不错的

  1. jpg
    有损压缩
    体积小,不支持透明
    用于背景,轮播
  2. png
    有损压缩,质量高,支持透明
    色彩线条更丰富,小图,比如logo,商品icon
  3. svg
    文本,体积小矢量图
    渲染成本,学习成本

打包雪碧图,减少http请求次数,webpack-spritesmith
gzip压缩, accept-encoding: gzip; 开启

Http压缩就是以缩小体积为目的,对http内容进行重新编码的过程
gzip压缩背后的原理,是在一个文本文件中找出一些重复出现的字符串,临时替换他们,从而使整个文件变小,根据这个原理,文件中代码的重复率越高,那么压缩的效率越高,使用Gzip的收益也就越大,反之亦然。

基本上来说,Gzip就是服务器干的活,比如nginx

本地存储

CDN
项目部署在分布式的服务器上,用户就近获取资源
cdn单独的域名,浏览器并发获取

服务端渲染
如果是spa首屏ssr就是性能优化的重要一环
nuxt 和 next

Vue服务端渲染

const vue = require('vue');
// 创建一个express应用
const server = require('express')();
// 提取出renderer实例
const renderer = require('vue-server-renderer').createRenderer();

server.get('*', (req, res) => {
    const app = new Vue({
        data: {
            url: req.url
        },
        template: `<div>访问的 URL 是:{{ url }}</div>`
    });
    // renderToString 把vue转化为真实dom的关键方法
    renderer.renderToString(app, (err, html) => {
        if (err) {
            res.status(500).end('Internal Server Error');
            return;
        }
        res.send(`
            <!DOCTYPE html>
            <html lang="en">
                <head>
                    <title>Hello</title>
                </head>
                <body>
                    ${html}
                </body>
            </html>
        `)
    })
});

server.listen(8080);

nuxt.js 服务端渲染框架体验

  1. 基于Vuejs
  2. 服务端渲染
  3. 路由
  4. 热加载
  5. 支持http2

react 服务端渲染

import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './App';

const app = express();
// renderToString 把虚拟DOM转化为真实DOM的关键方法
const RDom = renderToString(<App />);
// 编写HTML模板,插入转化后的真实DOM内容
const Page = `
            <!DOCTYPE html>
            <html lang="en">
                <head>
                    <title>Hello</title>
                </head>
                <body>
                    ${RDom}
                </body>
            </html>
`
app.get('/index', function(req, res) {
    res.send(Page);
});
const server = app.listen(8080);

接口如何更快

  1. 服务问题
  2. 服务也要做缓存,比如说做一个秒杀,只特价100个
  3. 数据库读取比较慢,我们可以把这100个放内存(缓存) redis

首屏加载有哪些比较好的方式

  1. 同构
  2. 骨架屏 + 懒加载

网络优化

TCP
可靠 数据完整性,数据有序
数据切片,重发,慢启动,滑动窗口,三次握手
操作系统内置

基于TCP/IP 有了 HTTP 应用层

缓存:
如果1小时内访问了文件,直接使用缓存200 from cache
如果过了1个小时,就会咨询服务,有变化更新,无变化304

文件合并
gzip服务端开启
文件hash indexasdsada1223.js

hash有点:
上线不会出现白屏问题,先上线cdn,后上线html
每次部署,修改的文件,文件名都不一样,所以不会替换,每次先上线cdn
由于静态资源基本都是kb和mb的量级,硬盘也便宜,三个月清理一次,大概有几个mb的冗余空间。可以接受

雅虎军规!

性能监控 Performance

performance.getEntriesByType('navigation');
重定向耗时: redirectEnd - redirectStart
DNS查询耗时: domainLookuoEnd - domainLookupStart
TCP链接耗时: connectEnd - connectStart
HTTP请求耗时: responseEnd - responseStart
解析dom树耗时: domComplete - domInteractive
白屏时间: responseStart - navigationStart
DOMready时间: domContentLoadedEventEnd - navigationStart
onload时间: loadEventEnd - navigationStart, 也是onload回调函数执行的时间

LightHouse

chrome 插件, 现在可以用命令行执行

npm install -g lighthouse

lighthouse https://www.baidu.com/ --view

如何做性能监控

  1. 通过performance 这个api可以获取到当前网页的监控数据
  2. 通过img标签发出请求,server 接受请求,解析参数,获取到用户ip, 比如百度统计,加载了很多的图片
  3. 前端要做统计,肯定要发网络请求,ajax, img, script, link, 使用img加载1*1的小图

服务实现:

  1. 第一种方式:img 实际是个接口,通过处理接口可以监控
  2. 第二种: 不是接口,实际就是一个图片,访问任何静态资源。nginx都有日志, 通过处理日志,获取统计结果

节流:
滚动,隔一段时间只触发一次,第一个说了算,在时间结束触发。

const throttle = (func, wait = 50) => {
    let lastTime = 0;
    return (...args) => {
        let now = Date.now();
        if (now - lastTime > wait) {
            lastTime = now;
            func.apply(this, args);
        }
    }
}

防抖:
输入,完成后再统一发送请求,最后一个人说了算,只认最后一次

const debounce = (func, wait = 50) => {
    let timer = 0;
    return function(...args) {
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(() => {
            func.apply(this, args);
        }, wait);
    }
}

重绘,回流

回流是影响最大的

  1. 窗体,字体大小
  2. 增加样式表
  3. 内容变化
  4. class属性
  5. offsetWidth 和 offsetHeight
  6. fixed

DocumentFragment 缓存 dom

lazy-load

// 获取所有图片
const imgs = document.getElementsByTagName('img');
// 获取可视区的高度
const viewHeight = window.innerHeight || document.documentElement.clientHeight;

// num 用于统计当前显示到了哪一张图片
let num = 0;
function lazyload() {
    for (let i = num; i < imgs.length; i++) {
        // 用可视区高度减去元素顶部距离可视区顶部的高度
        let distance = viewHeight - imgs[i].getBoundingClientRect().top;
        // 如果可视区高度大于等于元素顶部距离可视区顶部的高度,说明元素露出
        if (distance >= 0) {
            // 给元素写入真实的src,展示图片
            imgs[i].src = imgs[i].getAttribute('data-src');
            // 前i张图片已经加载完毕,下次从第i + 1 张开始检查是否露出
            num = i + 1;
        }
    }
}

window.addEventListener('scroll', lazyload, false);

Object.freeze();
冻结数据,取消setters; 不可变

值传递需要的props
不要随便

redux + reselect
data扁平化
每当store发生改变的时候,connect就会触发重新计算,为了减少重复的不需要计算,减少大型项目的性能开支,需要对selector函数做缓存,推荐使用reactjs/reselect

长列表优化如何优化?
只保留三屏的页面dom,react-virtualized,只渲染可见的
如果有1000个,只渲染20个,鼠标滚动的时候,新节点替换老节点。

renderRow(item) {
    return <div>
    <img src"image">
    <div>name</div>
    </div>
}

import { List } from 'react-virtualized';
<div>
{
    this.list.map(this.renderRow.bind(this))
}
</div>


<List
    width={100}
    height={100}
    rowHeight={10}
    rowRenderer={this.renderRow.bind(this)}
    rowCount={this.list.length}
/>

css优化
#box div
先找到所有的div
遍历查找所有的父级,是否有符合id名字为box的元素,再递归向上一级一级查找祖先

  1. 减少初次查找的次数
  2. 需要递归,建议多用>子选择器