击右上角【关注】发哥微课堂头条号,get更多相关技能~
0x00:示例项目
以一个项目示例总结下 SpringMVC 环境的搭建基本流程,项目结构如下图:
0x01:导入 jar 包
SpringMVC 主要 jar 包如下图,需导入到 WEB-INF 下的 lib 目录。
0x02:配置前端控制器
传统的 servlet 开发中,请求都在 web.xml 中配置,然后配置到对应的 servlet 中。同样,在 SpringMVC 中,请求也需要配置到对应的 servlet 上,而做配置的就是前端控制器,用于拦截符合配置的 url 请求。在 SpringMVC 中,正是通过前端控制器 DispatcherServlet 来对请求进行拦截并处理的。配置 web.xml,示例代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- SpringMVC前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
配置和 servlet 类似,以上配置会拦截所有以 action 为后缀的请求,交给前端控制器 DispatcherServlet 去处理,定义了 SpringMVC 的核心配置文件为 springmvc.xml。
0x03:配置处理器映射器
在 springmvc.xml 配置文件中添加处理器映射器,示例代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
</beans>
处理器映射器有多种,它们都实现了 HandlerMapping 接口,示例代码中用的是 BeanNameUrlHandlerMapping 类,映射规则是把 bean 的 name 作为 url 进行查找。
0x04:配置处理器适配器
由之前的 SpringMVC 工作流程可知,当处理器映射器 HandlerMapping 为前端控制器 DispatcherServlet 返回控制器 Handler 后,前端控制器就会给处理器适配器 HandlerAdapter 去执行相关的 Handler 控制器也就是 Controller。
处理器适配器也有多种,它们都实现了 HandlerAdapter 接口,这里使用 SimplerControllerHandlerAdapter 适配器,在 springmvc.xml 中添加以下代码:
<!-- 处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
0x05:配置视图解析器
当处理器适配器处理了相关的具体方法后,就会返回一个 ModelAndView 对象,这个对象包含了要跳转的视图信息 view 和视图上需要显示的数据 model,此时前端控制器会请求视图解析器 ViewResolver 来解析 ModelAndView 对象。
视图解析器也有很多种,这里使用默认的 InternalResourceViewResolver,在 springmvc.xml 中添加以下代码:
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
基本配置完成后,既需要配置处理器 Handler 了。
0x06:配置 Handler 处理器
因为上文处理器适配器使用的是 SimpleControllerHandlerAdapter,所以这里的 Handler 需要实现 Controller 接口。编写一个加载水果列表信息的功能,名为 FruitsControllerTest,示例代码如下:
package com.fageweiketang.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import com.fageweiketang.model.Fruits;
public class FruitsControllerTest implements Controller {
private FruitsService fruitsService = new FruitsService();
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {
//模拟Service获取水果商品列表
List<Fruits> fruitsList = fruitsService.queryFruitsList();
//返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
//相当于request的setAttribut,在jsp页面通过fruitsList获取数据
modelAndView.addObject("fruitsList", fruitsList);
//指定视图
modelAndView.setViewName("/WEB-INF/jsp/fruits/fruitsList.jsp");
return modelAndView;
}
//模拟Service的内部类
class FruitsService{
public List<Fruits> queryFruitsList(){
List<Fruits> fruitsList = new ArrayList<Fruits>();
Fruits apple = new Fruits();
apple.setName("苹果");
Fruits banana = new Fruits();
apple.setName("香蕉");
Fruits pear = new Fruits();
apple.setName("梨");
fruitsList.add(apple);
fruitsList.add(banana);
fruitsList.add(pear);
return fruitsList;
}
}
}
示例中查询到列表信息后创建了一个 ModelAndView,将需要传递的数据通过 ModelAndView 绑定到了对象中。又通过 setViewName 方法指定了要跳转的页面。
0x07:编写实体类代码
实体类很简单,一个 get 和 set 方法即可,示例代码如下:
package com.fageweiketang.model;
public class Fruits {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
0x08:编写视图页面
最后在 / WEB-INF/jsp/fruits 路径下创建 fruitsList.jsp 文件即可,示例代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>水果列表</title>
</head>
<body>
<h3>水果列表</h3>
<table width="300px;" border=1>
<c:forEach items="${fruitsList }" var="fruit">
<tr>
<td>${fruit.name }</td>
</tr>
</c:forEach>
</table>
</body>
</html>
因为 springmvc.xml 中配置的处理器映射器是 BeanNameUrlHandlerMapping,在接收请求时,会将 bean 的 name 作为 url 进行查找,所以最后需要在 springmvc.xml 中配置一个可以被 url 映射的 Handler 的 bean,配置示例如下:
<bean name="/queryFruits.action" class="com.fageweiketang.controller.FruitsControllerTest"/>
启动 tomcat 服务器,访问 localhost/SpringMVC/queryFruits.action,结果如下:
“爱读书”--给你讲技术》,我来看书,你来进步,让我们开始吧!
书名为《Spring+MyBatis企业应用实战》,是本人在学习JavaEE框架时候的一本基础书籍,本书对于SpringMVC和MyBatis框架及相关基础知识讲述的比较清晰,适合需要详细学习Java框架的读者。
本文内容为本书第二章--第八章,记录和总结了所有SpringMVC的知识
1.DispatcherServlet使用和配置
SpringMVC提供了一个名为org.springframework.web.servlet.DispatcherServlet的Servlet充当前端控制器,所有请求驱动都围绕这个DispatcherServlet来分配请求。DispatcherServlet是一个Servlet类,需要在web.xml中完成配置。
(1)配置了启动时立即加载Servlet
(2)需要配置springmvc-config.xml配置文件
(3)配置了用当前servlet处理所有请求URL
2.DispatcherServlet的分发原理
先看一下DispatcherServlet源码中的方法
源码如下:
initStrategies方法将在WebApplicationContext初始化后自动执行,自动扫描上下文的Bean,根据名称或类型匹配机制查找自定义的组件。如果没有找到则会装配一套默认组件,默认组件在DispatcherServlet.properties配置文件中。
配置文件如下:
如 果开发者希望使用自定义类型的组件,则只需要在Spring配置文件中配置自定义的Bean即可。MVC如果发现上下文中有用户自定义的组件,就不会使用默认组件。
1.在web.xml中定义前端控制器DispatcherServlet来拦截用户请求
2.定义处理用户请求的Handle类,可以实现Controller接口或使用@Controller注解
3.配置Handle,可采用xml文件或注解的方式
<!-- 配置Handle,映射/hello请求 -->
<bean name="/hello" class="org.fkit.controller.HelloController"/>
@Controller
public class HelloController{
@RequestMapping(value="/hello")
public ModelAndView hello(){
}
}
4.编写视图资源,Handle处理用户请求结束后,通常会返回一个ModelAndView对象,该对象包含返回的试图名和模型。试图名代表需要显示的物理视图资源;模型用于传输数据给视图资源。
说明如下:
(1)用户向服务器发送请求,请求被Spring的前端控制器DispatcherServlet截获
(2)DispatcherServlet对请求URL进行解析,得到URI。然后根据URI,调用HandlerMapping获得该Handler配置的所有相关对象,包括Handler对象以及Handler对象对应的拦截器,会被封装到一个HandlerExecutionChain对象中返回
(3)DispatcherServlet根据获得的Handler,选择一个HandlerAdapter。HandlerAdapter会被用于处理多种Handler,调用Handler实际处理请求的方法
(4)提取请求中的模型数据,开始执行Handler。在填充Handler的入参过程中,根据配置spring会帮你实现消息转换、数据转换、数据格式化、数据验证
(5)Handler执行完成后,向DispatcherServlet返回一个ModelAndView对象。ModelAndView对象中包含试图名和模型
(6)根据返回的ModelAndView对象,选择一个ViewResolver返回给DispatcherServlet
(7)ViewResolver结合Model和View来渲染视图
(8)将试图渲染结果返回给客户端
1.@Controller注解
@Controller用于标记一个类,使用它标记的类就是一个Controller对象,及一个控制器。Spring使用扫描机制查找应用中所有基于注解的控制器类。
@Controller
public class HelloController{
@RequestMapping(value="/hello")
public ModelAndView hello(){
}
}
使用注解前需要如下步骤:
<context:component-scan base-package="org.fkit.controller"/>
springmvc-config.xml常用配置
说明如下:
(1)使用<context:component-scan>指定需要扫描的包
(2)<mvc:annotation-driven>会自动注册RequestMappingHandlerMapping和Request MappingHandlerAdapter两个Bean,提供注解的必要支持
(3)<mvc:default-servlet-handler>是静态资源处理器,SpringMVC会默认捕获所有请求,包括静态资源请求。配置了当前元素后静态资源不会被DispatcherServlet处理
(4)视图解析器InternalResourceViewResolver来解析视图,将View呈现给用户。配置的prefix属性表示视图的前缀,suffix表示视图的后缀。
2.@RequestMapping注解
@RequestMapping注解可以用来注释一个控制器类,所有方法都将映射为相对于类级别的请求,表示该控制器处理的所有请求都被映射到value属性所指示的路径下。
上图代表映射到如下路径:
http://localhost:8080/user/register
http://localhost:8080/user/login
常用属性如下:
3.请求处理方法可出现的参数类型
所有参数Spring会自动将值传给方法
(1)HttpServletRequest参数
(2)HttpSession参数
(3)HttpServletResponse
(4)InputStream
(5)OutputStream
(6)Map
(7)Model
(8)ModelMap
(9)BindingResult
(10)WebRequest
4.请求处理方法可返回的类型
下面做一些详细说明。
(1)Model和ModelMap
SpringMVC在调用处理方法之前会创建一个隐含的模型对象,作为模型数据的存储容器。如果处理方法的参数为Model或ModelMap类型,则SpringMVC会将隐含模型的引用传递给这些参数。在处理方法内部,开发者可以通过这个参数对象访问模型中的所有数据,也可以向模型中添加新的数据。
(2)ModelAndView
控制器处理方法的返回值如果是ModelAndView,则既包含模型数据,也包含视图信息。
常用方法如下:
//添加模型数据
addObject(String key, Object value);
//设置视图
setViewName(String name);
5.页面转发
(1)转发到JSP
//默认forward跳转
return "main";
modelAndView.setViewName("main");
//重定向页面
return "redirect:/main.jsp";
modelAndView.setViewName("redirect:/main.jsp");
(2)转发到其他处理方法
//forward跳转
return "forward:/main";
modelAndView.setViewName("forward:/main");
//重定向
return "redirect:/main";
modelAndView.setViewName("redirect:/main");
6.@RequestParam注解
@RequestParam用于将指定的请求参数赋值给方法中的形参。属性如下:
name:指定请求参数绑定的名称
value:name属性的别名
required:指定参数是否必须绑定
defaultValue:指定默认值
7.@PathVariable注解
@PathVariable可以方便的获得请求URL中的动态参数。属性如下:
举例如下:
@RequestMapping(value="/pathVariableTest/{userId}")
public void pathVariableTest(@PathVariable Integer userId)
假如请求的URL为http://localhost:8080/pathVariableTest/1,则自动将URL中模板变量{userId}绑定到通过@PathVariable注解的同名参数上,即userId变量将被赋值为1。
8.@RequestHeader注解
@RequestHeader注解用于将请求头信息数据映射到功能处理方法的参数上。属性如下:
举例如下:
9.@CookieValue注解
@CookieValue注解用于将请求的Cookie数据映射到功能处理方法的参数上。属性如下:
举例如下:
10.@RequestAttribute注解
@RequestAttribute注解用于访问由请求处理方法、过滤器或拦截器创建的、预先存在于request作用域中的属性,将该属性转换到目标方法的参数。属性如下:
举例如下:
11.@SessionAttribute注解
@SessionAttribute注解用于访问由请求处理方法、过滤器或拦截器创建的、预先存在于session作用域中的属性,将该属性转换到目标方法的参数。属性如下:
举例如下:
12.@ModelAttribute注解
@ModelAttribute注解用于将请求参数绑定到对象。
举例如下:
Form请求的参数值会自动入参到@ModelAttribute注解的对象的同名属性中
13.@RequestBody注解
@RequestBody注解用来处理content-type类型为:application/json或application/xml的情况,将请求数据绑定到方法参数上。
举例如下:
其中前台向处理方法传递了Json格式的数据,Json数据的key和Book属性相对应
14.@ResponseBody注解
@ResponseBody注解用于将请求处理方法返回的对象,转换为指定格式后,写入到Response对象的body中。返回的数据不是HTML页面,而是其他格式数据,如JSON、XML时使用注解。
举例如下:
上图将List转换为Json格式输出
15.@RestController注解
@RestController注解相当于同时使用了@Controller和@ResponseBody。用于RESTFUL风格的请求处理方式。
SpringMVC提供的两种异常处理方式:
//该方法处理程序执行期间被抛出的异常,返回一个模型和视图,视图返回错误处理页面
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response)
通过springmvc-config.xml配置实现
<!-- p:defaultErrorView="error"表示所有没有指定的异常都跳转到异常处理页面error
p:exceptionAttribute="ex"表示异常处理页面中访问的异常对象变量名为ex -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
p:defaultErrorView="error" p:exceptionAttribute="ex">
<!-- exceptionMappings表示映射的异常,接受参数是一个Properties,key是异常类名,value是处理异常的页面 -->
<property name="exceptionMappings">
<props>
<prop key="IOException">ioerror</prop>
<prop key="SQLException">sqlerror</prop>
</props>
</property>
</bean>
@ExceptionHandler注解只在当前类生效
使用<context:component-scan>扫描到@ControllerAdvice注解后,会将注解修饰的类内部使用@ExceptionHandler、@InitBinder、@ModelAttribute注解的方法应用到所有请求的异常处理上。
1.messageSource接口
SpringMVC不直接使用java.util.ResourceBundle,而是使用messageSource的Bean来配置国际化属性文件。
上图basenames指定了资源文件的名称
2.localeResolver接口
SpringMVC使用语言区域解析器来实现用户选择语言区域。提供了一个语言区域解析器接口LocaleResolver,实现类包括:
AcceptHeaderLocaleResolver是默认解析器,会读取浏览器accept-language标题,来确定使用哪个语言区域
3.message标签
SpringMVC显示本地化消息使用message标签,使用前需先导入taglib标签库。
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
message标签属性如下:
4.AcceptHeaderLocaleResolver
实现步骤:
(1)创建资源文件
message_en_US.properties
message_zh_CN.properties
(2)在JSP中使用message标签输出国际化消息
(3)在SpringMVC配置文件中加载国际化资源文件并配置
(4)可在controller中使用国际化
RequestContext requestContext = new RequestContext(request);
String username = requestContext.getMessage("username");
Spring MVC框架将ServletRequest对象及处理方法的参数对象传递给DataBinder,DataBinder调用ConversionService组件进行数据类型转换、数据格式化工作,并将ServletRequest中的消息填充到参数对象中。然后再调用Validator组件对已经绑定了请求消息数据的参数对象进行数据合法性校验,并最终生成 数据绑定结果BindingResult 对象。
实现步骤:
(1)创建表单并设置为multipart/form-data
(2)创建controller
SpringMVC会将上传文件绑定到MultipartFile对象。MultipartFile提供了获取上传文件内容、文件名等方法。
MultipartFile常用方法如下:
byte[] getBytes():获取文件数据
String getContentType():获取文件MIME类型,如image/jpeg
InputStream getInputStream():获取文件流
String getName(): 获取表单中文件组件的名称
String getOriginalFilename():获取上传文件的原名
long getSize(): 获取文件的字节大小,单位为byte
boolean isEmpty(): 是否有上传的文件
void transferTo(File file):将上传文件保存到一个目标文件中
(3)在SpringMVC配置文件中增加文件上传功能(配置MultipartResolver)
CommonsMultipartResolver必须依赖于Apach FileUpload组件,需要引入JAR包
实现步骤:
(1)在页面中加入下载超链接,链接地址指向controller方法
(2)编写controller处理方法,用于文件下载
使用Apache FileUpload组件FileUtils读取要下载的文件,并将其构建成ResponseEntity对象返回。ResponseEntity对象可以方便的定义返回的BodyBuilder、HttpHeaders、HttpStatus。
BodyBuilder对象用来构建返回的Body
HttpHeaders代表Http协议头信息
HttpStatus代表Http协议的状态
Interceptor拦截器的主要作用是拦截用户的请求并进行相应的处理(比如通过拦截器来进行用户权限验证,或者用来判断用户是否已经登录等)
1.HandlerInterceptor接口
定义拦截器类需要实现HandlerInterceptor接口或继承抽象类HandlerInterceptorAdapter
接口中的方法如下:
//该方法在请求处理之前被调用,可以做前置的初始化操作或者是对当前请求的一个预处理,也可以判断来请求是否要继续进行下去。当返回值为false,表示请求结束,后续的Interceptor和Controller不会再执行;当返回值为true泽会继续执行
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
//该方法在controller方法被执行,在视图返回渲染前被调用。可以在这个方法中对处理后的ModelAndView进行操作
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv)
//该方法将在整个请求结束后执行,作用是进行资源清理
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
实现步骤:
(1)定义拦截器类,实现接口和接口中的方法
(2)在配置文件中配置拦截器(springmvc-config.xml)
起HTML标签,前端工程师会非常的有发言权,因为在平时开发中一定会用到,可以说是前端的入门必备知识。但往往在意更多的是页面的渲染效果及交互方式,也就是页面可见的部分,比如导航栏,菜单栏,列表,图文等。
其实还有一些页面上没有呈现出来却非常重要的标签,这些标签大部分在页面的头部head标签内,虽然在页面上看不见摸不着,但如果在特定的场景下,会产生意想不到的效果。下面我将从交互优化,性能优化,搜索优化三个方面并结合场景来聊聊被“忽视”的HTML标签。
交互优化
meta 标签:自动跳转/刷新
假设要实现一个类似自动播放的页面,首先我们第一反应会想到用js定时器控制页面跳转来完成。但是其实有更加简便的方法,通过meta标签的refresh功能来实现。
<meta http-equiv="refresh" content="10; url=view2.html">
上面的代码会在 10s 之后自动跳转到同域下的 view2.html 页面。我们要实现自动播放的功能,只需要在每个页面的 meta 标签内设置好下一个页面的地址即可。
如果要实现定时刷新的功能,只要去除后面url即可:
<meta http-equiv="refresh" content="10">
注意,用meta标签实现刷新/跳转的过程是不可取消的,所以需要手动取消的还是得老老实实使用js的定时器,但是对于简单的定时刷新或跳转,还是可以去亲自实践meta的用法。
title 标签:消息提醒
消息提醒功能实现在HTML5标准发布之前,浏览器还没有开放图标闪烁、音频播放,弹出系统消息之类的api,只能借助其他非常规的手段,比如修改title 标签来达到类似的效果。
下面的代码通过定时修改title标签的内容,实现了消息提醒的功能,可以让用户在浏览其他页面时候,及时发现服务端返回的消息。
let messageNum = 1; // 消息条数
let count = 0; // 计数器
const msgInterval = setInterval(() => {
count = (count + 1) % 2;
if(messageNum === 0) {
// 通过DOM修改title
document.title += `当前页面`;
clearInterval(msgInterval);
return;
}
const pre = count % 2 ? `新消息(${msgNum})` : '';
document.title = `${pre}当前页面`;
}, 1000);
当然,动态修改title标签的用途不仅仅是消息提醒,还可以显示一些异步进行的任务,比如下载进度,上传进度等。
性能优化
script 标签:调整加载顺序提升渲染速度
不知道你们有没有过这样的体验:当在浏览器打开某个页面时,发现页面一直在loading转圈,或者等了好长的时间页面才有响应。这一现象,除了网络网速的原因外,大多数都是由于页面结构设计不合理导致加载时间过长。因此,如果想要提升页面的渲染速度,就需要了解浏览器页面的渲染过程是怎样的,从根本上来解决问题。
浏览器在加载页面的时候会用到 GUI 渲染线程和 JavaScript 引擎线程。其中,GUI 渲染线程负责渲染浏览器界面 HTML 元素,JavaScript 引擎线程主要负责处理 JavaScript 脚本程序。由于 JavaScript 在执行过程中还可能会改动界面结构和样式,因此它们之间被设计为互斥的关系。也就是说,当 JavaScript 引擎执行时,GUI 线程会被挂起,等执行完 JavaScript 的脚本程序后又会切换 GUI 线程继续渲染页面。
所以我们可以知道页面渲染过程中包含了请求脚本文件以及执行脚本文件的时间,但页面的首次渲染可能并不需要执行完全部的文件,这些请求和执行文件的动作反而延长了用户看到页面的时间,从而降低了用户体验。
为了快速将内容呈现给用户,减少用户等待时间,可以借助script标签的3个属性来实现:
async:表示立即请求脚本文件,但不阻塞 GUI 渲染引擎,而是文件加载完毕后阻塞 GUI 渲染引擎并立即执行文件内容。
defer。立即请求脚本脚本,但不阻塞 GUI 渲染引擎,等到解析完 HTML 之后再执行文件内容。
HTML5 标准 type,对应值为“module”。让浏览器按照 ECMA Script 6 标准将文件当作模块进行解析,默认阻塞效果同 defer,也可以配合 async 在请求完成后立即执行。
所以可以得知,采用defer 属性以及 type="module" 情况下能保证渲染引擎的优先执行,从而减少执行文件内容消耗的时间,让用户更快地看见页面(即使这些页面内容可能并没有完全地显示)。除此外还要知道,当渲染引擎解析 HTML 遇到 script 标签引入文件时,会立即进行一次渲染,这就是为什么会把引用JavaScript 代码的 script 标签放入到 body 标签底部。
link 标签:通过预处理提升渲染速度
在我们对中大型项目进行性能优化时,往往会对资源做减法(gzip压缩,缓存等)或除法(按需打包,按需加载),可是如果能想到 link 标签的 rel 属性值来进行预加载,也能加快页面的渲染速度。
dns-prefetch。当 link 标签的 rel 属性值为“dns-prefetch”时,浏览器会对某个域名预先进行 DNS 解析并缓存。这样,当浏览器在请求同域名资源的时候,能省去从域名查询 IP 的过程(DNS查询),从而减少时间损耗。(注意:这个属性还在实验阶段,部分浏览器的部分版本支持)
preconnect。让浏览器在一个 HTTP 请求正式发给服务器前预先执行一些操作,这包括 DNS 解析、TLS 协商、TCP 握手,通过消除往返延迟来为用户节省时间。(注意:这个属性还在实验阶段,部分浏览器的部分版本支持)
prefetch/preload。两个值都是让浏览器预先下载并缓存某个资源,但不同的是,prefetch 可能会在浏览器忙时被忽略,而 preload 则是一定会被预先下载。
prerender。浏览器不仅会加载资源,还会解析执行页面,进行预渲染。(注意:这个属性还在实验阶段,部分浏览器的部分版本支持)
搜索优化
你所写的前端代码,除了要让浏览器更好执行,有时候也要考虑更方便其他程序(如搜索引擎)理解。合理地使用 meta 标签和 link 标签,恰好能让搜索引擎更好地理解和收录我们的页面。
meta 标签:提取关键信息
通过 meta 标签可以设置页面的描述信息,从而让搜索引擎更好地展示搜索结果。
例如,在百度中搜索“淘宝”,就会发现网站的描述信息,这些描述信息就是通过 meta 标签专门为搜索引擎设置的,目的是方便用户预览搜索到的结果。
为了让搜索引擎更好地识别页面,除了描述信息description之外还可以使用关键字,这样即使页面其他地方没有包含搜索内容,也可以被搜索到(当然搜索引擎有自己的权重和算法,如果滥用关键字是会被降权的,比如 Google 引擎就会对堆砌大量相同关键词的网页进行惩罚,降低它被搜索到的权重)。
当我们搜索关键字“安全购物”的时候搜索结果会显示淘宝网的信息,虽然显示的搜索内容上并没有看到“安全购物”字样,这就是因为淘宝网页面中设置了这个关键字。
对应代码如下:
<meta content="淘宝,掏宝,网上购物,C2C,在线交易,交易市场,网上交易,交易市场,网上买,网上卖,购物网站,团购,网上贸易,安全购物,电子商务,放心买,供应,买卖信息,网店,一口价,拍卖,网上开店,网络购物,打折,免费开店,网购,频道,店铺" name="keywords">
在实际工作中,推荐使用一些关键字工具来挑选,比如
Google Trends
https://trends.google.com/trends
站长工具
https://data.chinaz.com/keyword/
link 标签:减少重复
有时候为了用户访问方便或者出于历史原因,对于同一个页面会有多个网址,又或者存在某些重定向页面,比如:
- https://baidu.com/a.html
- https://baidu.com/detail?id=abcd
那么在这些页面中可以这样设置:
<link href="https://baidu.com/a.html" rel="canonical">
这样可以让搜索引擎避免花费时间抓取重复网页。不过需要注意的是,它还有个限制条件,那就是指向的网站不允许跨域。
当然,要合并网址还有其他的方式,比如使用站点地图,或者在 HTTP 请求响应头部添加 rel="canonical"。
*请认真填写需求信息,我们会在24小时内与您取得联系。