← 返回全部文章

技术笔记

前端基础总结

技术/前端
文章目录

总体分为4个部分,比较常用的基础。

HTML

标签基础

块: div, form, h1-h6, menu, ul, ol, p, section, nav, article, aside

行内: a, br, em, img, input, label, select, span, strong, textarea

全局属性

head

语义化

渐进增强/优雅降级

img:行内元素,不受同源策略影响

HTML 5 新特性

Web Audio/Video

应用实例

Audio 对象

Web Worker

应用:碰撞检测,webpack+worker

Drop/Drag

属性

事件

拖拽删除

<div class="wrapper">
    <ul>
        <li draggable="true">1</li>
        <li draggable="true">2</li>
        <li draggable="true">3</li>
        <li draggable="true">4</li>
        <li draggable="true">5</li>
    </ul>
    <div class="box">垃圾桶</div>
</div>
var oUl = document.getElementsByTagName('ul')[0],
    oBox = document.getElementsByClassName('box')[0],
    oLi = document.getElementsByTagName('li'),
    len = oLi.length;

function bindLiEvent(){
    for(var i = 0; i < len; i ++){
        oLi[i].addEventListener('dragstart',function(e){
            var index = getIndex(this);
            e.dataTransfer.setData('data', index);
        });
        oLi[i].addEventListener('dragover',function(e){
            e.preventDefault();
        });
        oLi[i].addEventListener('drop',function(e){
            var i = e.dataTransfer.getData('data');
            oUl.insertBefore(oLi[i], this);
        });
    }
}
//获取列表最新的索引值
function getIndex(dom){
    for(var i = 0; i < len; i ++){
        if(oLi[i] === dom){                    
            return i;
        }
    }

}
function removeLi(){
    oBox.addEventListener('dragover',function(e){
        e.preventDefault();
    })
    oBox.addEventListener('drop',function(e){
        e.preventDefault();
        var index = e.dataTransfer.getData('data');
        oLi[index].remove();
    })
}
bindLiEvent();
removeLi ();

Notification

桌面消息通知

用户授权信息:Notification.permission===’granted/denied‘

请求权限:Notification.requestPermission().then(permission => {})

推送通知: new Notification(title, options)

options:通知的设置选项(可选)。

Canvas

基础API

渲染优化

WebGL

表单

属性

自定义样式

<input type="number" id="test" />
<label for="test"></label>
input {
    position:absolute;
    clip:rect(0,0,0,0);
}
input + label:before:after {
    //样式
}
input:checked + label:before:after {
    //样式
}

验证

基础元素

input, textarea, select, button

类型:text, number, password, submit, radio, checkbox, color, date, email,range, search, url, time

新增元素

datalist, keygen, output

JS控制表单

const ajaxForm = (form, callback, async = true) => {
    let XHR = new XMLHttpRequest()
    let formData = new FormData(form)

    XHR.addEventListener('load', function(event) {
        callback.call(this, event.target.responseText)
    })

    XHR.open(form.method, form.action, async)

    XHR.setRequestHeader("Content-type", form.enctype)

    XHR.send(formData)

    return XHR
}

form.addEventListener("submit", function(event) {
    event.preventDefault()

    ajaxForm(this, callback);
})

缓存

作用:http会话标识,记录用户的有关信息,帮助站点保存信息,会话追踪

属性

特性

Web Storage

作用:提供访问特定域名下的会话存储sessionStorage或本地存储localStorage的功能,可添加,修改和删除,最大可存储5M,以字符串存储,用于储存用户访问的结构化数据,增强用户体验

属性

length : 存储在Storage对象中的数据项数量

方法

Storage.key(n) : 返回存储中的第n个键名

Storage.getItem(key) : 返回对应的键值

Storage.setItem(key, value) : 将键值对添加到存储中,键名存在,则更新

Storage.removeItem(key) : 删除对应的键名

Storage.clear() : 清空存储

区别

HTTP

method

方法 功能
GET 请求资源
HEAD 确认资源有效性
POST 输入数据
PUT 使用请求主体新建文件,若存在就覆盖
DELETE 删除指定URL资源
OPTIONS 询问支持的方法

状态码

1XX 信息性状态

状态码 信息
100 Continue 客户端继续发送请求
101 switching protocols 请求正常识别,切换协议

2XX 成功

状态码 信息
200 OK 客户端请求被正常处理了
204 No Content 请求被正常处理了,但响应中不包含主体
206 Partial Content 客户端范围请求被正确响应

3XX 重定向

状态码 信息
301 Move Permanently 永久性重定向
302 Found 临时性重定向,强制POST转GET
303 See Other 临时性重定向—GET
304 Not Modified 发生请求条件不满足,客户端存在为过期缓存
307 Temporary Redirect 临时重定向,可以POST

4XX 客户端错误

状态码 信息
400 请求报文语法错误
401 需要HTTP认证信息
403 请求资源被拒绝
404 请求资源不存在

5XX 服务器错误

状态码 信息
500 服务器执行请求出错
503 服务器维护或超负载

HTTP报文

请求报文

响应报文

XMLHttpRequest

XMLHtttpRequest实际上是浏览器对HTTP报文的一种应用封装

SSL

HTTP2.0

