擊右上角【關注】發哥微課堂頭條號,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小時內與您取得聯系。