1.前言 浏览器做了什么?
浏览器做的工作就是将我们输入的url变成一张位图BitMap。
BitMap传给计算机的显卡驱动设备,就转换成我们可以人眼可见的光信号。
浏览器将url变成一张BitMap,本篇主要解释基础的渲染流程部分,真正的浏览器工作比这个要复杂得多。
具体步骤:
-
http请求得到html页面:
输入url发送一个http请求,解析http回应,得到url对应的html页面; -
对html进行文本分析,解析得到DOM树:
对html文本进行parse解析,得到一个DOM树。 -
CSS Computing:
经过css计算,DOM树上对应哪些css规则,对css规则叠加,css规则覆盖,进行计算,得到带样式的DOM树; -
布局产生css盒的位置,
进行的一些位置的计算; -
render渲染,
给DOM树添加背景图和背景色。
2. 前置知识:有限状态机
2.1 状态机是什么?
有限状态机,又叫状态机。
每个状态都是一个机器
在每个机器里,我们可以做计算、存储和输出......
所有的机器接受的输入是一致的
状态机的本身没有状态,用函数表示的话,就是纯函数。
每个状态机知道下一个状态
有两种状态机:
Moore状态机
:每个机器都有确定的下一个状态。
Mealy状态机
:每个机器根据输入决定下一个状态(大多数比较实用)。
2.2 Js中的有限状态机(Mealy型)
// 每个函数是一个状态
function state(input){ // 函数参数就是输入
// 在函数中,可以自由的编写代码,处理每个状态的逻辑
// 返回值作为下一个状态
return next;
}
// 调用部分
while(input){
// 获取输入
state = state(input); //把状态机的返回值作为下一个状态
}
看到这里,不明白不要紧,往下看例子就知道咯....
2.2.1 一般方法解决字符输入查找
例:问题1:在一个字符串中找到字符‘a’, 怎么解?
我们可以这样:
function find(string){
for(let c of string){
if(c==='a')
return true;
}
return false;
}
let result = find("i am a girl",'a');
console.log(result); // true
例:问题2:在一个字符串中找到字符‘ab’, 怎么解?
function find(string){
let foundA = false; // 用一个变量标记a是否找到
for(let c of string){
if(c==='a')
foundA = true;
else if(foundA && c === 'b') // 在找到a的基础上,找字符b
return true;
else
foundA = false; // 如果a没有找到,或者找到a但是后面不是b,则表明ab没找到,将a的标记变量设置为false没找到
}
return false; // 循环结束没找到ab,则返回false
}
let result = find("i am a girl bcd");
console.log(result); // true
那问题3:在一个字符串中找到字符‘abcdef’, 怎么解呢?
同问题2,我们可以设置多个变量标识
function find(string){
let foundA = false;
let foundB = false;
let foundC = false;
let foundD = false;
let foundE = false;
for(let c of string){
if(c == 'a'){
foundA = true;
}else if(foundA && c === 'b'){
foundB = true;
}else if(foundB && c === 'c'){
foundC = true;
}else if(foundC && c === 'd'){
foundD = true;
}else if(foundD && c === 'e'){
foundE = true;
}else if(foundE && c === 'f'){
return true;
}else{
foundA = false;
foundB = false;
foundC = false;
foundD = false;
foundE = false;
}
}
return false
}
console.log(find("i am a abcjucabcdef")); // true
console.log(find("i am a abcjucabdef")); // false
看到这里,我们下面尝试使用状态机实现字符查找
2.2.2 使用状态机解决字符输入查找
在一个字符串中找到字符‘abcdef’, 用状态机解决。
思路:
- 找到字符'a'之前和之后,在for循环中的逻辑是完全不一样的,所以每找到我们要的一个字符,就去切换一个状态
function find(string){
let state = start; // state表示当前状态
for(let c of string){
state = state(c); // 将state执行的结果,也就是下一个状态赋给当前状态
}
return state === end;
}
function start(c){
if(c ==='a'){
return foundA;
}else
return start;
}
// end状态永远返回end,叫做一个trap
function end(c){
return end;
}
// foundA 找字符b
function foundA(c){
if(c ==='b'){
return foundB;
}else{
return start(c); // 把当前字符传给start从新开始往后找,避免漏掉当前字符。
}
}
// foundB 找字符c
function foundB(c){
if(c ==='c'){
return foundC;
}else{
return start(c);
}
}
// foundC 找字符d
function foundC(c){
if(c ==='d'){
return foundD;
}else{
return start(c);
}
}
// foundD 找字符e
function foundD(c){
if(c ==='e'){
return foundE;
}else{
return start(c);
}
}
// foundE 找字符f
function foundE(c){
if(c ==='f'){
return end;
}else{
return start(c);
}
}
console.log(find('abcdeabcdefsss')); // true
那用状态机怎么实现在字符串中查找'abababx' ?
// 状态机 处理字符串"abababx"
function find(string){
let state = start;
for(let c of string){
state = state(c);
}
return state === end;
}
function start(c){
if(c === "a"){
return foundA;
}else{
return start;
}
}
function end(c){
return end;
}
function foundA(c){
if(c === "b"){
return foundB;
}else{
return start(c);
}
}
function foundB(c){
if(c === 'a'){
return foundA2;
}else{
return start(c);
}
}
function foundA2(c){
if(c === 'b'){
return foundB2;
}else{
return start(c);
}
}
function foundB2(c){
if(c === 'a'){
return foundA3;
}else{
return start(c);
}
}
function foundA3(c){
if(c === 'b'){
return foundB3;
}else{
return start(c);
}
}
function foundB3(c){
if(c === 'x'){
return end;
}else{
return foundB2(c);
}
}
console.log(find("i am abababx")); // true
console.log(find("i am ababababx")); // true
console.log(find("i am abcabcababx")); // false