HTTP请求流程

  1. 在浏览器地址栏输入URL
  2. 浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤
  3. 如果资源未缓存,发起新请求
  4. 如果已缓存,检验是否足够新鲜,足够新鲜直接提供给客户端,否则与服务器进行验证。
  5. 检验新鲜通常有两个HTTP头进行控制Expires和Cache-Control:
    • HTTP1.0提供Expires,值为一个绝对时间表示缓存新鲜日期
    • HTTP1.1增加了Cache-Control: max-age=,值为以秒为单位的最大新鲜时间
  6. 浏览器解析URL获取协议,主机,端口,path
  7. 浏览器组装一个HTTP(GET)请求报文
  8. 浏览器获取主机ip地址,过程如下:
  9. 浏览器缓存
  10. 本机缓存
  11. hosts文件
  12. 路由器缓存
  13. ISP DNS缓存
  14. DNS递归查询(可能存在负载均衡导致每次IP不一样)
  15. 打开一个socket与目标IP地址,端口建立TCP链接,三次握手如下:
  16. 客户端发送一个TCP的SYN=1,Seq=X的包到服务器端口
  17. 服务器发回SYN=1, ACK=X+1, Seq=Y的响应包
  18. 客户端发送ACK=Y+1, Seq=Z
  19. TCP链接建立后发送HTTP请求
  20. 服务器接受请求并解析,将请求转发到服务程序,如虚拟主机使用HTTP Host头部判断请求的服务程序
  21. 服务器检查HTTP请求头是否包含缓存验证信息如果验证缓存新鲜,返回304等对应状态码
  22. 处理程序读取完整请求并准备HTTP响应,可能需要查询数据库等操作
  23. 服务器将响应报文通过TCP连接发送回浏览器
  24. 浏览器接收HTTP响应,然后根据情况选择关闭TCP连接或者保留重用,关闭TCP连接的四次握手如下:
    1. 主动方发送Fin=1, Ack=Z, Seq= X报文
    2. 被动方发送ACK=X+1, Seq=Z报文
    3. 被动方发送Fin=1, ACK=X, Seq=Y报文
    4. 主动方发送ACK=Y, Seq=X报文
  25. 浏览器检查响应状态吗:是否为1XX,3XX, 4XX, 5XX,这些情况处理与2XX不同
  26. 如果资源可缓存,进行缓存
  27. 对响应进行解码(例如gzip压缩)
  28. 根据资源类型决定如何处理(假设资源为HTML文档)
  29. 解析HTML文档,构件DOM树,下载资源,构造CSSOM树,执行js脚本,这些操作没有严格的先后顺序,以下分别解释
  30. 构建DOM树:
    1. Tokenizing:根据HTML规范将字符流解析为标记
    2. Lexing:词法分析将标记转换为对象并定义属性和规则
    3. DOM construction:根据HTML标记关系将对象组成DOM树
  31. 解析过程中遇到图片、样式表、js文件,启动下载
  32. 构建CSSOM树:
    1. Tokenizing:字符流转换为标记流
    2. Node:根据标记创建节点
    3. CSSOM:节点创建CSSOM树
  33. 根据DOM树和CSSOM树构建渲染树:
    1. 从DOM树的根节点遍历所有可见节点,不可见节点包括:1)script,meta这样本身不可见的标签。2)被css隐藏的节点,如display: none
    2. 对每一个可见节点,找到恰当的CSSOM规则并应用
    3. 发布可视节点的内容和计算样式
  34. js解析如下:
    1. 浏览器创建Document对象并解析HTML,将解析到的元素和文本节点添加到文档中,此时document.readystate为loading
    2. HTML解析器遇到没有async和defer的script时,将他们添加到文档中,然后执行行内或外部脚本。这些脚本会同步执行,并且在脚本下载和执行时解析器会暂停。这样就可以用document.write()把文本插入到输入流中。同步脚本经常简单定义函数和注册事件处理程序,他们可以遍历和操作script和他们之前的文档内容
    3. 当解析器遇到设置了async属性的script时,开始下载脚本并继续解析文档。脚本会在它下载完成后尽快执行,但是解析器不会停下来等它下载。异步脚本禁止使用document.write(),它们可以访问自己script和之前的文档元素
    4. 当文档完成解析,document.readState变成interactive
    5. 所有defer脚本会按照在文档出现的顺序执行,延迟脚本能访问完整文档树,禁止使用document.write()
    6. 浏览器在Document对象上触发DOMContentLoaded事件
    7. 此时文档完全解析完成,浏览器可能还在等待如图片等内容加载,等这些内容完成载入并且所有异步脚本完成载入和执行,document.readState变为complete,window触发load事件
  35. 显示页面(HTML解析过程中会逐步显示页面)

WebSocket

作为浏览器与服务器全双工通信的媒介,可以传输基于消息的文本和二进制数据,以数据流的方式实现数据交换,两端可以随时向对方发送数据。在享受全双工长连接通信的同时,不再享有HTTP连接的服务和优化,如状态管理,压缩,缓存等。

API

浏览器提供WebSocket对象用于创建WebSocket连接,以及用于通信控制的相关API

创建

使用浏览器提供的WebSocket构造函数创建一个websocket实例

const socket = new WebSocket(uri, protocols)

websocket uri 采用自定义模式,可选 ws 和 wss

ws : 表示纯文本通信,普通请求,占用80端口

"ws://"host[":"port]path["?"query]

wss : 表示使用加密信道通信(TCP + TLS),基于SSL的安全传输,占用443端口

