前端优化

脚本异步载入

传统的脚本加载方式是阻塞式的,即在脚本加载和执行完成之前,浏览器会阻塞页面的渲染。而异步加载脚本采用非阻塞方式,页面会继续渲染,而不必等待脚本的加载和执行。

异步加载脚本的实现方式主要有两种:

async

使用 async 属性: 将 script 标签的 async 属性设置为 true,浏览器将异步加载和执行脚本,加载完成后立即执行,不阻塞页面渲染。

<script async src="example.js"></script>

使用动态创建 script 元素: 使用 JavaScript 动态创建 script 元素,并通过设置 async 属性实现异步加载。

const script = document.createElement('script')
script.src = 'example.js'
script.async = true
document.head.appendChild(script)

defer

defer 属性与 async 属性类似,也用于异步加载脚本,但有一个重要的区别:defer 保证脚本的执行顺序与它们在页面中的顺序一致。

<script defer src="script1.js"></script>
<script defer src="script2.js"></script>
<script defer src="script3.js"></script>
// 按script1 script2 script3依次执行

优势

1、提高页面加载速度

异步加载脚本不会阻塞页面渲染,因此可以加速页面加载速度。尤其对于大型应用或包含多个脚本的页面,异步加载可以更高效地利用网络资源。

2、提升用户体验

通过异步加载脚本,可以使页面更快地呈现给用户,提升用户体验。特别是在移动设备或网络状况较差的情况下,异步加载对提高页面的响应速度更为显著。

3、并行加载多个脚本

异步加载脚本使得多个脚本能够并行加载,而不是串行加载。这意味着页面可以同时下载多个脚本文件,加快整体加载时间。

4、动态加载第三方库
在某些情况下,我们可能只有在特定条件下才需要加载某个第三方库。通过动态创建 script 元素,可以根据条件在运行时决定是否加载该库。

if (someCondition) {
const script = document.createElement('script')
script.src = 'third-party-library.js'
script.async = true
document.head.appendChild(script)
}

5、异步加载并执行
在某些情况下,可能需要等待一个异步操作完成后再加载并执行脚本。可以使用 onload 事件或 Promise 来实现。

const script = document.createElement('script')
script.src = 'example.js'
script.async = true
// 使用 onload 事件
script.onload = () => {
console.log('Script loaded and executed.')
document.head.appendChild(script)
}
// 或者使用 Promise
function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = src
script.async = true
script.onload = resolve
script.onerror = reject
document.head.appendChild(script)
})
}
loadScript('example.js').then(() => {
console.log('Script loaded and executed.')
})

注意

1、依赖关系

异步加载脚本可能导致脚本之间的依赖关系变得复杂。在使用异步加载脚本时,需要确保脚本的加载顺序不会破坏它们之间的依赖关系。

2、兼容性

虽然大多数现代浏览器都支持异步加载脚本的方式,但在某些旧版本浏览器中可能存在兼容性问题。在实际应用中,需要根据项目的浏览器兼容性要求做出相应的选择。

预加载和预渲染

预加载

有些资源不需要马上用到,但是希望尽早获取,这时候就可以使用预加载。预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的文件延后加载,唯一缺点就是兼容性不好

预加载其实是声明式的 fetch,强制浏览器请求资源,并且不会阻塞 onload 事件,可以使用以下代码开启预加载:

<link rel="preload" href="http://example.com" />

预渲染

可以通过预渲染将下载的文件预先在后台渲染,预渲染虽然可以提高页面的加载速度,但是要确保该页面百分百会被用户在之后打开,否则就白白浪费资源去渲染,可以使用以下代码开启预渲染:

<link rel="prerender" href="http://example.com" />

HTTP 缓存

浏览器询问服务器缓存是否有效,服务器返回 304 指示浏览器使用缓存。

资源仍然处于有效期时,浏览器会直接使用磁盘缓存。

Cache-Control 响应头表示了资源是否可以被缓存,以及缓存的有效期。

Etag 响应头标识了资源的版本,此后浏览器可据此进行缓存以及询问服务器。

Last-Modified 响应头标识了资源的修改时间,此后浏览器可据此进行缓存以及询问服务器。

Cache-Control

Cache-ControlHTTP 响应头中,用于指示代理和 UA(User Agent,简称 UA,浏览器标识,是一种用于标识浏览器类型、版本和操作系统等信息的字符串) 使用何种缓存策略

no-cache 为本次响应不可直接用于后续请求(在没有向服务器进行校验的情况下)

no-store 为禁止缓存(不得存储到非易失性介质,如果有的话尽量移除,用于敏感信息)

private 为仅 UA 可缓存

public 为大家都可以缓存。

