精华内容
下载资源
问答
  • Java高性能高并发实战之页面优化技术(五)

    千次阅读 多人点赞 2020-05-03 19:35:18
    文章目录前言正文增加缓存页面...对于模块三部分主要是关于秒杀商品页面的设计主要是权限设计和秒杀时间的倒计时设计后续会持续推出,这部分主要来讲述页面优化部分的设计。 正文 对于秒杀业务的瓶颈大部分都是来...

    前言

    此篇文章是系列的第五章篇文章,具体文章目录:

    章节名称博客地址
    安装部署Redis集成Redis(已完结)
    页面登陆功能设计登录功能设计(更新优化中)
    秒杀页面具体设计秒杀详情页(已完结)
    JMeter初级压测学习Jmeter压测入门学习(已完结)
    页面优化设计页面优化设计(已完结)
    接口优化RabbbitMq接口优化(已完结)
    图形验证码等图形验证码及接口防刷(更新优化中)

    在前面学习到了基础的登录功能模块的设计(还在继续完善中)以及Redis封装类的设置对应的是github源码miaosha_2miaosha_2模块。对于模块三部分主要是关于秒杀商品页面的设计主要是权限设计和秒杀时间的倒计时设计后续会持续推出,这部分主要来讲述页面的优化部分的设计。

    正文

    对于秒杀业务的瓶颈大部分都是来源于数据库的设计,因为对于商品而言商家的增添,用户的购买减少商品的数量,以及用户的查询都是会访问到数据库,能够降低数据库的访问是我们在秒杀业务中要做的重中之重,所以这部分的页面优化我们主要考虑来减少对数据库的访问。

    增加缓存

    而第一种最有效减少对数据库的访问就是加缓存,通过各种粒度的缓存来实现减少对数据库的访问,通常用 页面缓存+ URL缓存+对象缓存,最大粒度的就是页面缓存,最小粒度的就是对象缓存。将这些缓存的信息缓存在Redis中,后面可以使用到RDM来进行具体查看,发现缓存了整个页面。

    页面静态化,前后端分离

    什么是页面静态化:对于现在的很多的应用程序都是使用到JSP页面或是thymeleaf 模板解析也都是动态化的。静态化就是单纯的html页面,通过js,ajax来请求服务端,进行页面的渲染等。
    好处: 前面提到了使用页面缓存技术,但是客户端还是会请求服务端来进行页面的下载,但是若是做了页面的静态化,客户端就相当于缓存了前端的静态页面,不需要次次的请求都从服务端进行页面数据的下载。

    页面缓存

    概念简述: 当我们在访问一个页面的时候,并不是就会立马前往服务端请求页面数据的下载,而是先在缓存中查看有没有这个页面数据,若是存在就会返回给客户端,若是没有再去服务端请求数据手动渲染数据,返回给客户端,然后存在缓存中。所以就包含以下的三步:

    • 去缓存
    • 手动渲染模板
    • 结果输出

    实际操作

    在我们实现页面缓存之前先来看一下之前是如何操作的,可以去github上下载源代码,对于前4部分是没有使用到页面缓存的,所以我们先来打开miaosha_4模块看之前是如何将我们的商品列表给渲染出来的。

    1. 首先是访问固定的商品列表的url:localhost:8080/goods/to_list查看代码:key看到是访问到固定的url以后,会在进行一系列的Controller-> Service-> dao从数据库中取出数据,然后存在一个list中,放在model中返回给商品列表页,这个时候对于用户的每一次访问到前端页面都会进行数据库的请求,这个时候在高并发的情况下肯定是不实用的,所以我们要进行思考和更改。
      如下是之前的操作:
        @RequestMapping(value="/to_list")
        public String list(Model model,MiaoshaUser user) {
        	model.addAttribute("user", user);
        	List<GoodsVo> goodsList = goodsService.listGoodsVo();
        	model.addAttribute("goodsList", goodsList);
        	 return "goods_list";
        }
    

    这个时候就需要用到了thymeleafViewResolver 具体可以参看参看地址使用ctrl+f进行全局搜索。既然知道使用到这个,就需要我们使用*@Autowired*注入:

        @Autowired
    	ThymeleafViewResolver thymeleafViewResolver;
    

    然后使用到下面这个方法(这个方法就是用来做缓存功能):

    thymeleafViewResolver.getTemplateEngine().process();
    

    但是我们需要传参数,就可以使用到快捷键 ctrl+P查看需要什么具体的参数:
    在这里插入图片描述
    这里我们可能会疑惑,IContext类型又是个什么类型呢,这个时候使用到双击shift进行全局的搜索:
    可以看到的是如下,然后我们点击进行:
    在这里插入图片描述
    点击进去之后使用快捷键ctrl+ alt+B查看相关的实现:查看与Spring相关联的配置(因为我们是Spring项目进行整合)。
    在这里插入图片描述
    可以发现若是我们想要使用SpringWebContext就需要传入参数呀,我们找到对应的实现,见下图:我们传入这些参数,然后new一个IContext类型的对象传入到我们的函数中,才能够实现其功能。

    在这里插入图片描述
    代码如下:

       @RequestMapping(value="/to_list", produces="text/html")
        @ResponseBody
        public String list(HttpServletRequest request, HttpServletResponse response, Model model,MiaoshaUser user) {
        	model.addAttribute("user", user);
        	//取缓存
        	String html = redisService.get(GoodsKey.getGoodsList, "", String.class);
        	if(!StringUtils.isEmpty(html)) {
        		return html;
        	}
        	List<GoodsVo> goodsList = goodsService.listGoodsVo();
        	model.addAttribute("goodsList", goodsList);
    		SpringWebContext ctx=new SpringWebContext(request,response,request.getServletContext(),request.getLocale(),
    		model.asMap(),applicationContext);
    		// new了一个ctx 传入上面要求的参数,然后传入到process函数中即可返回我们的页面信息。
    		html=thymeleafViewResolver.getTemplateEngine().process("goods_list",ctx);
    		if(!StringUtils.isEmpty(html)){
    			redisService.set(GoodsKey.getGoodsList,"",html);
    			// 判断缓存是否是空。
    		}
        	return html;
        }
    

    注意在之前的文章中我们已经封装了对应的redisService 所以这里将GoodsKey对应的缓存也实现相对应的加入:

    public class GoodsKey extends BasePrefix{
    
    	private GoodsKey(int expireSeconds, String prefix) {
    		super(expireSeconds, prefix);
    	}
    	public static GoodsKey getGoodsList = new GoodsKey(60, "gl");
    	// 这里设置一个过期时间,我们思考一下对于页面缓存的处理是为了防止在瞬间大量的用户请求到同一个页面而导致服务端响应超载,这里设置过期时间为60s,
    	//表示这个页面缓存为一分钟,在一分钟里面再度访问就可以请求到这个缓存,但是却不能够一直留有这个缓存的信息,因为页面会发生变动。
    	//我们可以接受自己的页面是一分钟之前的页面,再刷新就好了,但是若是保存的一直都是之前的页面那体验也未免太差了。
    	public static GoodsKey getGoodsDetail = new GoodsKey(60, "gd");
    }
    

    以上都完成以后就可以返回页面,我们做一个测试,访问http://localhost:8080/goods/to_list页面,然后页面信息就会缓存到redis中,我们在reids客户端中进行查看,发现将html页面都给缓存了下来如下图所示,这个时候当在高并发的情况下很多人都有访问到这个页面时候,就会从Redis中取出这个数据而不是再度进行数据库的查询,也就减少了对数据库的访问。
    可以看到对应的key值的格式(具体可参见redis数据封装那一节的设计,一方面是使用到缓存,另外一方面是防止Key值的重复)
    在这里插入图片描述

    URL缓存

    对于URL缓存的大致思想其实和前面的商品列表是类似的也都是使用到thymeleafViewResolver 但是也有不同的地方。
    举个栗子:对于商品的列表页面,对于任何人的访问列表页面都是一样的,但是对于商品的详情页面,我们每个商品的显示的列表页面应该不同,所以再存入到redis缓存中时候对于页面缓存,我们这样写:

    	redisService.set(GoodsKey.getGoodsList,"",html);
    	// 可以看到的是对于 中间的参数表示key值为空,表示无差别key值。
    	```
    	对于URL缓存我们可以以details为例:
    	```java
    		redisService.set(GoodsKey.getGoodsDetail, ""+goodsId, html);
    		// key值传入时候需要带上商品的id,这样就可以根据具体的id信息来进行缓存处理操作。
    

    对象缓存

    在前面完成了对于页面缓存:缓存哪些在短时间内访问很高的页面加入到redis缓存中,可以让用户在访问同一个页面的时候不会每次都会请求到数据库,但是这个页面缓存也是有时间限制的我们限制在一分钟,就是说你过了一分钟之后再度请求这个页面,若你还是第一次请求,那么就会再度请求到数据库,然后再度加入缓存。
    对于URL缓存的粒度会更加细,对于商品的列表页面是无差别的,不同的用户也会显示相同的页面,但是对于商品的详情页面就需要根据具体的商品的id信息来具体显示所以URL缓存会更加对应匹配。
    对于对象缓存也是属于缓存类的一种,顾名思义就是缓存当前用户对象的具体数据,这样对于每一个用户就会有不同的页面以及数据显示。

    具体实现思想

    在之前我们没有设置对象缓存之前会根据传入的id信息来查询数据库,来判断当前用户的登录的账号(手机号码是否存在)

    // 调用底层的查询数据库。
    public MiaoshaUser getById(long id) {
    		return miaoshaUserDao.getById(id);
    	}
    

    这里就可以使用到对象缓存,之前在登录功能设计中有设计到使用一个唯一的token信息来实现分布式session功能(具体原因上一篇文章中有介绍),所以这里就思考能不能实现对token信息的缓存处理,让在查询数据库之前先进行缓存的查询。然后再进行一系列的操作。

    具体实现过程

    1. 既然想要将token信息添加到redis缓存中,就需要先生成对应的getById函数
    public static  MiaoshaUserKey getById=new MiaoshaUserKey(0,"id");
    // 表示无过期时间
    
    1. 完成以后就可以在redis中进行查询:
    //取缓存
    		MiaoshaUser user = redisService.get(MiaoshaUserKey.getById, ""+id, MiaoshaUser.class);
    
    1. 如果不为空表示查询到了对应的信息,正确返回,若是为空表示之前的信息没有就需要将信息加入到缓存中
    redisService.set(MiaoshaUserKey.getById, ""+id, user);
    

    所以以上代码为:

    public MiaoshaUser getById(long id) {
    		//取缓存
    		MiaoshaUser user = redisService.get(MiaoshaUserKey.getById, ""+id, MiaoshaUser.class);
    		if(user != null) {
    			return user;
    		}
    		//取数据库
    		user = miaoshaUserDao.getById(id);
    		if(user != null) {
    			redisService.set(MiaoshaUserKey.getById, ""+id, user);
    		}
    		return user;
    	}
    

    可能这里还看不出来对于页面缓存,URL缓存和对象缓存的具体区别,区别在于对象缓存的用户信息的修改。前面我们设置了页面和URL,这个时候我们同时设置了过期时间:
    在这里插入图片描述
    表示对于这些缓存的信息只能够保存一分钟(具体实现过程就不细讲了),但是我们的对象缓存是永久的这个时候若是对密码进行更改该如何操作呢?
    4. 首先根据之前的修改过的查询查询出来用户的信息。
    5. 然后对具体的密码进行定点更改。
    6. 完成之后将原来保存的key值进行删除,因为用户的密码已经更改成功。
    7. 将之前保存的用户的token信息进行更新(注意不是删除,删除了token以后就无法正常登录)。

    public boolean updatePassword(String token, long id, String formPass) {
    		//取user
    		MiaoshaUser user = getById(id);
    		if(user == null) {
    			throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
    		}
    		//更新数据库
    		MiaoshaUser toBeUpdate = new MiaoshaUser();
    		toBeUpdate.setId(id);
    		toBeUpdate.setPassword(MD5Util.formPassToDBPass(formPass, user.getSalt()));
    		miaoshaUserDao.update(toBeUpdate);
    		//处理缓存
    		redisService.delete(MiaoshaUserKey.getById, ""+id);
    		user.setPassword(toBeUpdate.getPassword());
    		redisService.set(MiaoshaUserKey.token, token, user);
    		return true;
    	}
    

    页面静态化

    前面讲述的都是一些关于缓存的信息下面部分来具体讲述关于静态化的处理。
    更为激进的一种缓存的方式,就是直接把一些页面数据下载到本地的浏览器上,在访问时候直接访问本地数据,而不需要去和服务器进行交互。对于这部分的操作我们就以goods_detail页面为例,对于之前的页面布局是这样的:

    <html xmlns:th="http://www.thymeleaf.org">
    <!-- 可以看到的是引用了模板信息有引用到thymeleaf 模板解析等,
    并且下方的引用都是th:src="@{};类型表示使用到的是thymeleaf的解析,我们要实现页面的静态化就需要将这些模板的解析都给拿掉-->
    <head>
        <title>商品详情</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <!-- jquery -->
        <script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
        <!-- bootstrap -->
        <link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.min.css}" />
        <script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.min.js}"></script>
        <!-- jquery-validator -->
        <script type="text/javascript" th:src="@{/jquery-validation/jquery.validate.min.js}"></script>
        <script type="text/javascript" th:src="@{/jquery-validation/localization/messages_zh.min.js}"></script>
        <!-- layer -->
        <script type="text/javascript" th:src="@{/layer/layer.js}"></script>
        <!-- md5.js -->
        <script type="text/javascript" th:src="@{/js/md5.min.js}"></script>
        <!-- common.js -->
        <script type="text/javascript" th:src="@{/js/common.js}"></script>
    </head>
    

    对于页面静态化来说,这些模板解析都需要去掉,使其访问路径为直接的绝对路径。如下代码所示,这样一来就可以将相对的信息读取到本地浏览器缓存中,而不是每次的请求都需要再访问到服务器端进行页面的渲染。

    <html >
    <head>
        <title>商品详情</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <!-- jquery -->
        <script type="text/javascript" src="/js/jquery.min.js"></script>
        <!-- bootstrap -->
        <link rel="stylesheet" type="text/css" href="/bootstrap/css/bootstrap.min.css" />
        <script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
        <!-- jquery-validator -->
        <script type="text/javascript" src="/jquery-validation/jquery.validate.min.js"></script>
        <script type="text/javascript" src="/jquery-validation/localization/messages_zh.min.js"></script>
        <!-- layer -->
        <script type="text/javascript" src="/layer/layer.js"></script>
        <!-- md5.js -->
        <script type="text/javascript" src="/js/md5.min.js"></script>
        <!-- common.js -->
        <script type="text/javascript" src="/js/common.js"></script>
    </head>
    

    当然以上只是界面的引用信息,对于基础的html代码我们也来看一看一些细微的变化,就举个立即秒杀的栗子:对于版本5之前都是这样的提交方式,这样在我们点击立即秒杀时候需要提交表单到服务端,这个时候我们就需要进行一些变化,让button按钮绑定到对应的函数实现ajax请求,只请求部分的信息。

    <form id="miaoshaForm" method="post" action="/miaosha/do_miaosha">
       <!-- 定义一个form表达,提交到如上的地址-->
            		<button class="btn btn-primary btn-block" type="submit" id="buyButton">立即秒杀</button>
            		<input type="hidden" name="goodsId" th:value="${goods.id}" />
            	</form>
    

    对于静态化之后的立即秒杀就是一个简单的button按钮具体如下:

       <!-- 使用ajax方式做请求处理 -->
    <button class="btn btn-primary btn-block" type="button" id="buyButton"οnclick="doMiaosha()">立即秒杀</button>
      <input type="hidden" name="goodsId"  id="goodsId" />
    

    下面我们来看一下对应的doMiaosha()函数:

    // 使用ajax方式来进行局部信息的提交。
    function doMiaosha(){
    	$.ajax({
    		url:"/miaosha/do_miaosha",
    		type:"POST",
    		data:{
    			goodsId:$("#goodsId").val(),
    		},
    		success:function(data){
    			if(data.code == 0){
    				window.location.href="/order_detail.htm?orderId="+data.data.id;
    			}else{
    				layer.msg(data.msg);
    			}
    		},
    		error:function(){
    			layer.msg("客户端请求有误");
    		}
    	});
    }
    

    将一些页面需要的主要信息都不再请求数据库,而是使用参数对象的方式将具体的信息映射到前端的页面上,实现页面的静态化。不只是对于商品详情页,对于秒杀商品页或是订单详情页都有对应的静态化操作,大家将源码下载下来以后可以进行具体的查看,调试等。这里就不再进行一一的详细解释。
    在这里插入图片描述

    后记

    (对于sql部分参见秒杀页面设计中sql语句)
    对于页面优化技术这里主要讲诉了三种不同粒度的缓存和页面静态化的处理,涉及的业务代码这里没有进行具体的讲解,讲解的也都是思想,想要效仿学习大家可以自行下载代码进行调试处置。源码部分不是很难,有些地方也都有具体的注释。个人的理解也是有限,所以有些地方没有讲到或是讲错的地方还希望大家能够指证出来,大家一起学习,后续还会持续对这篇文章进行一个更正与添加,也算是激励自己持续学习。
    源码参见Github中有全部的部分,对于这部分对应的是miaosha_5可以与最近的miaosha_4进行一个对比与记录。

    展开全文
  • 常见的页面优化技术页面的优化技术分为:缓存和,页面静态化,静态资源优化,CDN优化等其中缓存分为: 页面缓存+url缓存+对象缓存页面缓存也没缓存的时间比较短的。比如10秒钟的缓存时间失效思路: 获取页面缓存,...

    常见的页面优化技术

    页面的优化技术分为:缓存和,页面静态化,静态资源优化,CDN优化等

    其中缓存分为: 页面缓存+url缓存+对象缓存


    页面缓存

    也没缓存的时间比较短的。比如10秒钟的缓存时间失效

    思路: 获取页面缓存,没有的时候重新获取页面然后进行渲染,然后返回

    使用  Thymeleaf 的话,Springboot中有ThymeleafViewResolver可以帮助我们获取到页面的模板

    ThymeleafViewResolver

    这个方法可以得到一个模板的引擎,这个类的父类  TemplateEngine,其中的process方法是关键



    其中的IContext这个类的参数,可以通过  SpringWebContext

    SpringWebContext

    SpringWebContext ctx = new SpringWebContext(request,response,
        request.getServletContext(),request.getLocale(), model.asMap(), applicationContext );


    渲染模板

    html = thymeleafViewResolver.getTemplateEngine().process("goods_list", ctx);


    Controller方法上加入produces="text/html"

    重新我们之前的GoosController的商品列表

    此时这个Controller方法返回的是一个页面,因此需要  @ResponseBody进行标记

    /**
    	 * 使用页面缓存技术
    	 * @param model
    	 * @param user
    	 * @return
    	 * @throws Exception 
    	 */
    	@RequestMapping(value="/toListCache", produces="text/html")
    	@ResponseBody
    	public String toListWithPageCache(HttpServletRequest request, HttpServletResponse response,Model model , User user) throws Exception {
    		if(user == null) {
    			return "login";
    		}
    		model.addAttribute("user", user);
    		//获取页面缓存
    		RedisServiceProxy proxy = new RedisServiceProxy(GoodsKey.GOODS_LIST,redisService);
    		String html = proxy.getBean("", String.class);
        	if(!StringUtils.isEmpty(html)) {
        		return html;
        	}
    		//查询商品信息
    		List<GoodsVo> goodsList = goodsService.listGoods();
        	model.addAttribute("goodsList", goodsList);
        	//页面缓存的核心东西,渲染页面
        	SpringWebContext ctx = new SpringWebContext(request,response,
        			request.getServletContext(),request.getLocale(), model.asMap(), applicationContext );
        	//手动渲染
        	html = thymeleafViewResolver.getTemplateEngine().process("goods_list", ctx);
        	if(!StringUtils.isEmpty(html)) {
        		proxy.setBean("", html);
        	}
        	
    		return html;
    		
    	}





    查看redis




    注意点

    页面的缓存呢其实呢是user不一样而已,其他的对大部分用户来说是一样的。

    但是呢如果是一个详情页面,那么就有问题了。

    因此这也就是url缓存的概念了

    也就是将用户在url中的参数作为页面缓存key的一部分。

    这样不同的用户看到的详情页是不一样的


    Url缓存

    这个是对页面缓存的进一步利用,参数作为key的一部分。

    比如我们的商品详情页面,url中有一个参数  商品id

    /**
    	 * 使用缓存的例子
    	 * @param model
    	 * @param user
    	 * @param goodsId
    	 * @return
    	 * @throws Exception 
    	 */
    	@RequestMapping(value="/to_detailCache/{goodsId}",produces="text/html")
        @ResponseBody
    	public String detailWithCache(HttpServletRequest request, HttpServletResponse response, Model model,User user,
        		@PathVariable("goodsId")Long goodsId) throws Exception {
    		
    		model.addAttribute("user", user);
    		//获取页面缓存
    		RedisServiceProxy proxy = new RedisServiceProxy(GoodsKey.GOODS_DETAIL,redisService);
    		String html = proxy.getBean(""+goodsId, String.class);
        	if(!StringUtils.isEmpty(html)) {
        		return html;
        	}
        	
    		GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
        	model.addAttribute("goods", goods);
        	
        	
        	long startAt = goods.getStartDate().getTime();
        	long endAt = goods.getEndDate().getTime();
        	long now = System.currentTimeMillis();
        	
        	int miaoshaStatus = 0;
        	int remainSeconds = 0;
        	if(now < startAt ) {//秒杀还没开始,倒计时
        		miaoshaStatus = 0;
        		//单位是毫秒
        		remainSeconds = (int)((startAt - now )/1000);
        	}else  if(now > endAt){//秒杀已经结束
        		miaoshaStatus = 2;
        		remainSeconds = -1;
        	}else {//秒杀进行中
        		miaoshaStatus = 1;
        		remainSeconds = 0;
        	}
        	model.addAttribute("miaoshaStatus", miaoshaStatus);
        	model.addAttribute("remainSeconds", remainSeconds);
        	SpringWebContext ctx = new SpringWebContext(request,response,
        			request.getServletContext(),request.getLocale(), model.asMap(), applicationContext );
        	html = thymeleafViewResolver.getTemplateEngine().process("goods_detail", ctx);
        	
        	if(!StringUtils.isEmpty(html)) {
        		proxy.setBean(""+goodsId, html);
        	}
        	
    		return html;
    	}



    对象缓存

    将对象化成json然后存入到redis中再从redis中获取到就是对象缓存。

    缓存中没有的时候才会查询数据库.

    之前的User对象的获取就是这种形式的

    更新注意缓存的更新

    因此对于页面上的一些表示对象可以进行缓存。

    但是呢如果遇到了更新的话,我们更新完数据库之后,要处理缓存的。

    先更新数据库,然后更新缓存,保证缓存的一致性。

    注意一定要更新数据库,之后再进行缓存的更新。

    因为如果调用顺序之后呢,就会先加载缓存,然后更新,数据库的数据被更新了,是最新的,造成了数据不一致

    注意了调用呢,一定要调用Service

    service中可能是使用了缓存的,直接使用dao就可能造成这个缓存的不一致。


    缓存的目的

    减少对数据库的访问。

    基本上保证在60秒内可以不访问 mysql数据库,直接从redis中获取的。

    这样系统的负载就只体现在 java 和redis进程上面。

    消灭掉mysql的负载




    展开全文
  • 前端页面优化技巧

    千次阅读 2017-03-27 13:47:21
    前端页面优化;网站加载速度提升技巧;增加用户体验度的实用小技巧;
    1、首先说说浏览器的加载流程:

    (1) 用户在地址栏中打开一个URL,浏览器首先会寻找该URL所在服务器,通过DNS服务器查询浏览器会获

    得该URL所在网站的IP地址,然后向该地址发起请求,连接到服务器;


       (2) 建立连接后,向服务器发送http请求,请求对应的HTML文档;


       (3) 解析HTML文档,目的是知道该页面需要哪些资源以及生成DOM树;生成DOM树和获取到相应需要的

    资源文件同时进行;解析HTML文档时,一旦发现一个标签,就会根据标签的要求分配对指定的资源进行下载,当DOM树生成后,DOMContentLoaded事件被触发;

               理论上浏览器并行下载页面所需要的资源会带来更好的性能体验!


      (4) Onload事件,当解析完成后,生成了DOM树,所有页面需要的资源文件都已经成功下载和执行后,

    浏览器会发出Onload事件并回调HTML文档中的onload函数。


    2、对于优化页面速度的必要性:

    页面的打开速度对于网站的优化有极大的意义,如果打开一个页面长时间处于白屏状态,如果超过5s,暴脾气

    的我是会直接关闭这个网页;或者是页面加载出来了,但是比较慢,页面显示不完整,标签一直在转圈,页面处于不

    可交互状态,这也是一种很不好的体验;


    一个页面的打开速度快不快,可以用两个指标来描述,一个是ready时间,一个是load时间,chrome控制台可以看到;


    一共是加载了19.2KB,ready时间是133ms,load时间是147ms;


    3、分点介绍优化策略:

    (1) 避免head标签js堵塞:

    所有放在head标签里面的js和css都会堵塞渲染;如果这些css和js需要加载很久的话,那么页面就空白了;

    [html]  view plain  copy
    1. <head>  
    2.     <title>test</title>  
    3.     <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>  
    4. </head>  


    用google的cdn加载一个jQuery文件是访问不了的,所以标签一直在转圈,页面没有任何显示;


    有两种解决办法,第一种是把script放到body后面,这也是很多网站采取的方法。第二种是给script加defer或者async的属性,一旦script是defer或者async延迟的,那么这个script将会异步加载,但不会马上执行,会在readystatechange变为Interactive后按顺序依次执行;


    两者相同点:

    • 加载文件时不阻塞页面渲染
    • 对于inline的script无效
    • 使用这两个属性的脚本中不能调用document.write方法
    • 有脚本的onload的事件回调

    两者不同点:

    • async下,js一旦下载好了就会执行,所以很有可能不是按照原本的顺序来执行的。如果js前后有依赖性,用async,就很有可能出错。
    • 如果一个script加了defer属性,即使放在head里面,它也会在html页面解析完毕之后再去执行,也就是类似于把这个script放在了页面底部。


    (2) 减少head里面的css资源:

    css必须放在head标签里面,如果放在body里面会造成对layout好的dom进行重排造成页面闪烁;但是一旦

    放在head标签里面又会堵塞页面渲染;所以要尽可能的减小css体积;


    例:不要放太多base64在css里面,webpack构建工具常常会配置图片体积小于多少的直接转换成base64加载,这

    里是挺影响性能的,一个是不能用到缓存机制,另一个就是加大了css的体积;个人建议上线项目直接把图片用cdn托

    管;


    (3)延迟加载图片:

    对于很多网站来说,图片汪汪是占用最多流量和带宽的资源;

    [html]  view plain  copy
    1. <span style="font-size:18px;"><body>  
    2.     <img id="imgTest" src="about:blank" data-src="1.gif" />  
    3. </body>  
    4. <script type="text/javascript">  
    5. window.onload = function(){  
    6.     $("#imgTest").attr("src",$("#imgTest").data("src"));  
    7. }  
    8.   
    9. </script></span>  

    这里没有直接给src路径,而是在页面加载完成后用js操作src,减少了页面加载图片的时间,首先把整个页面结构呈现给用户;惰性加载图片也是差不多;当用户滑动页面到一定高度时(监听scroll事件),再动态的依次对图片进行处理;


    (4) 压缩和缓存:

    压缩就不说了;缓存会在后续文章中具体写一个demo,持续更新;


    (5) DNS解析优化:

    DNS查询需要花费大量时间来返回一个主机名的IP地址;

    在我们的网站中,可能会加载到很多个域的东西,比如引入了百度地图啊之类的sdk和一些自己的子域名服务;第一次打开网站时要做很多次DNS查找;DNS预读取能够加快网页打开时间;

    [html]  view plain  copy
    1. <link rel="dns-prefection" href="https://www.baidu.com">  
    在head中写上几个link标签,对标签中的地址提前解析DNS,这个解析是并行发生的,不会堵塞页面渲染;


    还有非常多的页面优化技巧,html别嵌套太多层,加重页面layout的压力;css选择器的合理运用,减少匹配的计算量;js中别滥用闭包,会加深作用域链,增加变量查找时间;减少http请求之类的等等;

    展开全文
  • 网站优化---页面静态化技术

    千次阅读 2018-03-14 21:07:49
    页面静态化技术

    一:

    首先先区分一下动态页面和静态页面的区别

    动态文件:PHP脚本、Java脚本等

    动态文件的执行过程:词法、语法分析 -> 编译 -> 渲染输出

    静态文件:HTML文件

    从加载速度上可以看出,静态文件明显比动态文件速度快

    二:静态文件的分类

    真静态:真正的静态文件(访问时候的地址是动态地址,但实际上是静态文件),目的是为了减轻数据库服务器的压力,提高访问速度

    伪静态:不是真正的静态文件,(但是访问的时候的网址是静态网址,但实际访问的是动态文件),目的是为了SEO推广,方便百度搜索引擎进行搜索,

    三:实现方法

    真静态:OB缓冲技术;模板替换术

    伪静态:使用PHP脚本进行实现;通过web进行配置实现

    四:实现方法及原理

    OB缓存

     1实现原理

      PHP执行过程中,存在一个缓冲区output_buffering

      oboutput_buffering(输出缓存),用于缓存响应主体的数据内容。

    第一种方式:在php.ini文件中,

    第二种方式:在页面中使用ob_start()函数,来开启。

    两种方式的区别是,ob_start()只在当前页面有效,推荐第二种方式来完成。

    常用函数

    ob_start( );开启

    ob_get_contents();获取ob缓存里面的数据内容。

    ob_clean();//清空ob缓存里面的数据,不关闭ob缓存。

    ob_end_clean();//清空ob缓存里面的数据,并关闭ob缓存。

    ob_flush();//ob缓存里面的数据给刷新(移动,推送)到程序缓存,不关闭ob缓存。

    ob_end_flush();//ob缓存里面的数据给刷新(移动,推送)到程序缓存,并关闭ob缓存。

    3、实现页面静态化的三种方式

      ①访问时生成静态文件(不推荐)

         控制好静态文件的更新时间

      ②在后台手动生成静态文件

         后台手动更新

      ③使用定时任务定期生成静态文件(推荐使用)

    最佳做法:②③的结合体,先后台手动生成一次静态文件,然后定时更新,如果在更新的时间内,定时脚本没有运行,就手动清除缓存(删除缓存文件)


    模板替换技术

    1、实现方式:

    1)在添加新闻内容的时候,生成对应的新闻详情的静态页面。

    2)在修改新闻内容的时候,要重新生成新闻详情的静态页面。

    3)在访问新闻详情页面的时候,直接访问生成的静态页面

    真静态的应用场景

    1)网站页面访问比较频繁的,但是更新不是很频繁,比如一些新闻类型的网站详情页及网站的首页

    2)不适合于要求实时更新的一些网站,比如股票及银行类型的网站

    3)一般来说后台不用做真静态


    伪静态

    先来看一个网址:

    http://jingyan.baidu.com/article/90bc8fc804f4faf652640c6c.html  

    从形式上看是一个静态地址,实际上还是访问的动态地址,

    比如:访问:http://www.abc.com/news-sport-id123.html

    实际上是:http://www.abc.com/news.php?type=sprot&id=123;

    作用:主要是利于seo推广,静态页面的方式,比较容易被搜索引擎给搜集


    第一种:apache的重写机制

    实现原理:

    使用apache/nginxrewrite机制(就是一个url的重写机制

    在apache/conf/httpd.conf开启(开启重写模块

    配置方式:直接在配置虚拟主机处进行配置 ,每次修改apache的文件都需要重启apache

    在配置虚拟机时给对应的域名开启重写机制

    权限控制   先拒绝后允许

    在需要重写机制的文件夹的下面新建文件    .htaccess   并在.htaccess中写入重写规则

    比如:

    重启apache

    CI框架中的重写规则

    第一步:在虚拟主机开启  AllowOverride All

    第二步: //配置伪静态时 在CI框架的配置文件config中 修改URL协议为

    $config['uri_protocol']= 'PATH_INFO';


    nginx的重写机制

    2.在需要重写机制的文件夹写新建   .htaccess  文件  并在文件中写入相应的规则

    比如:

    3.在ngniz的配置文件ngnix.conf  或者 引入的.conf文件中引入重写规则的文件<文件放在server内location外>


    4.重启nginx  .php-fpm

    伪静态的使用遵循原则

    主要是为了搜索引擎的收集

    只要url不要过长,过多的参数,同时不要让蜘蛛陷入链接黑洞,现在的搜索引擎技术对待动态链接和静态链接基本没有区别。因此,如果不方便动态链接静态化的站长朋友,也没必要将太多精力花在这方面。另外,伪静态是通过服务器配置将动态映射成静态页面,多了一个映射步骤,伪静态处理更加占用服务器cpu资源。

    如何选择真静态和伪静态?

    网站实时性要求高,不要使用静态化(真静态,伪静态均不适宜)。

    如果网站访问量较小,没有必要使用静态化技术(网站后台)

    如果数据项目文件不多,但是访问频率极大,建议使用真静态,比如新浪新闻频道。

    如果数据项目海量(论坛),使用真静态会生成海量的html静态页面,建议使用伪静态。

    在一个大型网站中,静态化技术是综合使用的,这个需要大家经验的积累,多做项目。(

    网站:新闻频道,真静态,基金频道:伪静态,管理后台:不使用静态技术)

    后台:  管理控制前台生成真静态或者更新静态页面


    展开全文
  • 前端页面优化

    千次阅读 2019-04-15 20:04:10
    1. 从用户角度而言,优化能够让页面加载得更快、对用户的操作响应得更及时,能够给用户提供更为友好的体验。 2. 从服务商角度而言,优化能够减少页面请求数、或者减小请求所占带宽,能够节省可观的资源。 总之,...
  • 页面性能优化的方法

    千次阅读 2018-11-19 06:57:11
    引子 互联网有一项著名的8秒原则。用户在访问Web网页时,如果时间超过8秒就会感到不耐烦...那我们如何优化页面性能,提高页面加载速度呢?这是本文主要要探讨的问题,然而性能优化是个综合性问题,没有标准答案,想...
  • (当然技术大牛除外) 通过查阅相关资料,了解到了一些关于web性能优化的点,其中涉及的知识大致可以分为几类:度量标准、编码优化、静态资源优化、交付优化、构建优化、性能监控。 在详细介绍上边内容之前先来介绍...
  • 一个网站如果没有内容,谈再多的SEO优化技术都是空谈。网站内容可以是文字、图片或者是视频,但是我们知道,搜索引擎是比较喜欢图文结合的内容,所以,讯阅网xuuyue.com在这里建议大家在做网站内容的时候,尽量做...
  • 《目录》 ----------&gt;缓存的需要,缓存的原理 ----------&gt;页面缓存的思路 ----------&...热点数据缓存的思路,4个点 ...由于后端跳转页面转向ajax技术请求参数的页面静态化技术与思路,这一...
  • 浅谈移动端页面性能优化方案

    千次阅读 2019-06-11 12:04:29
    这就要求我们产品质量越来越高,那对于我们前端工程师来说也是一个挑战,如何让我们所开发的页面能有更好的体验,就是我们今天讨论的话题:移动端页面性能优化。 Html5的出现对于移动端影响挺大,HTML5框架可以提升...
  • 从构建、浏览器渲染、缓存、PWA、服务端优化等多方面,梳理前端性能优化技术点、综合分析技术的原理,根据不同的业务场景选择合适的性能优化点进行应用,最终为你的网站带来显著的速度提升和整体性能提升。
  • 页面性能优化的五种办法

    千次阅读 2019-06-05 16:27:04
    以下是我总结性能优化常见的办法: 一、资源压缩与合并 主要包括这些方面:html 压缩、css 压缩、js 的压缩和混乱和文件合并。 资源压缩可以从文件中去掉多余的字符,比如回车、空格。 1.html 压缩 html代码压缩...
  • 如何优化html页面

    千次阅读 2018-09-26 15:26:05
    1. 把js文件 放到html页面最后去执行 2. 可以将html页面,以及加载的其他内容压缩和混淆 3. 压缩图片(png,jpeg,gif) png: 无损压缩的图片格式 带透明通道 (小图) jpeg ...图片背景 (spring 技术) 图片精灵 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 255,721
精华内容 102,288
关键字:

页面优化技术