"wss://"host[":"port]path["?"query]

因为 WebSocket 最初建立连接时是借助HTTP协议 ,后续是基于TCP 进行通信,而部分HTTP 中间件可能不理解新的WebSocket协议 ,而这可能导致一些问题:盲目的连接升级,意外缓冲WebSocket帧,修改内容,把WebSocket流量误当作不完整的HTTP通信,而这就需要一条加密信道,所有引入了wss ,它建立了一条端到端的安全通道,这条加密信道对中间设备模糊了数据,因此中间设备就不能再感知到数据内容,也就无法在对请求特殊处理。

可以自定义的一套用于传输数据的子协议。WebSocket自身只提供基本的文本和二进制数据传输,对消息的具体内容格式不保证。但服务器和客户端可以自定义一套有关消息元数据的格式的子协议,进而简洁实现其他格式数据的传输。

在服务器定义协议数据的格式要求,通过protocols 这个参数,客户端和服务器进行互相选择,按照约定的方式处理发送及接受到的数据。

属性

WebSocket 实例提供的属性接口

属性名 类型 描述
binary DOMString 传输数据的类型。blob 或 arraybuffer
bufferedAmout unsigned long 只读 ,数据队列中等待传输但还未发出的数据长度
extensions DOMString 服务器提供的可扩展协议的列表
protocol DOMString 选定的子协议名字的字符串
readyState unsigned short 只读 ,连接的当前状态
url DOMString 只读 ,通信地址

常量

readyState 属性的取值,标识当前WebSocket 的连接状态

常量 值 描述
CONNECTING 0 连接还没开启
OPEN 1 连接已开启并准备好进行通信
CLOSING 2 连接正在关闭的过程中
CLOSED 3 连接已经关闭,或连接无法建立

事件

WebSocket 连接被响应或服务器的连接请求,当readyState 的值为OPEN 时触发该事件,接收一个名为open的事件对象

socket.addEventListener("open", (e) => {
    socket.send("Hello")
})

当接收到来自服务器推送的消息时触发该事件,传入一个名为message 的事件对象

socket.addEventListener("message", (e) => {
    console.log(e.data)
})

客户端或服务器报告错误信息时触发,并且会关闭连接,传入一个包含错误信息的名为error 的事件对象

socket.addEventListener("error", (error) => {
    console.log(error)
})

连接关闭或连接失败时触发,客户端或服务器都可以发起关闭连接。服务器会发送关闭码,根据关闭码可以针对一些异常参数进行相关处理。传入一个包含关闭码的事件对象。

socket.addEventListener("close", (e) => {
    e.wasClean [Boolen] 
        true 客户端或服务器调用close方法主动关闭
        false 连接失败或异常关闭
    e.code [Number] 关闭连接的状态码
    e.season [String] 关闭连接的原因 
})
状态码 名称 描述
1000 CLOSE_NORMAL 正常关闭
1001 CLOSE_GOING_AWAY 终端离开,服务器错误或浏览器从打开的连接跳转离开
1002 CLOSE_PROTOCOL_ERROR 协议错误
1003 CLOSE_UNSUPPORTED 接收到不允许的数据类型
1005 CLOSE_NO_STATUS 没有收到预期的状态码
1006 CLOSE_ABNORMAL 没有关闭帧
1007 unsupported Data 接收到格式不符合的数据
1009 CLOSE_TOO_LARGE 接收到过大的数据帧
1011 Internal Error 客户端由于遇到没有预料的情况而断开链接
1012 Service Restart 服务器重启
1013 Try Again Later 服务器由于临时原因(负载)
1015 TLS Handshake 连接无法完成TLS握手

方法

socket.send(data)

必须在连接建立后才可以发送数据,即open 事件触发后,也可以通过判断readyState 是否等于OPEN 常量,查看连接是否还活着。

data 的数据类型可以是基本的String, Blob, ArrayBuffer, ByteBuffer 等,也可以是子协议商定的自定数据类型

socket.close(code, reason)

使用该方法可以正常关闭连接,code 为状态码,reason 为关闭信息,相关信息同close事件.

升级协商

前面描述过,创建WebSocket 连接时,可以通过protocols 参数进行协商扩展。所以WebSocket 协议具有很大的灵活性,而客户端和服务器先通过HTTP的方式协商适当的参数后才建立连接,完成协商后,所有信息的发送和接收不再后HTTP 相关,而是由WebSocket 协议自身基于TCP连接处理。

协商的过程中,使用了一些 HTTP 头域

客户端发送,表示想使用的 WebSocket 协议版本

客户端自动生成的一个键,以验证服务器支持请求的协议版本

服务器响应,包含Sec-WebSocket-Accept 的签名值,证明支持请求的协议版本

协商应用的子协议,客户端发送支持的协议列表,服务器回应支持的协议名

协商相关的WebSocket 扩展,客户端发送支持的扩展,服务器返回自己支持的扩展

根据HTTP header 的设置,客户端与服务器完成升级协商,后面客户端不再发生HTTP通信 ,由WebSocket 协议接管

应用场景

WebSocket 协议随着HTML5 的发展推进,因为其强大的自定义灵活性,长时连接,双向通信机制,广为应用,但WebSocket 不会取代XHR ,怎么使用,会对浏览器性能产生巨大的影响,我们需要认清该协议的长处,合理分配使用WebSocket 和XHR 。

