前端性能优化(一)提升加载速度

加入QQ群:864680898,一起学习进步!点击群名可查看本人网站,有最新文章!

前端性能优化————(一)提升加载速度

由于现在大部分是做的单页面应用了,那么会导致页面的首次加载时间非常的长。常见的三大框架Vue,react,angular都会存在这种问题,那么怎么来解决呢?

路由拆分

可以将路由打包拆分,将会生成多个js文件,在路由加载到的时候才加载该js文件,具体实现方案的话,如下:

1、基于require.js来实现引入模块的方式(比较老)

let routes = [
  {path: '/home', component: resolve => require(['./components/Home.vue'], resolve), children:[
    {path: '/detail', component: resolve => require(['./components/Detail.vue'], resolve)}
  ]}
]

2、es6模块化的拆分形式

let routes = [
  {path: '/home', component: () => import('./components/Home.vue'), children:[
    {path: '/detail', component: () => import('./components/Detail.vue'), resolve)}
  ]}
]

组件按需引入

像这种全局引入会导致最终打包文件过大,首次加载时间非常长

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

可以按需引入element的组件,要借助babel的模块插件,那么只会引入你导入的组件的那部分js,没有用到的就不会导入

1、安装babel的插件

npm install babel-plugin-component -D

2、修改.babellrc

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

3、在main.js或者vue的组件中只引入需要的组件

import { Button, Select } from 'element-ui';

图片懒加载

没有进入到可视区域的图片如果使用懒加载的话,就可以不加载,等进入可视区域再加载,可以缩短加载时间

在vue中使用一个懒加载的库vue-lazyload:

import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload, {
  preLoad: 1,    //预加载高度的比例
  error: 'http://cdn.uehtml.com/201402/1392662591495_1140x0.gif',  //图像的src加载失败
  loading: '', //src的图像加载
  attempt: 2,  //尝试计数
  listenEvents: [ 'scroll', 'mousewheel' ] //你想要监听的事件,我个人喜欢全部监听,方便
});

然后在vue的组件中使用v-lazy

<img v-lazy="myUrl" alt="">

可视化加载

原理和图片懒加载一样,但是我们有的不是图片,但是可能比图片还庞大的资源,肯定得使用可视化加载,如地图,庞大的组件;当然这是在它不必一开始就显示的前提下

webpack打包

1、sourcemap 一个可以从中查看源码的文件,但是在线上环境是没必要的,这个就可以关闭

2、别名的使用,使用别名比使用相对路径在服务器上查找文件更快

module.exports = {
  resolve: {
    extensions: ['.js', '.vue', '.json'],     //  使用这些后缀的文件时就可不写扩展名
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  }
}

3、assetsPublicPath设置为/时能被nginx代理识别,但是无法被文件系统识别,但是访问速度比设置成./时快

module.exports = {
  build:{
    assetsPublicPath: '/',
  }
}

有时我们想项目打包出来直接就能访问,完全是基于文件系统,相对路径的识别,只需要做如下更改

module.exports = {
  build:{
    assetsPublicPath: './',
  }
}

4、js文件压缩,webpack使用uglifyjs-webpack-plugin插件压缩js代码

CDN加速

CDN的全称Content Delivery Network,(缩写:CDN)即内容分发网络。

CDN是一个经策略性部署的整体系统,从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均而产生的用户访问网站响应速度慢的根本原因。

CDN目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,解决 Internet 网络拥塞状况,提高用户访问网站的响应速度。

一般的公司不可能在每个城市地区都有服务器,那么用户一次完整的请求要经过的历程将路漫漫其修远兮

  • 方法1、将比较大的库,如vue,vue-router引用稳定的三方cdn

在index.html引入

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
    <title>mySkey</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

然后在webpack中配置,修改webpack.base.config.js

module.exports = {
  externals: {
    'vue': 'Vue',
    'vue-router': 'VueRouter'
  }
}
  • 方法二、将前端的代码托管到有cdn的平台

像腾讯云,阿里云,七牛云这些平台都有cdn功能,可以将打包文件托管在上面来使用

服务端渲染 SSR

简单理解是将组件或页面通过服务器生成html字符串,再发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序

  • 优势

1、首屏加载快
相比于加载单页应用,我只需要加载当前页面的内容,而不需要像 React 或者 Vue 一样加载全部的 js 文件(当然,单页应用文件加载过大的情况可以使用 code spliting 来解决)。

2、SEO 优化
对于单页应用,搜索引擎并不能收录到 ajax 爬取数据之后然后再动态 js 渲染出来的页面(个人感觉是搜索引擎自己挖了个坑,然后全互联网跟着填坑)。

  • 缺陷

1、线上排错不方便
如果数据请求是 ajax 来进行,出现的问题都能够很方便的通过浏览器的控制台来观察。但是如果是服务端渲染,如果一个后台拼接数据的过程中或者组件书写的过程中出了问题,必须到对应的服务器端(node,java 等)去查看线上日志,再分析 debug。

2、职责混杂
浏览器和服务器端职责混杂,服务器端在一定程度上还得做前端的页面绘制工作(以前写 html 页面,写完之后再转成 jsp,再在里面混写 java 代码调用数据)。

加载顺序上限制,保证首页先显示的内容

首页可能不止请求一个接口,那么这些接口返回的顺序也不一致,我们应该保证能直接进入视野的区域先显示

比如列表从上到下的顺序是热门,最新,分类

