- A+
所属分类:Web前端
这篇笔记总结自网课?DNS解析和优化【渡一教育】
DNS用于将域名转换成IP地址。
特点:
-
DNS解析过程耗费时间长;
-
DNS有本地缓存。
DNS解析完成得到IP地址,这个IP地址会存储到本地设备,后续再读这个域名会直接返回本地缓存的IP地址。
用户浏览网页中的DNS解析流程
- 首先用户输入url地址,然后需要对网站的域名进行DNS解析,这个解析过程无法优化。
- 而在站点中可能还用到了很多其它域名下的资源,在解析
html
的过程也会触发DNS解析。
例如:<img>
标签的src
引用了其它域名站点的图片,或者<script>
标签引入了外部的脚本文件,或者<link>
标签引入了其它域名站点的css
文件。
当解析html的过程中遇到了站外的
script
标签且本地无缓存时,解析html
的进度会暂停,直到script
标签引入并执行再继续。
随着网站规模越来越大,这种外部资源的引入可能越来越多。而多次的DNS解析会耗费许多时间。
优化思路:源代码中使用的外部域名是已知的,可以把它们都提取到html
的头部,提前异步解析。
提前异步解析DNS
使用link标签的dns-prefetch
<html> <head> <link rel="dns-prefetch" href="https://www.a.com"/> <link rel="dns-prefetch" href="https://www.b.com"/> <link rel="dns-prefetch" href="https://www.c.com"/> ... </head> <body> ... </body> </html>
但是,考虑到我们平时的开发环境有以下特点:
- 使用框架开发,不同的域名分散在不同的组件;
- 多人开发,不知道其他人有没有引入外部域名;
- 一般不会手动编辑打包后的
index.html
文件。
我们需要较为自动化的脚本协助完成整个项目中的外部域名统计,并写入到最终打包的index.html
头部。
脚本编写
目的:读取dist
文件夹中的.css
,.js
文件,统计外部域名并写入到index.html
头部。
创建脚本:项目根目录下创建文件夹/scripts
,创建文件dns-prefetch.js
;
脚本内容:
const fs = require('fs'); const path = require('path'); const { parse } = require('node-html-parse'); const { glob } = require('glob'); const urlRegex = require('url-regex'); // 获取外部链接的正则表达式 const urlPattern = /(https?://[^/]*)/i; const urls = new Set(); // 遍历dist目录中的所有HTML, JS, CSS文件 async function searchDomain(){ const files = await glob('dist/**/*.{html,css,js}'); for(const file of files){ const source = fs.readFileSync(file, 'utf-8'); const matches = source.match(urlRegex({strict: true})); if(matches){ matches.forEach((url)=>{ const match = url.match(urlPattern); if(match && match[1]){ urls.add(match[1]); } }); } } } async function insertLinks(){ const files = await glob('dist/**/*.html'); const links = [...urls] .map((url) => `<link rel="dns-prefetch" href="${url}"/>`) .join('n'); for(const file of files){ const html = fs.readFileSync(file, 'utf-8'); const root = parse(html); const head = root.querySelector('head'); head.insertAdjacentHTML('afterbegin', links); fs.writeFileSync(file, root.toString()); } } async function main(){ await searchDomain(); // 在<head>标签中添加预取链接 await insertLinks(); } main();
glob
用于使用正则表达式将匹配的文件都找到;fs
用于读取选中的文件;urlRegex
用于分析出文件中的URL地址;node-html-parse
用于在脱离浏览器的环境下,将读取到的html
代码文本转换为节点。
当脚本编写完成之后,将其添加到打包代码的工具流程中。
在package.json
文件中:
{ "scripts": { "build": "vite build && node ./scripts/dns-prefetch.js" } }