XHR 是专门为“事务型”请求/响应通信而优化的:依托于完善的HTTP协议, 客户端向服务器发送完整的,格式良好的HTTP 请求,服务器返回完整的响应。WebSocket 是唯一一个能通过同一个TCP连接实现双向通信的协议,客户端和服务器随时可以交换数据,保证低延迟传输。

通信时延大致可以分为四部分:传播时延, 传输时延 ,处理时延, 排队时延 。

无论是什么协议,客户端与服务器的往返次数和传播时延是固定的,但采用不同的协议,可以有不同的排队时延,对XHR 来说,排队时延就是客户端的轮询间隔,而WebSocket 机制,可以在消息可用时立即发送,消除了排队时延,所以总的时延更小。

HTTP 早已实践多年,具有广泛的应用,各种优化机制也已经被浏览器及服务器等设备实施,依托于完善的HTTP ,XHR 自然就继承了这些优秀的特性,而WebSocket 由其特殊性,可以让我们在客户端和服务器间自定义协议,但同样的就不能使用浏览器提供的很多优化服务,应用可能需要自己实现一些基础功能,如缓存,状态管理等。

总的来说,WebSocket 是为实时双向通信而设计的,并提供高效,灵活的文本,二进制数据传输和自定义协议,XHR 是为短时突发性异步通信设计的,依托于完善的HTTP 协议,成熟而稳定。所以选择时需要根据不同的场景选择恰当的通信方式,合理选择,利益这些机制的长处以求得最佳性能。

Socket.IO

由于不同的平台及浏览器版本对WebSocket 支持的不同,有人实现了socket.IO 这个库,提供跨平台实时通信的功能,它不仅是使用WebSocket ,还支持一系列降级功能,我们可以使用它逐渐向WebSocket 转换。

优雅降级

移动端

物理像素/逻辑像素

300延迟

实质:在移动端,当用户点击,分别触发touchstart, touchend, click,同时浏览器判断是否有双击,造成点击事件延迟触发。

点击渗透:假如页面上有两个元素A和B。B元素在A元素之上。我们在B元素的touchstart事件上注册了一个回调函数,该回调函数的作用是隐藏B元素。我们发现,当我们点击B元素,B元素被隐藏了,随后,A元素触发了click事件。

解决

<meta name="viewport" content="user-scalable=no"> <meta name="viewport" content="initial-scale=1,maximum-scale=1">

从URL到页面显示

计算机网络基础

CSS

CSS基础

CSS世界

选择器

  1. *通用选择器:选择所有元素,不参与计算优先级,兼容性IE6+ *
  2. #X id选择器:选择id值为X的元素,兼容性:IE6+ *
  3. .X 类选择器: 选择class包含X的元素,兼容性:IE6+
  4. X Y后代选择器: 选择满足X选择器的后代节点中满足Y选择器的元素,兼容性:IE6+
  5. X 元素选择器: 选择标所有签为X的元素,兼容性:IE6+
  6. :link,:visited,:focus,:hover,:active链接状态: 选择特定状态的链接元素,顺序LoVe HAte, 兼容性: IE4+
  7. X + Y直接兄弟选择器:在X之后第一个兄弟节点中选择满足Y选择器的元素,兼容性: IE7+
  8. X > Y子选择器: 选择X的子元素中满足Y选择器的元素,兼容性: IE7+
  9. X ~ Y兄弟: 选择X之后所有兄弟节点中满足Y选择器的元素,兼容性: IE7+
  10. [attr]:选择所有设置了attr属性的元素,兼容性IE7+
  11. [attr=value]:选择属性值刚好为value的元素
  12. [attr~=value]:选择属性值为空白符分隔,其中一个的值刚好是value的元素
  13. [attr|=value]:选择属性值刚好为value或者value-开头的元素
  14. [attr^=value]:选择属性值以value开头的元素
  15. [attr$=value]:选择属性值以value结尾的元素
  16. [attr*=value]:选择属性值中包含value的元素
  17. [:checked]:选择单选框,复选框,下拉框中选中状态下的元素,兼容性:IE9+
  18. X:after, X::after:after伪元素,选择元素虚拟子元素(元素的后一个子元素),CSS3中::表示伪元素。兼 容性:after为IE8+,::after为IE9+
  19. :hover:鼠标移入状态的元素,兼容性a标签IE4+, 所有元素IE7+
  20. :not(selector):选择不符合selector的元素。不参与计算优先级,兼容性:IE9+
  21. ::first-letter:伪元素,选择块元素第一行的第一个字母,兼容性IE5.5+
  22. ::first-line:伪元素,选择块元素的第一行,兼容性IE5.5+
  23. :nth-child(an + b):伪类,选择前面有an + b - 1个兄弟节点的元素,其中n >= 0, 兼容性IE9+
  24. :nth-last-child(an + b):伪类,选择后面有an + b - 1个兄弟节点的元素 其中n >= 0,兼容性IE9+
  25. X:nth-of-type(an+b):伪类,X为选择器,解析得到元素标签,选择前面有an + b - 1个相同标签兄弟节点的 元素。兼容性IE9+
  26. X:nth-last-of-type(an+b):伪类,X为选择器,解析得到元素标签,选择后面有an+b-1个相同标签兄弟节点 的元素。兼容性IE9+
  27. X:first-child:伪类,选择满足X选择器的元素,且这个元素是其父节点的第一个子元素。兼容性IE7+
  28. X:last-child:伪类,选择满足X选择器的元素,且这个元素是其父节点的后一个子元素。兼容性IE9+
  29. X:only-child:伪类,选择满足X选择器的元素,且这个元素是其父元素的唯一子元素。兼容性IE9+
  30. X:only-of-type:伪类,选择X选择的元素,解析得到元素标签,如果该元素没有相同类型的兄弟节点时选中 它。兼容性IE9+
  31. X:first-of-type:伪类,选择X选择的元素,解析得到元素标签,如果该元素 是此此类型元素的第一个兄弟。 选中它。兼容性IE9+