Cache-Control 为可缓存时,同时可指定缓存时间(比如 public, max-age:86400)。 这意味着在 1 天(60x60x24=86400)时间内,浏览器都可以直接使用该缓存(此时服务器收不到任何请求)

import http from 'http'
let server = http.createServer((req, res) => {
res.setHeader('Cache-Control', 'public, max-age=86400')
res.end('harttle.com')
})
server.listen(3333)

除了 Cache-Control 中的 max-age 外,ExpiresVary 等头字段也可用来设置缓存的有效性。

Etag

如果资源本身确实会随时发生改动,还用 Cache-Control 就会使用户看到的页面得不到更新。 但如果还希望利用 HTTP 缓存(万一资源没变呢),这就需要有条件的(conditional)HTTP 请求。

Etag 响应头字段表示资源的版本,浏览器在发送请求时会带 If-None-Match 头字段, 来询问服务器该版本是否仍然可用。如果服务器发现该版本仍然是最新的, 就可以返回 304 状态码指示 UA 继续使用缓存。

import http from 'http'
let server = http.createServer((req, res) => {
console.log(req.url, req.headers['if-none-match'])
if (req.headers['if-none-match']) {
// 检查文件版本
res.statusCode = 304
res.end()
} else {
res.setHeader('Etag', '00000000')
res.end('harttle.com')
}
})
server.listen(3333)

Last-Modified

Etag 类似,Last-Modified HTTP 响应头也用来标识资源的有效性。 不同的是使用修改时间而不是实体标签。对应的请求头字段为 If-Modified-Since

import http from 'http'
let server = http.createServer((req, res) => {
console.log(req.url, req.headers['if-modified-since'])
if (req.headers['if-modified-since']) {
// 检查时间戳
res.statusCode = 304
res.end()
} else {
res.setHeader('Last-Modified', new Date().toString())
res.end('harttle.com')
}
})
server.listen(3333)

页面刷新

按下刷新按钮或快捷键(在 MacOS 中是 Cmd+R)会触发浏览器的“正常重新加载”(normal reload), 此时浏览器会执行一次 Conditional GETCache-Control 等缓存头字段会被忽略,并且带 If-None-Match, If-Modified-Since 等头字段。 此时服务器总会收到一次 HTTP GET 请求。 在 Chrome 中按下刷新,浏览器还会带如下请求头:Cache-Control:max-age=0

在 Chrome 中按下 Cmd+Shift+R (MacOS)可以触发强制重新加载(Hard Reload), 此时包括页面本身在内的所有资源都不会使用缓存。 浏览器直接发送 HTTP 请求且不带任何条件请求字段。

nginx 代码压缩

Nginx 开启 Gzip 压缩功能, 可以使网站的 cssjsxmlhtml 文件在传输时进行压缩,提高访问速度, 开启 Gzip 功能后,Nginx 服务器会根据配置的策略对发送的内容, 如 cssjsxmlhtml 等静态资源进行压缩, 使得这些内容大小减少,在用户接收到返回内容之前对其进行处理,以压缩后的数据展现给客户。

这样不仅可以节约大量的出口带宽,提高传输效率,还能提升用户快的感知体验, 一举两得; 尽管会消耗一定的 cpu 资源,但是为了给用户更好的体验还是值得的

在 nginx 中配置文件 http{}中这样写

http {
.......
gzip on; // 开启 gzip 压缩功能
gzip_min_length 1k; // 设置允许压缩的页面最小字节数; 这里表示如果文件小于 10 个字节,就不用压缩,因为没有意义,本来就很小
gzip_buffers 4 16k; // 设置压缩缓冲区大小,此处设置为 4 个 16K 内存作为压缩结果流缓存
gzip_http_version 1.1; // 压缩版本
gzip_comp_level 6; //设置压缩比率,最小为 1,处理速度快,传输速度慢;9 为最大压缩比,处理速度慢,传输速度快; 这里表示压缩级别,可以是 0 到 9 中的任一个,级别越高,压缩就越小,节省了带宽资源,但同时也消耗 CPU 资源,所以一般折中为 6
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/javascript application/json; // 制定压缩的类型,线上配置时尽可能配置多的压缩类型!
gzip_disable "MSIE [1-6]\."; // 配置禁用 gzip 条件,支持正则。此处表示 ie6 及以下不启用 gzip(因为 ie 低版本不支持)
gzip_vary on; // 选择支持 vary header;改选项可以让前端的缓存服务器缓存经过 gzip 压缩的页面; 这个可以不写,表示在传送数据时,给客户端说明我使用了 gzip 压缩
}
posted @   有些东西学不会  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2022-05-07 Dos命令
2022-05-07 CSS技巧
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css
点击右上角即可分享
微信分享提示