渲染流程
地址栏输入了url后都发生了什么
http协议
http1和http2的区别
http1 服务端到静态目录查找html,若文件存在,返回静态资源后,若有js 或css,再请求资源
http2 服务端找到静态文件html后,循环里面需要的静态文件,做一次服务端推送,而不是请求的时候才返回。(就是第一次请求就把资源都返回)
浏览器收到内容后做什么?
6.将不同图层进行绘制,转交给合成线程处理,最终产生页面,并显示在浏览器上(painting, display)
为什么css放上面,js放下面
css不阻塞html解析,阻塞页面渲染
- css放下面会导致重绘,回流,parse html, parse stylesheet, paint, parse html, parse stylesheet, paint
- js会阻塞html解析成dom
js中可能会有加载css,所以js等待css,js里要操作dom节点,dom等待js,导致渲染一段段的
所以js放下面
模拟浏览器解析流程
node服务,server.js
//请求服务,返回html
const http = reuire('http');
const fs = require('fs');
const path = require('path');
const server = http.createServe((req, res)=>{
console.log(req.headers);
res.end(fs.readFileSync(path.resolve(__dirname,'index.html')));
})
client.js用node写客户端
const net = require('net');
const HttpParser = require('./http-parser');
const HtmlParser = require('./htmlparser2');
// 发送请求,监听数据的到来
class HTTPRequest {
constructor(options = {}) {
this.host = options.host;
this.method = options.method || 'GET';
this.path = options.path || '/';
this.port = options.port || 80;
this.headers = options.headers
}
send(){
return new Promise((resolve, reject)=>{
// 构建http请求
const rows = [];
rows.push(`${this.method} ${this.path} HTTP/1.1`); // 模拟浏览器的请求行
Object.keys(this.headers).forEach(key=>{
rows.push(`${key}:${this.headers[key]}`)
})
let data = rows.join('\r\n') + '\r\n\n\n';
let socket = net.createConnection({ // 通过主机名端口寻址,拿到通道(tcp连接传输http数据)
host: this.host
port: this.port
},()=>{
socket.write(data);
})
let parser = new HttpParser(); // 解析器
socket.on('data',function(chunk){ //事件会触发多次
console.log(chunk.toString);
// 解析数据 为二进制流
parser.parse(chunk);
if(parser.result){
resolve(parser.result); //
}
})
})
}
}
function parserCSS(csstext) {
let ast = css.parser(csstext)
}
async function request() {
const request = new HTTPRequest({
host: '127.0.0.1',
method:'GET',
port:3000,
path: '/',
headers: {
name:chao,
age:20
}
})
let {responseLine, headers, body} = await request.send();
// 浏览器会根据响应类型来解析文件 Content-Type:'text/html'
// html -> html-parser -> dom tree 词法分析 分析html
// 解析后需要生成tree,典型的栈结构
let DomTree = [{type:'document',children:[]}]; // 数据结构
let parser = new HtmlParser.parser({
onopentag(name, attributes){
console.log('start', name, attributes);
let parent = stack[stack.length -1];
let element ={
tagName:name,
attributes,
children:[],
parent
}
parent.cildren.push(element);
stack.push(element);
},
ontext(text){
console.log('text', text);
let parent = stack[stack.length -1];
let textNode = {
type:'text',
text
}
parent.children.push(textNode);
},
onclosetag(name){
console.log('close', name);
if(name === 'style'){
parserCSS(parent.children[0].text)
}
stack.pop();
},
});
console.log(body);
parser.end(body);
}