BFC

创建规则

作用

盒模型

box

块级盒子:占据父容器在内联方向上的全部空间,独占一行,内容会换行

内联盒子:不会换行,不能使用width/height

盒子其实分为两层,外部类型只能为block或inline,但内部类型则不一定,display改变的就是内部类型,inline-block就表示外部为inline、内部为block,其他同理。

Content

通常默认为width和height生效的区域,也可以通过box-sizing: border-box将生效区域修改为Border盒子 ,即实际的内容区域宽高为设置的width(height)-padding-border

对应的CSS属性为Content,取值可接收字符串、url、counter和attr,用以在表现层替代显示内容,但不能SEO和获取选中。Iconfont

多在伪元素方法中使用该属性,因为该属性会将元素转换为替换元素,替换元素本身不支持伪元素,且影响页面一致性(展示和设置不一致)。

Padding

Padding 默认是透明的,不支持负值,可使用百分比,百分比相对元素宽度计算

Padding会影响内联元素的有效区域,但不会影响相邻元素的布局,但如果设置为box-sizing:border-box则会丢失这个特性

Border

可设置线宽,颜色、类型、圆角,线宽不支持百分比

Margin

默认外边距,不参与元素的高宽计算,可使用百分比,相对宽度计算

auto:自动平分父元素的剩余可用空间,多用于块级元素左右居中,对应方向具有自动填充特性,才能实现居中,块级元素流的特性保证了水平方向的自动填充,但不满足垂直方向的自动填充,而绝对定位元素满足了垂直方向的自动填充。

元素固定宽度时,Margin无法改变元素尺寸,当元素为块级元素无宽带流式状态时,Margin会影响元素尺寸

等高布局,让内容高度较少的一边,通过margin-bottom设置了极大的有效区域,再通过padding-bottom补上背景并抵消布局影响

.parent {
    overflow: hidden;
}
.child{
    margin-bottom: -9999px;
    padding-bottom: 9999px;
}

外边距折叠: 在垂直方向上,两个非浮动元素的外边距不会相互推开,而是相互重叠,导致元素内容之间的间距为两个元素中的较大的那个margin值。

display:none与visibility:hidden

联系:它们都能让元素不可见
区别:

继承属性:font, word-break, letter-spacing, text-align, text-rendering, word-spacing, text-indent, text-transform, text-shadow, line-height, color, visibility, cursor

移动端REM/vw/em:基于页面根文档的font-size为基准,其他部分进行自适应

布局

Position

水平/垂直居中

Flex

Grid

响应式布局:根据不同的屏幕尺寸,分配不同的布局,最大化用户体验 @media sreen and ()

自适应布局:页面布局按比例像素级分配放缩

流式布局:应用块级元素流特性布局,无宽度

圣杯布局

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>实现三栏水平布局之圣杯布局</title>
    <style type="text/css">
    .container {
        padding: 0 300px 0 200px;
    }
    .left, .main, .right {
        position: relative;
        min-height: 130px;
        float: left;
    }
    .left {
        left: -200px;
        margin-left: -100%;
        background: green;
        width: 200px;
    }
    .right {
        right: -300px;
        margin-left: -300px;
        background-color: red;
        width: 300px;
    }
    .main {
        background-color: blue;
        width: 100%;
    }
    </style>
</head>
<body>
<div class="container"> 
  <div class="main">main</div> 
  <div class="left">left</div> 
  <div class="right">right</div> 
</div>
</body>
</html>

双飞翼布局

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>实现三栏水平布局之双飞翼布局</title>
    <style type="text/css">
    .left, .main, .right {
        float: left;
        min-height: 130px;
        text-align: center;
    }
    .left {
        margin-left: -100%;
        background: green;
        width: 200px;
    }

    .right {
        margin-left: -300px;
        background-color: red;
        width: 300px;
    }
    .main {
        background-color: blue;
        width: 100%;
    }
    .content{
        margin: 0 300px 0 200px;
    }
    </style>
</head>
<body>
<div class="container"> 
  <div class="main">
      <div class="content">main</div> 
    </div>
  <div class="left">left</div> 
  <div class="right">right</div> 
</div>
</body>
</html>

动画

less

JavaScript

函数执行

执行上下文

事件/函数执行时,它所以来的环境和变量,主要由活动对象,作用域链和this构成

上下文栈:浏览器维护的一个用于调度各种事件及函数的栈

当一个函数或事件可以执行时,将起上下文压入栈,在函数执行之后,将其弹出。正在运行的页面线程中,栈底永远有全局上下文。

函数生命周期
活动对象

又称变量对象为,对应环境为函数环境,包括函数内的所有形参、变量和函数声明,但初始化时只有arguments