<template>
    <div id="app">
      <div>{{hots}}</div>
      <div>{{news}}</div>
      <div>{{types}}</div>
    </div>
</template>
<script>
	export default {
  data () {
    return {
      hots:[],
      news:[],
      types:[]
    }
  },
  created () {
    // 保证最先加载热门的列表
    this.getHots()
      .then(()=>this.getNews())
      .then(()=>this.getTypes())
  },
  method: {
    async getHots(){
      return new Promise((resolve,reject)=>{
        this.hots = await ajax.get('/hots')
      })
    },
    async getNews(){
      return new Promise((resolve,reject)=>{
        this.news = await ajax.get('/news')
      })
    },
    async getTypes(){
      return new Promise((resolve,reject)=>{
        this.types = await ajax.get('/types')
      })
    }
  },
}
</script>

预加载

在当前页面完全加载之后就可以预先加载一些数据,可以加快用户操作时的速度,下面一个例子不太好,但是把原理说明了

<template>
    <div id="app">
      <img src="https://img.alicdn.com/simba/img/TB14sYVQXXXXXc1XXXXSutbFXXX.jpg" alt="">
      <img src="//img.alicdn.com/tfs/TB1iZ6EQXXXXXcsXFXXXXXXXXXX-520-280.jpg_q90_.webp" alt="">
      <img src="https://img.alicdn.com/simba/img/TB1C0dOPXXXXXarapXXSutbFXXX.jpg" alt="">
      <img src="//img.alicdn.com/tfs/TB1iZ6EQXXXXXcsXFXXXXXXXXXX-520-280.jpg_q90_.webp" alt="">
    </div>
</template>
<script>
	export default {
  data () {
    return {
      count : 0,
      show : false
    }
  },
  mounted () {
    var _this = this
    let imgs = document.querySelectorAll('img')
    Array.from(imgs).forEach((item)=>{
      let img = new Image()
      img.onload = ()=>{
      this.count++
      }
      img.src=item.getAttribute('src')
    })
  },
  watch : {
    count (val,oldval) {
      if(val == 4){
        this.show = true
        alert("加载完毕")
        //然后可以对后台发送一些ajax操作
      }
    }
  }
}
</script>

减少DNS查找

有一篇文章写的不错,讲述了从浏览器输入url回车后到页面显示到底发生了什么————从输入url到页面加载完成发生了什么?

每一个不同的域名都会DNS解析,这是很耗时间的,所以要减少域名的使用,当然,正常的项目也只有一个后台一个域名

当我们在浏览器的地址栏输入网址(譬如: www.22family.com) ,然后回车,回车这一瞬间到看到页面到底发生了什么呢?

域名解析 --> 发起TCP的3次握手 --> 建立TCP连接后发起http请求 --> 服务器响应http请求,浏览器得到html代码 --> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户

域名解析是页面加载的第一步,那么域名是如何解析的呢?见文章:(后面补上,or自行百度)

DNS也是开销,通常浏览器查找一个给定域名的IP地址要花费20~120毫秒,在完成域名解析之前,浏览器不能从服务器加载到任何东西。那么如何减少域名解析时间,加快页面加载速度呢?

当客户端DNS缓存(浏览器和操作系统)缓存为空时,DNS查找的数量与要加载的Web页面中唯一主机名的数量相同,包括页面URL、脚本、样式表、图片、Flash对象等的主机名。减少主机名的 数量就可以减少DNS查找的数量。

而减少唯一主机名的数量会潜在减少页面中并行下载的数量,这样减少主机名和并行下载的方案会产生矛盾,需要大家自己权衡。建议将组件放到至少两个但不多于4个主机名下,减少DNS查找的同时也允许高度并行下载。

gzip压缩

使用vue-cli的同胞都知道如何查看打包报告

npm run build --report

那么鼠标放上去会看到有个gzip的大小,明显比静态包小很多,这个放到服务器压缩承诺gzip文件后,依然能被谷歌这样的浏览器解析,能大幅提升加载速度

最基础的css,js引入位置

  • 样式表放头部

放在头部对于实际页面加载的时间并不能造成太大影响,但可以减少页面首屏出现的时间,使页面内容逐步呈现,改善用户体验,防止“白屏”。

我们总是希望页面能够尽快显示内容,为用户提供可视化的回馈,这对网速慢的用户来说是很重要的。

将样式表放在文档底部会阻止浏览器中的内容逐步出现。为了避免当样式变化时重绘页面元素,浏览器会阻塞内容逐步呈现,造成“白屏”。这源自浏览器的行为:如果样式表仍在加载,构建呈现树就是一种浪费,因为所有样式表加载解析完毕之前不需绘制任何东西

  • 脚本放底部

与样式表相同,脚本放在底部对于实际页面加载的时间并不能造成太大影响,但是这会减少页面首屏出现的时间,使页面内容逐步呈现。

js的下载和执行会阻塞Dom树的构建(严谨地说是中断了Dom树的更新),所以script标签放在首屏范围内的HTML代码段里会截断首屏的内容。

因为脚本可能修改页面内容,因此浏览器会等待;另外,也是为了保证脚本能够按照正确的顺序执行,因为后面的脚本可能与前面的脚本存在依赖关系,不按照顺序执行可能会产生错误。

使用本地存储

不是必要的动态数据可以使用本地存储localStorage,能保证用户下次进入的速度

  • 持续总结,没有结束~~~
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值