极客时间——重学前端

时间:Oct. 19, 2021 分类:

目录:

开篇词 | 从今天起,重新理解前端

2006年前,页面跳转通过超链接的形式,谷歌基于ajax发布的Gmail也没有多久,也就标志着web1.0(静态网页)到web2.0(动态网页)

专栏分四个模块

  • JavaScript 文法和运行时的角度来讨论Js
  • Css和Html 侧重语言和设计思想的角度讲解
  • 浏览器实践 浏览器工作原理和API,包括DOM,BOM,CSSOM和其他内容
  • 前端综合应用

01

学习方法

  • 0基础推荐 JavaScript高级程序设计和精通Css

建立知识架构

文法
    词法
    语法
语义
运行时
    类型
    执行过程
  • 文法根据编译原理划分,语法和语义又一一对应
  • 再往下词法就是直接量,关键字,运算符
  • 语法和语义则是表达式,语句,函数,对象,模块
  • 运行时部分则是程序=算法+数据结构,类型就是数据结构,算法就是执行过程
  • 类型包含对象,数字,字符串等

在Js中,有完整的文法定义和语法语义,浏览器中的API分布在w3c的各种标准中

追溯本源

例如css的两个属性

  • opacity 单纯的数值
  • display 每个取值背后都是一个不同的布局体系,需要关注正常流(Normal Flow),关注弹性布局系统以及grid等

02

JavaScript

HTML和CSS

Html的标签分为几种

  1. 文档元数据
  2. 语义相关
  3. 连接 文档内部和外部的链接
  4. 替换型标签 引入声音,图片和视频等外部元素替换自身的标签
  5. 表单
  6. 表格

浏览器的实现原理和API

前端工程实践

03 | HTML语义 div和span

目前的前端没有复杂的语义标签,只需要div和span即可

语义类的标签,更多的

10 | 浏览器:一个浏览器是如何工作的?(阶段一)

  1. 浏览器首先使用HTTP协议或者HTTPS协议像服务端请求页面
  2. 将请求获得的HTML代码解析,构建DOM树
  3. 计算DOM树上的CSS属性
  4. 根据CSS属性对元素进行渲染,得到内存中的位图
  5. 一个可选步骤,对位图进行合成,可以极大的增加后续绘制速度
  6. 合成后绘制到界面上

浏览器实现可以是使用一个TCP库甚至一个现成的HTTP库就可以解决浏览器通信部分

HTTP阶段略过,一个request/responce模式

11 | 浏览器:一个浏览器是如何工作的?(阶段二)

解析HTML代码

流程为

处理内容为HTTP的Response的Body部分

HTML处理需要进行容错,例如"

词token拆分

<p class="a">text text text</p>

作为一个词,如果是整个p标签就过大了,因为p标签也可以嵌套,只用p标签开头是不符合的,但是需要包含属性,所以以"<p"为第一个token(词)标签开始,然后是"class="a""属性,然后是">"标签结束,”text text text"文本,"</p>"

其他的还有就是注释对应的<!--xxxx--><![CDATA[hello world]]>(Data是XHTML(XML)文档中的一个特殊区域,这个区域可以包含任意格式的不需要解析的文本内容,可以用于解决js脚本在XHTML(XML)文档中特殊符号如<报错的问题)

对于接受到第一个<就可以认定不是文本,然后后来收到的如果不是!那就是标签了,如果是就再判断是注释还是CDATA

状态机

绝大多种语言的词法部分都是用状态机来实现的

可以参考HTML官方文档,官方文档规定了80个状态,是唯一一个在标准中规定了状态机的实现的语言,对于大多数语言来说,状态机是一种实现而非定义

和刚才说的一样

初始状态就是区分<和非<

  • 如果是<进入一个标签状态
  • 如果是非<,那么进入一个标签状态

在标签状态下

  • 如果下一个为"!",那么就进入注释节点或CDATA节点
  • 如果下一个为"/",那么就进入一个结束标签
  • 如果下一个是字母,就可以确定进入一个开始标签

还可能有?和%等内容需要进行判断

状态机涉及编译原理的知识了

接下来就是代码实现了,C/C++和JavaScript中实现状态机的方式大同小异,把每个函数当做一个状态,参数是接收到的字符串,返回值是下一个状态函数

对于JavaScript代码来写就是

var data = function(c){
 if(c=="&") {
 return characterReferenceInData;
 }
 if(c=="<") {
 return tagOpen;
 }
  else if(c=="\0") {
 error();
 emitToken(c);
 return data;
 }
 else if(c==EOF) {
 emitToken(EOF);
 return data;
 }
 else {
 emitToken(c);
 return data;
 }
};
var tagOpenState = function tagOpenState(c){
 if(c=="/") {
 return endTagOpenState;
 }
 if(c.match(/[A-Z]/)) {
 token = new StartTagToken();
 token.name = c.toLowerCase();
 return tagNameState;
 }
 if(c.match(/[a-z]/)) {
 token = new StartTagToken();
 token.name = c;
 return tagNameState;
 }
 if(c=="?") {
 return bogusCommentState;
 }
 else {
 error();
 return dataState;
 }
};
//……

而状态迁移代码为

var state = data;
var char
while(char = getInput())
 state = state(char);

主要关键的是state = state(char),对于那种方式来读取字符串流,都可以通过state来处理输入的字符流,真实的场景来自TCP输出流

function HTMLLexicalParser(){
 // 状态函数们……
 function data() {
 // ……
 }
 function tagOpen() {
 // ……
 }
 // ……
 var state = data;
 this.receiveInput = function(char) {
 state = state(char);
 }
}

然后实现字符流拆分为词,token

构建DOM树

构建DOM树就是通过栈的方式实现了

对于每个节点单独建立了一个栈

css解析