作用域链

保存所有父级变量对象的层级链,在函数定义时确定

This

语句执行的主体,依赖于执行环境,而不是定义环境

闭包

使当前函数可以在变量定义的作用域之外,获取到该变量的值。

一般,当函数执行完毕后,局部活动对象会被销毁。而闭包,则通过作用域链保存有父级活动对象参数的特性,通过匿名函数的形式,将其他函数的变量或对象挂载到匿名函数上,而执行函数可在执行时,通过作用域链查找到相应的变量。

具有块级作用域的特点,在ES6之前,唯一能创建作用域的方式就是函数,避免变量污染。

通过闭包可以保护部分变量不被销毁并且重复调用,但同时,会增加内存占用。

垃圾回收

变量在被使用和取消时,会被标记为“进入环境/离开环境”,实质是是否被作用域链引用。

每隔固定事件进行一次清理,清理前先compact,将无用对象聚集在尾部,统一清理,保证内存的连续性。

当一块对象引用为0时,被清除。但存在循环引用的情况导致对象虽然不再使用,但内存不能释放

原型

工厂:无法判断对象类型

构造:对于每个实例,都会创建新的函数方法

原型:原型对象是公共的,一旦修改,其他实例也会被影响

借用构造:父类实例的过程放在子类构造函数中,杜绝了属性污染,但构造函数本身仍有函数服用问题

组合继承:父类在子类构造函数中实例化,同时将子类的原型定义为一个父类的实例,这个过程中父类有两次实例化

寄生组合:引入中间原型,改写constructor保持原型链

// ES 5实现
function Parent(name) {
    this.name = name
}
Parent.prototype.say = function () {
    console.log(`hello, I'm ${this.name}.`)
}

function Child(name, hobby) {
    Parent.call(this, name)
    this.hobby = hobby
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
Child.prototype.express = function() {
    console.log(`hello, I'm ${this.name}, like ${this.hobby}.`)
}

事件

Click, mousedown, touchdown....

事件流

事件代理

基于事件流一层一层传递,而且事件对象内部target可以指向真正的事件目标,从而达到在父级元素上绑定一个事件,可以管理所有子元素对该事件的相同响应

异步

浏览器异步

基础名词

IO:IO只有阻塞/非阻塞的调度方法

阻塞/非阻塞:关注程序等待调用结果时的状态

异步/同步:关注的是消息通信机制

同步执行、阻塞调用很类似,但主要区别在于是否挂起线程,占用CPU资源。阻塞不会挂起,一直占用CPU

上下文:程序的执行环境,执行上下文栈

调度:决定哪个上下文可以获得CPU时间,阻塞/非阻塞。

进程:独立的资源,内存空间,互不干扰

线程:独立的栈,共享同一进程的资源

协程:控制流的主动让出和恢复,依赖于线程执行(Generator),新增了挂起态

协程调度时,保存主栈上下文并挂起,进入协程执行(yield),执行完毕后回到主线程,在JS单线程中,可以视为同步。

浏览器多线程
事件循环

浏览器基于上述多线程并配合事件循环机制进行调度。

在主线程同步代码执行完毕后,浏览器会定期检查各线程是否有事件返回需要执行,需要执行时,将相应的回调放入对于的事件队列中。

每次执行,按照微对队列、宏队列的顺序询问并执行。

发布/订阅


Promise

const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
class mPromise {
    constructor(resolver) {
        if (typeof resolver !== 'function') throw new Error('callback is not a function')
        this.state = PENDING
        this.data = undefined
        this.onResolve = undefined
        this.onReject = undefined
        console.log(resolver)
        resolver(this.onSuccess.bind(this), this.onError.bind(this))
    }

    onSuccess(data) {
        if (typeof data === 'object' && typeof data.then === 'function') {
            data.then(this.onSuccess, this.onError)
        }
        if (this.state === RESOLVED) {
            this.onResolve(data)
        }
        this.data = data
        this.state = RESOLVED

    }

    onError(error) {
        if (this.state === REJECTED) {
            this.onReject.call(this, error)
        }
        this.data = error
        this.state = REJECTED
    }

    then(resolve, reject) {
        if (this.state === RESOLVED) {
            resolve(this.data)
        } else if (this.state === REJECTED) {
            reject(this.data)
        } else {
            this.onResolve = resolve
            this.onReject = reject
        }
        return this
    }
}

Async/Await

在Generator基础上进一步封装,内置执行器,自动进行阻塞,返回值默认为Promise。关键词await启动执行器。

DOM/BOM

Array

返回新数组、修改原数组、对原数组无影响

遍历

forEach:依次遍历数组成员,不返回

map:依次遍历并映射数组成员到新数组,返回新数组

flatMap(mapFunc):数组根据mapFunc对成员映射后,执行一次深度为1的flat,返回新数组

filter(testFunc):返回通过测试的成员组成的新数组

reduce:依次累计遍历元素,返回最后的累计值

reduceRight从末尾开始遍历元素,返回最后的累计值

every(testFunc):测试数组中每一个成员是否都通过testFunc,都通过为true,否则为false

some(testFunc):数组中有一个成员通过testFunc则为true,否则为false

entries:数组键值对的Iterator对象

keys:数组键的Iterator对象

join:返回数组成员组成的字符串

查找

find(testFunc):返回通过测试的第一个元素的值,否则undefined

findIndex(testFunc):返回通过测试的第一个元素的索引,否则-1

includes:判断数组是否包含指定值,否则为false

indexOf:返回数组中第一个指定值的索引,否则-1

lastIndexOf:返回数组中最后一个指定值的索引,否则-1

更新

pop:删除并返回数组最后一个元素

push:在数组末尾添加一个新元素

shift:删除并返回数组第一个元素

unshift:在数组开头添加一个新元素

fill(value, start=0, end=length):以value填充数组

reverse:使数组倒序,并返回新数组

slice(start,end):返回start - end-1的数组

splice:通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。

sort:用原地算法排序 (a,b) < 0 a在前

copyWithin(target, start = 0, end = length):浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。修改原数组

concat(arr1, arr2):返回新的合并数组

flat:返回一个根据指定深度聚合后的新数组

数组扁平化

function flatten(arr) {
        return arr.reduce((prev, curr) => arr.concat(curr instanceof Array ? flatten(curr) : curr), [])
}

数组去重

Array.from(new Set(arr))

正则

跨域

协议、域名、端口号

CORS

JSONP

iframe

postMessage

设计模式

ES6

let/const

都生成块级作用域,const定义一个常量,let定义变量

箭头函数

Set/Map

Set 类似于Array 但不允许重复值,add、delete、has、size;没有下标,元素值就是对应的索引

const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);

