说起HTML标签,前端工程师会非常的有发言权,因为在平时开发中一定会用到,可以说是前端的入门必备知识。但往往在意更多的是页面的渲染效果及交互方式,也就是页面可见的部分,比如导航栏,菜单栏,列表,图文等。
其实还有一些页面上没有呈现出来却非常重要的标签,这些标签大部分在页面的头部head标签内,虽然在页面上看不见摸不着,但如果在特定的场景下,会产生意想不到的效果。下面我将从交互优化,性能优化,搜索优化三个方面并结合场景来聊聊被“忽视”的HTML标签。
交互优化
meta 标签:自动跳转/刷新
假设要实现一个类似自动播放的页面,首先我们第一反应会想到用js定时器控制页面跳转来完成。但是其实有更加简便的方法,通过meta标签的refresh功能来实现。
上面的代码会在 10s 之后自动跳转到同域下的 view2.html 页面。我们要实现自动播放的功能,只需要在每个页面的 meta 标签内设置好下一个页面的地址即可。
如果要实现定时刷新的功能,只要去除后面url即可:
注意,用meta标签实现刷新/跳转的过程是不可取消的,所以需要手动取消的还是得老老实实使用js的定时器,但是对于简单的定时刷新或跳转,还是可以去亲自实践meta的用法。
title 标签:消息提醒
消息提醒功能实现在HTML5标准发布之前,浏览器还没有开放图标闪烁、音频播放,d出系统消息之类的api,只能借助其他非常规的手段,比如修改title 标签来达到类似的效果。
下面的代码通过定时修改title标签的内容,实现了消息提醒的功能,可以让用户在浏览其他页面时候,及时发现服务端返回的消息。
当然,动态修改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 引擎就会对堆砌大量相同关键词的网页进行惩罚,降低它被搜索到的权重)。
当我们搜索关键字“安全购物”的时候搜索结果会显示淘宝网的信息,虽然显示的搜索内容上并没有看到“安全购物”字样,这就是因为淘宝网页面中设置了这个关键字。
对应代码如下:
在实际工作中,推荐使用一些关键字工具来挑选,比如
link 标签:减少重复
有时候为了用户访问方便或者出于 历史 原因,对于同一个页面会有多个网址,又或者存在某些重定向页面,比如:
- https://baidu.com/a.html
- https://baidu.com/detail?id=abcd
那么在这些页面中可以这样设置:
这样可以让搜索引擎避免花费时间抓取重复网页。不过需要注意的是,它还有个限制条件,那就是指向的网站不允许跨域。
当然,要合并网址还有其他的方式,比如使用站点地图,或者在 HTTP 请求响应头部添加 rel="canonical"。
使用preload加载最重要的资源,以高优先级加载资源
允许浏览器在后台空闲时获取将来可能用到的资源,当执行到带有 prefetch的连接时,可以立刻从缓存中加载内容。link,dns,prerendering
允许浏览器在一个http请求正式发给服务器之前预先执行一些 *** 作,包括dns解析,TLS协商,TCP握手,消除了往返延迟并为用户节省时间
可以做为性能优化的一个方式
什么是 Preload,Prefetch 和 Preconnect?
以及原文
Preconnect
从Cronet.mm开始
1. CRNHTTPProtocolHandler来处理拦截的请求
2. CRNHTTPProtocolHandler 中startLoading开始发送请求
3. url_request Start
4. URLRequestHttpJob StartJob
5. 接着进入HttpNetworkTransaction::Start 这个比较重要,里面调用DoLoop
6. DoCreateStream 可能会创建出三种Stream HttpBasicStream, SpdyHttpStream, QuicHttpStream ,而我们只需要QuicHttpStream, 创建stream的流程大致如下:
http_stream_factory::RequestStreamInternal
http_stream_factory_job_controller::Start
http_stream_factory_job_controller::Start 又开始了一个新的loop
7. http_stream_factory_job_controller::DoCreateJobs 这一步最为关键,全部源码贴出来,
在QUIC的情况下会创建一个mainjob , 一个alternative_job_ ,优先alternative_job_执行,mainjob会执行DoWait,alternative_job_是否能创建取决于proxy(网络代理)的判断和 之前我们添加的QuicHints
int HttpStreamFactory::JobController::DoCreateJobs() {
DCHECK(!main_job_)
DCHECK(!alternative_job_)
HostPortPair destination(HostPortPair::FromURL(request_info_.url))
GURL origin_url = ApplyHostMappingRules(request_info_.url, &destination)
// Create an alternative job if alternative service is set up for this domain,
// but only if we'll be speaking directly to the server, since QUIC through
// proxies is not supported.
if (proxy_info_.is_direct()) {
alternative_service_info_ =
GetAlternativeServiceInfoFor(request_info_, delegate_, stream_type_)
}
quic::ParsedQuicVersion quic_version = quic::ParsedQuicVersion::Unsupported()
if (alternative_service_info_.protocol() == kProtoQUIC) {
quic_version =
SelectQuicVersion(alternative_service_info_.advertised_versions())
DCHECK_NE(quic_version, quic::ParsedQuicVersion::Unsupported())
}
LOG(WARNING) <<"TripCronet alternative_service_info_ protocol: "<<alternative_service_info_.protocol()
if (is_preconnect_) {
// Due to how the socket pools handle priorities and idle sockets, only IDLE
// priority currently makes sense for preconnects. The priority for
// preconnects is currently ignored (see RequestSocketsForPool()), but could
// be used at some point for proxy resolution or something.
if (alternative_service_info_.protocol() != kProtoUnknown) {
HostPortPair alternative_destination(
alternative_service_info_.host_port_pair())
ignore_result(
ApplyHostMappingRules(request_info_.url, &alternative_destination))
main_job_ = job_factory_->CreateAltSvcJob(
this , PRECONNECT, session_, request_info_, IDLE, proxy_info_,
server_ssl_config_, proxy_ssl_config_, alternative_destination,
origin_url, alternative_service_info_.protocol(), quic_version,
is_websocket_, enable_ip_based_pooling_, session_->net_log())
} else {
main_job_ = job_factory_->CreateMainJob(
this , PRECONNECT, session_, request_info_, IDLE, proxy_info_,
server_ssl_config_, proxy_ssl_config_, destination, origin_url,
is_websocket_, enable_ip_based_pooling_, session_->net_log())
}
main_job_->Preconnect(num_streams_)
return OK
}
main_job_ = job_factory_->CreateMainJob(
this , MAIN, session_, request_info_, priority_, proxy_info_,
server_ssl_config_, proxy_ssl_config_, destination, origin_url,
is_websocket_, enable_ip_based_pooling_, net_log_.net_log())
// Alternative Service can only be set for HTTPS requests while Alternative
// Proxy is set for HTTP requests.
if (alternative_service_info_.protocol() != kProtoUnknown) {
DCHECK(request_info_.url.SchemeIs(url::kHttpsScheme))
LOG(WARNING) <<"Selected alternative service (host: "
<<alternative_service_info_.host_port_pair().host()
<<" port: "<<alternative_service_info_.host_port_pair().port()
<<" version: "<<quic_version <<")"
HostPortPair alternative_destination(
alternative_service_info_.host_port_pair())
ignore_result(
ApplyHostMappingRules(request_info_.url, &alternative_destination))
alternative_job_ = job_factory_->CreateAltSvcJob(
this , ALTERNATIVE, session_, request_info_, priority_, proxy_info_,
server_ssl_config_, proxy_ssl_config_, alternative_destination,
origin_url, alternative_service_info_.protocol(), quic_version,
is_websocket_, enable_ip_based_pooling_, net_log_.net_log())
main_job_is_blocked_ = true
alternative_job_->Start(request_->stream_type())
}
// Even if |alternative_job| has already finished, it will not have notified
// the request yet, since we defer that to the next iteration of the
// MessageLoop, so starting |main_job_| is always safe.
main_job_->Start(request_->stream_type())
return OK
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)