Map 类似于Object(字符串-值),但可以使用值-值的键值关系,set、get、delete、has、size

const myMap = new Map()
  .set(true, 7)
  .set({foo: 3}, ['abc']);

// map转数组
[...myMap] 

// map转对象 要求map的键为字符串
function strMapToObj(strMap) {
  let obj = Object.create(null);
  for (let [k,v] of strMap) {
    obj[k] = v;
  }
  return obj;
}


// 数组转Map 要求原数组至少为二维数组
new Map([
  [true, 7],
  [{foo: 3}, ['abc']]
])

// 对象转Map
let map = new Map(Object.entries(obj));

WeakSet/WeakMap 成员只能为对象(具有 Iterator 接口的对象),且内部成员不计入引用计数

Symbol

独一无二的值,接收一个字符串作为描述,多用作键

解构赋值

Promise

Generator

*标示协程函数,yield断点、挂起标志,func.next()执行

async/await

基于Generator封装,函数执行时内部根据await判断挂起

Module

静态加载:代表ES6 Module

运行时加载 代表CommonJS

AMD/CMD/ES6 Module/CommonJS

AMD(requireJs)/CMD(SeaJs)是专用于浏览器端的加载方案

ES6 Module/CommonJS是通用加载方案,ES6 Module是W3C引导的标准方案,CommonJS是Node引导的服务端加载方案,如果用于浏览器,需要提前编译打包,因此在构建工具出现后,也作为通用加载方案应用于浏览器端。

babel

Source -> Tokens -> AST -> polyfill AST -> runtime code

转换规则定义AST-> polypill AST的规则。

语法就是节点的遍历路径,当需要向下兼容时,就是遍历到新版本的语法路径时,将起替换为低版本的语法路径,我们设置的polyfill规则实际上就是确定新版本语法对应的低版本语法路径。

TypeScript

工程函数

防抖

事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行

function debounce(func, wait, immediate) {

    var timeout, result;

    var debounced = function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            // 如果已经执行过,不再执行
            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) result = func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                result = func.apply(context, args)
            }, wait);
        }
        return result;
    };

    debounced.cancel = function() {
        clearTimeout(timeout);
        timeout = null;
    };

    return debounced;
}

节流

如果持续触发事件,每隔一段时间,只执行一次事件。

function throttle(func, wait, options) {
    var timeout, context, args, result;
    var previous = 0;
    if (!options) options = {};

    var later = function() {
        previous = options.leading === false ? 0 : new Date().getTime();
        timeout = null;
        func.apply(context, args);
        if (!timeout) context = args = null;
    };

    var throttled = function() {
        var now = new Date().getTime();
        if (!previous && options.leading === false) previous = now;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            func.apply(context, args);
            if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining);
        }
    };
    return throttled;
}

柯里化

参数复用。本质上是降低通用性,提高适用性。

function curry(fn, args, holes) {
    length = fn.length;

    args = args || [];

    holes = holes || [];

    return function() {

        var _args = args.slice(0),
            _holes = holes.slice(0),
            argsLen = args.length,
            holesLen = holes.length,
            arg, i, index = 0;

        for (i = 0; i < arguments.length; i++) {
            arg = arguments[i];
            // 处理类似 fn(1, _, _, 4)(_, 3) 这种情况,index 需要指向 holes 正确的下标
            if (arg === _ && holesLen) {
                index++
                if (index > holesLen) {
                    _args.push(arg);
                    _holes.push(argsLen - 1 + index - holesLen)
                }
            }
            // 处理类似 fn(1)(_) 这种情况
            else if (arg === _) {
                _args.push(arg);
                _holes.push(argsLen + i);
            }
            // 处理类似 fn(_, 2)(1) 这种情况
            else if (holesLen) {
                // fn(_, 2)(_, 3)
                if (index >= holesLen) {
                    _args.push(arg);
                }
                // fn(_, 2)(1) 用参数 1 替换占位符
                else {
                    _args.splice(_holes[index], 1, arg);
                    _holes.splice(index, 1)
                }
            }
            else {
                _args.push(arg);
            }

        }
        if (_holes.length || _args.length < length) {
            return curry.call(this, fn, _args, _holes);
        }
        else {
            return fn.apply(this, _args);
        }
    }
}

Node

RESTful

一种架构设计风格,特定规则的设计原则和约束条件。前后端基于固定的方式交换数据,进行CURD

GraphQL

将请求归类为查询动作Query Mutation Subscribe ,类似数据库语法,但数据库表应基于数据内聚性设计,而接口服务是面向应用设计。

框架

Koa2和Express

Squelize

数据库ORM

var sequelize = new Sequelize('database', 'username', 'password', {
  host: 'localhost',
  dialect: 'mysql'|'mariadb'|'sqlite'|'postgres'|'mssql',

  pool: {
    max: 5,
    min: 0,
    idle: 10000
  },

  // 仅 SQLite 适用
  storage: 'path/to/database.sqlite'
});

Buffer

Stream

Process

工程化

MV*

Vue与React 异同

生命周期

Vue生命周期

vue生命周期

React生命周期

react生命周期

数据流
通信

父->子:Props Vue(Provide, inject)

子->父:Vue(emit) React(props.parentFunc)

兄弟:Vue(Bus.js(new Vue)) React(HOC)

状态管理

单一数据源,纯函数reducer接收action标示执行状态改变操作

吸收flux思想,并进一步封装以更符合Vue的状态管理

Diff
Router

主要依赖location和history api

Vue

vuex

React

小程序

Webpack

基础配置

主要就是4个配置项,entry、output、loader、plugin

entry: 项目的整体入口,也是需要打包的入口,根据该入口及其引用的对象进行打包

output:打包后的文件出口

loader:针对不同类型文件的处理和打包,偏向语法。需要单独安装

plugin:等效于webpack的生命周期钩子,对处于不同处理阶段的文件进行管理。常用功能集成在了webpack.optimize

{
        entry: path.join(__dirname, 'src/index.js'),
        output: {
                path: path.join(__dirname), "./dist"),
                filename: "bundle-[hash].js"
        },
        mode: "production"  // 环境
        module: { //配置loader
                rules: [
                        {
                test: /\.js?$/, //正则匹配文件
                use: [
                    {
                        loader: 'babel-loader'
                    }
                ],// 从下往上、从右往左应用loader处理
                exclude: /node_modules/  //跳过的文件夹
            },
                ]
        },
        plugin: {  //配置plugin
                new CleanWebpackPlugin(
            ['*'],
            {root: outPath}
        ),
        }
        devServer: {
            contentBase: './public', // 本地服务器所加载的页面所在的目录
            historyApiFallback: true, // 单页面应用路由切换时不跳转
            inline: true, // 实时刷新
            port: 8080, //启动时的端口号
            proxy: { //代理配置
                '/api': { // 如果接口中带有 API 标志,那么就需要开始代理
                        target: 'http://localhost:8001',
                        changeOrigin: true,  // target 是域名的话,需要这个参数,
                        secure: false  // 设置支持 https 协议的代理,不检查安全与否
                }
            }
    }
}

Gulp

const gulp = require("gulp")
const pm2 = require("pm2")
const babel = require("gulp-babel")
const webpack = require("webpack")

const config = require("./webpack.build.config")

let path = {
    babel: "./src/controller/**/*.js"
}

gulp.task("build", (cb) => {
    webpack(config, (err) => {
        if (err) {
            console.error(err)
        }
    })
    return cb()
})

gulp.task("server", () => {
    return gulp.src(["./config.json", "./src/app.js"])
    .pipe(gulp.dest("./build"))
})

gulp.task("babel", () => {
    return gulp.src(path.babel)
    .pipe(babel())
    .pipe(gulp.dest("./build/controller"))
})

gulp.task("pm2", ["babel"], (cb) => {
    pm2.connect(() => {
        pm2.start("./server.dev.js", {name: "server", watch: true}, (err) => {
            if (err) {
                pm2.disconnect();
            }
        })
        return cb()
    })
})

gulp.task("development", ["babel", "pm2"], () => {
    gulp.watch(path.babel, ["babel"])
})

gulp.task("production", ["babel", "server", "build"])

PM2

性能优化

算法

Web 安全

Nginx

反向代理服务器,就是请求代理,解析请求的域名、端口,将请求转发到相应的代理服务器或服务

代理

个人使用多使用基于域名代理,将子域名请求分别发往不同的本机端口

server {
        #监听端口
        listen       80;

        #域名可以有多个,用空格隔开
        server_name  blog.lizardlove.ren;

        #默认编码
        #charset utf-8;

        #定义本虚拟主机的访问日志
        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
            proxy_redirect off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:99999;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

负载均衡

多个端口/服务器可处理相同的服务,根据服务器的负载情况,将请求发往不同的端口或服务器

server {
        ...
        upstream backserver {
                ip_hash; //处理带session的请求,同一个客户端的请求会发往相同的处理服务器
                server 192.168.0.10:88 weight=3; //权重越高,访问的概率越大
                server 192.168.0.10:90 weight=2;
                server 192.168.0.11:90 weight=5;
                fair;   //按服务器的响应时间分配,响应时间短的优先

        }
}

The Last

你有什么想问的?