Git Product home page Git Product logo

knowledge-network's Introduction

Hi there 👋

Anurag's GitHub stats

knowledge-network's People

Contributors

gitbook-bot avatar palmerye avatar

Watchers

 avatar  avatar

knowledge-network's Issues

SQL notes

什么是数据库

一般用过电脑的人,都对Excel不陌生。Excel是一张二维表格,通过行列来记录和描述数据。简单来说,类比在数据库中,也是一张张表,区别在于,数据库中的多张表是可以相互联系的。所以粗暴地理解数据库,就是多张表+各表之间的关系

所以我们学习的方向可以这样:

  1. 数据库表的结构
  2. 各表之间的关系

参考

如何学习 SQL 语言? - 猴子的回答 - 知乎

《SQL入门经典》
《SQL必知必会》

不要再问我什么是闭包了

闭包使得函数可以继续访问定义时的词法作用域。

保持对函数定义时的词法作用域的引用,这个引用就是闭包。

像轮子哥说的,什么是闭包? - 知乎用户的回答 - 知乎,闭包就是封闭外部状态,而不是封闭内部状态。即函数定义时外部的词法作用域失效时(js引擎的垃圾回收器考虑回收它),但由于这个词法作用域被内部其他函数引用,无法被回收,所以这个外部状态就被保留了下来,这就是所谓的封闭外部状态。

闭包就是一个引用,该函数在定义时的词法作用域scope以外执行时,因为有了这个引用(闭包),使得该函数能继续访问定义时的词法作用域scope

function foo() {
    var a = 2
    function bar() {
        console.log(a);
    }     
    return bar
}
var cat = foo()
cat() // 2

看这个栗子:

for (var i = 1; i <= 5; i++) {
    setTimeout(function timer() {
        console.log(i)
    }, i*100);
}

// result: 6 6 6 6 6 

看这段代码的语义,是想输出1 2 3 4 5 ,实际则不然。这里的 i 都被封闭在外部(全局作用域)中,因此只有一个 i 。由于定时器回调函数式在循环结束后执行,这时i为6,因此回调函数中输出的是i=6.因此要解决这个问题,我们必须在每一次循环迭代中有自己的作用域。我们做以下尝试:

for (var i = 1; i <= 5; i++) {
    (function () { // 这里用了一个IIFE,在每次迭代中创建封闭的作用域
        setTimeout(function timer() {
            console.log(i)
        }, i*100);
    })()
}

// result: 6 6 6 6 6 

但为什么还是存在问题呢,因为这个封闭的作用域中,仍旧是循环结束后执行(i=6),该作用域中的i并没有被封闭起来。那我们再改造下,把封闭作用域中的i存起来。

for (var i = 1; i <= 5; i++) {
    (function (i) {
        setTimeout(function timer() {
            console.log(i)
        }, i*100);
    })(i)
}

// result: 1 2 3 4 5

CSS 篇

px pt em rem vh vw 的区别

  • px:像素,与显示设备有关,通常是一个设备像素点
  • pt:磅,1 pt = (1 / 72) in, 1 in = 96 px,3 pt = 4 px
  • em1em 等于元素的父元素的字体大小,假设设置 body { font-size: 20px; },那么1em = 20px
  • rem ( root em ):CSS3 单位,只是相对 HTML 根元素,假设设置 html{ font-size: 10px; },那么1rem = 10px
单位 解释
vw 1vw = 视口宽度的1%
vh 1vh = 视口高度的1%
vmin 选取vw和vh中最小的那个
vmax 选取vw和vh中最大的那个

SASS / LESS / Stylus / CSS Module

BFC

Block formatting context直译为"块级格式化上下文",BFC是一个容器,用于管理块级元素。

特性

  • 内部的Box会在垂直方向,一个接一个地放置(即块级元素独占一行)。
  • BFC的区域不会与float box重叠(利用这点可以实现自适应两栏布局)。
  • 内部的Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠(margin重叠三个条件:同属于一个BFC;相邻;块级元素)。
  • 计算BFC的高度时,浮动元素也参与计算。(清除浮动 haslayout)
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。

触发

  • float为 left|right
  • overflow为 hidden|auto|scroll
  • display为 table-cell|table-caption|inline-block|inline-flex|flex
  • position为 absolute|fixed
  • 根元素

linear-gradient

background: linear-gradient(direction, color-stop1, color-stop2, ...);
描述
direction 用角度值指定渐变的方向(或角度)。
color-stop1, color-stop2,... 用于指定渐变的起止颜色。

JavaScript 异步编程

回调函数

function f1(callback) {
    setTimeout(function () {
        console.log('f1')
        callback()
    }, 1000)
}

function f2() {
    console.log('f2')
}
f1(f2)

手写Promise

Vue

生命周期

beforecreated

el 和 data 并未初始化

created

完成了 data 数据的初始化,el 不可见

beforeMount

完成了 el 和 data 初始化

mounted

完成挂载

beforeUpdate 和 updated

数据改变——导致虚拟DOM的改变——调用这两个生命钩子去改变视图,这个数据只有和模版中的数据绑定了才会发生更新。

beforeDestory 和 destoryed

在beferoDestory生命钩子调用之前,所有实例都可以用,但是当调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

举栗

let vm = new Vue({
  el: '#app',
  data: {
    message: 1
  },
  template: '<div id="app"><p>{{message}}</p></div>',
  beforeCreate() {
    console.log('调用了beforeCreate')
    console.log(this.message)
    console.log(this.$el)
  },
  created() {
    console.log('调用了created')
    console.log(this.message)
    console.log(this.$el)
  },
  beforeMount() {
    console.log('调用了beforeMount')
    console.log(this.message)
    console.log(this.$el)
  },
  mounted() {
    console.log('调用了mounted')
    console.log(this.message)
    console.log(this.$el)
  },
  beforeUpdate() {
    console.log('调用了beforeUpdate')
    console.log(this.message)
    console.log(this.$el)
  },
  updated() {
    console.log('调用了updated')
    console.log(this.message)
    console.log(this.$el)
  },
  beforeDestory() {
    console.log('调用了beforeDestory')
    console.log(this.message)
    console.log(this.$el)
  },
  destoryed() {
    console.log('调用了Destoryed')
    console.log(this.message)
    console.log(this.$el)
  }
})

vm.message = 2
// 调用了beforeCreate
// undefined
// undefined
// 调用了created
// 1
// undefined
// 调用了beforeMount
// 1
// <div></div>
// 调用了mounted
// 1
// <div id="app"><p>1</p></div>
// 调用了beforeUpdate
// 2
// <div id="app"><p>2</p></div>
// 调用了updated
// 2
// <div id="app"><p>2</p></div>

使用场景

  • beforecreate : 举个栗子:可以在这加个loading事件
  • created :在这结束loading,还做一些初始化,实现函数自执行
  • mounted : 在这发起后端请求,拿回数据,配合路由钩子做一些事情
  • beforeDestroy: 你确认删除XX吗? destroyed :当前组件已被删除,清空相关内容

组件通信

父子通信 props

Vue.component('child', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})

// parent component
<child title="My journey with Vue"></child>

子父通信 $emit

兄弟通信

  • 空Vue实例,eventBus
  • vuex

Tips

Vue为什么不能检测数组变动

实现双向绑定MVVM

Node notes

一些听起来很酷的词儿

BFF(Backends For Frontends)

2015 年,Sam Newman 提出了 Pattern: Backends For Frontends,为了适应体验者API(高频变更)。其中原则之一是服务自治,谁使用谁开发,即它应该由前端同学去维护。

v2-50720e139878624f394dcf2d3de836fb_r

RPC(Remote Procedure Call)

远程过程调用

BaaS(Backend as a Service)

DIRT(data-intensive real-time)

数据密集型实时持程序

I/O 操作

其关键点是要将应用程序的IO操作分为两个步骤来理解:IO调用(由进程发起)和IO执行。IO调用才是应用程序干的事情,而IO执行是操作系统的工作。

在IO调用时,对待操作系统IO就绪状态的不同方式,决定了其是阻塞或非阻塞模式;在IO执行时,线程或进程是否挂起等待IO执行决定了其是否为同步或异步IO。

Redis 缓存

先来从最简单的场景来看为什么要有 Redis 缓存这个东西。

  1. 这里有一个请求数据量很大,用户在客户端请求接口时SQL查询需要花费很多时间,为了解决这个问题,我们可以尝试基于HTTP的缓存机制 cache-control,但在缓存时间内,用户可能得到旧数据。×
  2. 那怎么办,简单粗暴地放在api服务器内存里吧,同样也可以设置缓存时间,但弊端是,api服务器内存要炸了... ×
  3. 咦?那就专门搞一台服务器来消耗这些缓存,把这台服务器内存搞的大大的。Radis 就这样来了。√

特性

  • 持久化(Persistence)
    • 为了保证api服务器和数据库的减负,Radis服务不能说崩就崩啊,一旦崩了,缓存(放在内存里)不就没了么,所以要保证这台服务器的持久性,所以这里的持久化指的是,把缓存放在硬盘里,这样重启后依然能用是功能一次的缓存。
  • 哨兵(Sentinel)
  • 复制(Replication)
  • 集群(Cluster)

CAS

CAS(Central Authentication Service)是耶鲁大学的一个开源项目,旨在为web应用系统提供一种可靠的单点登录(SSO)解决方案。

票据

  • TGT:Ticket Grangting Ticket
    • 授权票据,获取这TGT之后才能申请服务票据(ST),用户如果在CAS系统认证成功之后,就会生成TGC写入浏览器,同时也生成一个TGT,TGT对象的id就是cookie值。之后每次请求过来通过此cookie来从缓存获取TGT,就不用提交身份认证信息(Credentials)
  • TGC:Ticket Granted Cookie
    • CAS系统用来识别用户身份的凭证
  • ST:Service Ticket
    • 服务票据,服务的唯一标识码,由TGT生成ST,返回给用户,接着拿着生成的ST去访问service,service又会把ST拿到CAS系统去验证,验证通过后才允许用户访问该资源

Node.js 特性

单线程、非阻塞、异步I/O

开发工具

服务端开发思维

  • MVC 模式
    • Model(ORM):数据层,在Node中(ORM是一种将数据库操作抽象成语言原生对象操作的方法工具),Model通过一个ORM抽象成对象
    • View:视图层,一般用模板引擎来渲染数据为页面
    • Controller:负责连接数据和视图,但一般不会直接操作数据,而是由service层控制业务逻辑,controller来组装各个service提供的数据,返回给视图
  • Service 层:抽象数据操作,包含大部分业务逻辑,给controller提供“操作”
  • Route:定义了请求应该进入哪个controller,便于管理

JavaScript 设计模式

单例模式

顾名思义,单例就是单个实例,一个类只有一个实例。即使多次实例化该类,也只返回第一次实例化后的实例对象,能减少不必要的内存开销, 并且也能减少全局的函数和变量冲突。

经典算法

VisuAlgo:通过动画学习算法和数据结构。VisuAlgo 源自 Steven Halim 博士的一个工具,用于帮助他的学生更好理解学习数据结构和算法。
https://visualgo.net/zh

UI架构设计--MVC/MVP/MVVM

MVC

MVC的其中一个缺点便是没有明确的定义,所以不同的实现(比如Struts和ASP.NET MVC)细节上都是不一样的。MVC一般的流程是这样的:View(界面)触发事件 --> Controller(业务)处理业务,触发了数据更新 --> 更新Model的数据 --> Model(带着数据)回到了View --> View更新数据

在经典MVC中,controller是用户和系统之间的链接;但在现代的UI系统中,其中controller的功能已经意义不大了。

MVP

对比MVC

可见,MVP和MVC的依赖关系图应该是一样的,Model-View-Presenter是在MVC的基础上,进一步规定了Controller中的一些概念而成的,所以presenter它就是一种controller。

MVVM

MVVM中最重要的概念是数据绑定,用双向绑定的方式替代了MVC和MVP中的view和model的互相通讯,这进一步把逻辑代码变成了声明模式。

前端UI框架演变史

参考:
Winter大大写的文章:《谈谈UI架构设计的演化》
你对MVC、MVP、MVVM 三种组合模式分别有什么样的理解? - Indream Luo的回答 - 知乎

this 指向

this 指向哪儿

一句话总结在前,在 JavaScript 中,this 永远指向最后调用它的那个对象。

在js红皮书中关于this的说法是,this对象是在运行时基于函数的执行环境绑定的。说的很明确,运行时函数的执行环境,那我们先来看看这些是个啥。

  • 上下文:简单点说是程序执行的环境,严谨点说,指的是程序运行必要的外部变量的集合。轮子哥在知乎的回答
  • 执行环境:(execution context,简称为环境)也叫执行上下文,每当程序的执行流进入到一个可执行的代码时,就进入到了一个执行环境中。

Git nodes

合并分支(多个commit为一个commit)

git merge dev --squash 
git commit -m "xxx"

JavaScript 字符串

JavaScript中有5种基本数据类型,分别是Undefined、Null、Boolean、Number、String,还有一种复杂数据类型Object,对象实质上就是属性的集合。在JavaScript中不能直接访问内存中的位置,因此JavaScript在操作对象时,实际上是在操作对象的引用。所以之所以字符串string这个基本数据类型,有substring()等对象方法,是因为JavaScript在读取基本数据值的时候,会创建一个对应的基本包装类型对象,这个对象上有一些扩展方法。

字符方法

  • charAt(n) 返回第n个字符
  • charCodeAt(n) 返回第n个字符编码

字符串操作方法

  • concat() 拼接字符串
    • oldValue.concat('new value')
  • slice(x, y) x代表起始位置,y代表终止位置(若空则默认返回最后位置),并返回子字符串
    • value.slice(1, 5)
  • substring(x, y) 同上
  • substr(x, y) y代表返回字符个数
  • trim() 去除value前后空格后返回
  • trimLeft() 删除前面的空格
  • trimRight() 删除后面的空格
  • toLowerCase() 转化为小写
  • toUpperCase() 转化为大写

字符串位置方法

  • indexOf(a, x)value中搜索a,起始搜索位置为x,然后向后搜索,返回第一个结果下标
  • lastIndexOf(a, x)value中搜索a,起始搜索位置为x,然后向前搜索,返回第一个结果下标

字符串正则

  • match() 只接收一个参数,正则表达式或者是RegExp对象

比较字符串大小

  • localeCompare()
    • value.localeCompare(tovalue) 比较value和tovalue的字符串大小,若value排在tovalue前,则返回-1,否则返回1,相等返回0

HTML 篇

Doctype 作用

Doctype 声明告诉浏览器应该按照什么规则集解析文档,其中,DTD 叫文档类型定义,里面包含了文档的规则,浏览器就根据你定义的 DTD 来解释你页面的标识。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
// xhtml1-transitional.dtd 属于 transitional 过渡的,还有,严格的(Strict),框架的(Frameset)

HTML5 只需要 <!DOCTYPE HTML>,因为 HTML5 不基于 SGML,而 HTML4.01 基于SGML,所以需要引用DTD

行内元素/块级元素/空(void)元素

  • 行内元素:a b i span img input select strong textarea
  • 块级元素:div ul ol li dl dt dd h1 h2 h3 h4…p section table
  • 空(void)元素:<br> <hr> <img> <input> <link> <meta>

块级元素与行内元素的区别

  1. 块级元素会独占一行,其宽度自动填满其父元素宽度;行内元素不会独占一行,相邻的行内元素会排列在同一行,直至一行排不下才会换行,其宽度随元素的内容而变化。
  2. 块级元素可以包含行内元素和块级元素;行内元素不能包含块级元素。
  3. 行内元素设置 width、height、margin-top、margin-bottom、padding-top、padding-bottom 无效。

标签脚本

defer 延迟

遇到defer脚本立即下载,但不立即执行,整个页面解析完成后运行,按出现的先后顺序执行,但实际不一定在DOMContentLoaded事件触发前执行

async 异步

与defer脚本类似,但不能保证其顺序;且,async脚本一定会在load事件前执

Canvas 集合

准备环境:渲染上下文

// html,这里要注意,canvas的宽高要在节点上设置,默认值为300和150,单位为px,若在css中设置,则会使坐标系拉伸
<canvas id="demo" width="100" height="100"></canvas>

const CANVAS = document.getElementById('demo')
const ctx= CANVAS.getContext('2d')  // 也可以是3d环境,则调用 WebGL, getContext('webgl')

绘制矩形

canvas 2d坐标系是以左上角为原点,x向右y向下递增

// 绘制一个填充的矩形
fillRect(x, y, width, height)

// 绘制一个矩形的边框
strokeRect(x, y, width, height)

// 清除指定的矩形区域,然后这块区域会变的完全透明
clearRect(x, y, widh, height)

绘制路径

canvas 只支持一种原生的图形绘制:矩形。所有其他图形都至少需要生成一种路径 path

  1. 创建路径起始点
  2. 调用绘制方法去绘制出路径
  3. 把路径封闭
  4. 路径生成,通过描边或填充路径区域来渲染图形。

线段

ctx.beginPath() // 新建一条path
ctx.moveTo(50, 50) // 把画笔移动到指定的坐标
ctx.lineTo(70, 50)  // 绘制一条从当前位置到指定坐标(200, 50)的直线.
ctx.closePath()
ctx.stroke() // 绘制路径

ctx.setLineDash([5,15]) 绘制虚线,括号里的数组为虚线间隔

三角形

同理可得,多次 lineTo(x, y)可以绘制各式各样的路径形状

ctx.beginPath() // 新建一条path
ctx.moveTo(50, 50) // 把画笔移动到指定的坐标
ctx.lineTo(70, 50)  // 绘制一条从当前位置到指定坐标(70, 50)的直线.
ctx.lineTo(70, 90)  // 绘制一条从当前位置到指定坐标(70, 90)的直线.
ctx.closePath()
ctx.stroke() // 绘制路径,填充则为 ctx.fill()

圆弧

  • arc(x, y, r, startAngle, endAngle, anticlockwise)
    • 以(x, y)为圆心,以r为半径,从 startAngle弧度开始到endAngle弧度结束。anticlosewise是布尔值,true表示逆时针,false表示顺时针。(默认是顺时针)
  • arcTo(x1, y1, x2, y2, radius)
    • 两条切线之间的圆弧
ctx.beginPath() // 新建一条path
ctx.arc(50, 50, 40, 0, Math.PI / 2, false)
ctx.stroke() // 绘制路径,填充则为 ctx.fill()

保存状态

save()restore()

save()保存当前Canvas画布状态并放在栈的最上面,可以使用restore()方法依次取出。

绘图效果本身不会被保存,保存的只是绘图状态,包括:

  • 当前矩阵变换。transform()
  • 当前剪裁区域。clip()
  • 当前虚线设置。setLineDash()
  • 以及下面这些属性的值:strokeStyle,fillStyle,globalAlpha,lineWidth,lineCap,lineJoin,miterLimit,lineDashOffset,shadowOffsetX,shadowOffsetY,shadowBlur,shadowColor,globalCompositeOperation,font,textAlign,textBaseline

Tips

1px线条模糊问题

曲线折线锯齿现象

https://www.canvasapi.cn

理解CSS3 transform中的Matrix(矩阵)

globalCompositeOperation 设置Canvas图形的混合模式

优雅JavaScript

JavaScript 复杂判断的更优雅写法

函数防抖与函数节流

函数防抖与函数节流

  • 函数防抖 debounce:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
    • search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
    • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
handleResize (fn, delay = 0) {
    let timer = null
    return () => {
        clearTimeout(timer)
        timer = setTimeout(() => {
           fn()
        }, delay)
    }
}
  • 函数节流 throttle:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
    • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
    • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
handleResize (fn, delay = 0, atleast = 0) {
    let timer = null
    let previous = null
    return () => {
        let now = +new Date()
            if (!previous) {
                previous = now
            }
           if (now - previous > atleast) {
                fn()
                previous = now
           } else {
                clearTimeout(timer)
                timer = setTimeout(() => {
                    fn()
                }, delay)
          }
    }
}
  • 区别:
    • 函数防抖和函数节流都是防止某一时间频繁触发,但是这两兄弟之间的原理却不一样。
    • 函数防抖是某一段时间内只执行一次,而函数节流是间隔时间执行。

最直观的表现防抖和节流的区别

JavaScript 数组

创建数组

  • Array构造函数
    • var array = new Array()
  • []数组字面量
    • var array = []

检测数组

  • instanceof
    • if(value instanceof Array) ...
  • isArray
    • if(Array.isArray(value)) ...

转换方法

  • toLocaleString()
    • 返回数组每个值以逗号分隔的字符串,实际上是调用每一项的toLocaleString()方法
  • toString()
    • 返回数组每个值以逗号分隔的字符串,实际上是调用每一项的toString()方法
  • valueOf()
    • 返回数组本身
  • join()
    • join()传递的符号,可以得到以该符号分隔的字符串

数组操作

栈(后进先出)

  • push()
    • 推入数组末尾
  • pop()
    • 移除数组末尾项,并返回该项

队列(先进先出)

  • unshift()
    • 推入数组头部
  • shift()
    • 移除数组头部项,并返回该项

排序

  • reverse()
    • 反序
  • sort()
    • 先调用每一项的toString()方法,然后比较字符串大小(转成ASCII码)
    • function compare(v1, v2) { v1比v2小返回负数, v1比v2大返回正数,相等返回0 } values.sort(compare)

新增 contat()

先创建当前数组的一个副本,然后将接收到的一个或多个数组push到当前数组,然后返回新数组。

删除/插入/替换 splice()

  • 删除
    • 指定两个参数:要删除的第一项位置及要删除的项数。如value.splice(0, 2)可删除前两项
  • 插入
    • 指定三个参数:起始位置,要删除的项数(0),要插入的项。如value.splice(1, 0,'item1', 'item2')可在第一项后插入两项,返回新数组
  • 替换
    • 指定三个参数:起始位置,要删除的项数,要插入的项。如value.splice(2, 1,'item1', 'item2')可删除当前数组位置2的项,再从位置2插入后两项,返回新数组

查找

  • indexOf()
    • 从前往后查找该项的位置,一旦匹配,则立即返回该项的索引,找不到返回-1
  • lastIndexOf()
    • 从后往前查找该项的位置,一旦匹配,则立即返回该项的索引

迭代

  • every()
    • 用于查询数组中的项是否满足某个条件,必须每一项都满足,则返回true
  • some()
    • 同上,但只要其中一项满足就返回true
  • filter()
    • 用于过滤数组中的符合条件项,并返回符合条件项组成的新数组
  • map()
    • 在数组的每一项中运行传入函数的结果,返回新数组,如给数组每一项乘以2,然后返回新数组。
  • forEach()
    • 单纯地遍历数组项,类似for循环
  • reduce()
    • 函数接收4个参数:前一项,当前项,项索引,数组对象。如:value.reduce(function(prev, cur, index, array){return prev + cur})可执行数组所有值求和,第一次迭代发生在数组的第二项,因此prev 为第一项,cur 为第二项
  • reduceRight()
    • 同上,方法相反

HTTP 网络篇

TCP/IP 协议

http.png

  • 应用层:向用户提供应用服务的通信活动,FTP、DNS、HTTP都在这一层
  • 传输层:提供两台计算机之间的数据传输,包括 TCP 传输控制协议、UDP 用户数据报协议
  • 网络层:处理网络上的数据包,规定传输路线
  • 链路层:处理连接网络的硬件部分

e.g. HTTP

  1. 客户端发出一个HTTP请求(应用层)
  2. 将HTTP请求报文进行分割,打上标记后(TCP首部)转给下一层(传输层)
  3. 将上面的数据包加上(IP首部:包括MAC地址)转发给链路层(网络层)
  4. 接收端(加上以太网首部)收到数据(链路层)

三次握手

snipaste20180910_170709.png

  1. 发送端发送一个带SYN(synchronize)标志的数据包
  2. 接收端收到后,返回一个带有SYN/ACK(acknowledgement)标志的数据包,表达确认收到
  3. 发送端再传回一个带ACK标志的数据包,握手结束

四次挥手

Client和Server发起均可断开连接请求,以Client为例

  1. Client发起断开请求,发送FIN标志,Client进入FIN_WAIT_1状态
  2. Server收到请求,发送ACK回应,表示已经收到断开请求,Server进入CLOSE_WAIT状态
  3. 但此时可能还有数据在传输,不能立即断开,需等待数据传完后,发送FIN告诉Client可以断开了,Server进入LAST_ACK状态
  4. Client收到FIN,进入TIME_WAIT状态,回应ACK,Server进入Close状态,挥手结束

为什么连接的时候是三次握手,关闭的时候却是四次握手?

简单的说,原因是TCP是全双工的,每个方向都必须要单独进行关闭。主动方发起断开请求,被动方收到断开请求时,回应ACK,等待数据传输完,再回应FIN。所以是多了等待前回应的这一次。

HTTPS

HTTP缺点:

  • HTTP 本身不具备加密的功能,HTTP 报文使用明文方式发送
  • 可以伪装客户端 / 服务端
  • 中间人攻击(Man-in-the-Middle attack,MITM)

HTTPS经由HTTP进行通信,利用SSL/TLS来加密数据包,具有非对称加密的可靠性和对称加密的高效性

网络攻击

XSS 跨站脚本攻击(Cross Site Scripting)

在浏览器运行非法的HTML标签或者JavaScript,是一种攻击者利用预先设置的陷阱触发的被动攻击

防御:设置 httpOnly;字段过滤;

CSRF 跨站点请求伪造(Cross-Site Request Forgeries)

一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法

3636937-b8ba0dd4bc821bdd.jpg

防御

  • 验证HTTP Referer字段
  • 添加token验证
  • 验证码
  • 尽量使用POST,限制GET
  • 在HTTP头部添加自定义属性

代理

代理其实就是在client端和真正的server端之前增加一层提供特定服务的服务器,即代理服务器proxy

正向代理

客户端和代理服务器可以直接互相访问,属于一个LAN(局域网);代理对用户是非透明的,即用户需要自己操作或者感知得到自己的请求被发送到代理服务器;代理服务器通过代理用户端的请求来向域外服务器请求响应内容。

反向代理

代理服务器和真正server服务器可以直接互相访问,属于一个LAN(服务器内网);代理对用户是透明的,即无感知。一般用于安全及权限和负载均衡。

区别

正向代理是代理客户端,为客户端收发请求,使真实客户端对服务器不可见;而反向代理是代理服务器端,为服务器收发请求,使真实服务器对客户端不可见。

浏览器 🌐

在浏览器输入URL后发生了什么?

  1. DNS域名解析成IP地址
  2. 三次握手建立连接,发送请求
  3. 服务器返回HTTP响应,到浏览器进行解析

1.DNS解析

当用户在浏览器输入一串url地址,先从本地DNS服务器找缓存,若没有,则用递归或者迭代查询的方式向根域名服务器、顶级域名服务器、权威域名服务器查询IP地址,返回给浏览器

2.HTTP请求

#1

3. 浏览器解析

  1. 返回的HTML 自上而下,经过词法分析、语法分析构建DOM树
  2. 期间若遇到CSS外链,则异步请求资源,并不阻塞DOM树构建

若遇到JS外链,由于JS可能会造成回流和重绘,因此会阻塞DOM树构建

  1. CSS资源下载完毕后,经过词法分析、语法分析构建CSSOM树

无论是DOM还是CSSOM,都是要经过Bytes → characters → tokens → nodes → object model这个过程。

  1. 合并DOM树和CSS规则,生成render树
  2. 布局render树(Layout/reflow),负责各元素尺寸、位置的计算
  3. 绘制render树(paint),绘制页面像素信息
  4. 浏览器会将各层的信息发送给GPU,GPU将各层合成(composite),显示在屏幕上

跨域

浏览器端的跨域问题,来源于它的安全策略:同源政策 same-origin policy。

同源指的是:

  • 协议相同
  • 域名相同
  • 端口相同

解决跨域问题:

  1. 设置document.domain

两个网页一级域名相同,二级域名不同时,设置document.domain,且仅适用于 Cookie 和 iframe 窗口

  1. hash路由变更,子窗口hashchange监听
  2. window.postMessage() 两个不同源窗口通信
  3. JSONP 动态添加script标签,在回调函数传参
  4. websocket 不受同源策略影响
  5. CORS跨域(W3C标准 Cross-origin resource sharing)
    • 简单请求:
    • 复杂请求:发出预检请求(OPTIONS),当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 动词和头信息字段。一旦服务器通过了“预检”请求,以后每次浏览器正常的 CORS 请求,就都跟简单请求一样,会有一个Origin头信息字段。

浏览器内核

浏览器内核又可以分成两部分:渲染引擎(layout engineer 或者 Rendering Engine)和 JS 引擎。它负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入 CSS 等),以及计算网页的显示方式,然后会输出至显示器或打印机。JS 引擎则是解析 Javascript 语言,执行 javascript 语言来实现网页的动态效果。最开始渲染引擎和 JS 引擎并没有区分的很明确,后来 JS 引擎越来越独立,内核就倾向于只指渲染引擎。

  • Trident内核:IE 360, 搜狗浏览器
  • Gecko内核:Firefox
  • Presto内核:Opera7及以上 [Opera内核原为:Presto,现为:Blink ]
  • Webkit内核:Safari, Chrome [ Chrome的:Blink(WebKit的分支)]

localStorage, sessionStorage, Cookie, Session

localStorage / sessionStorage

  • 相同点

    • 存储大小均为5M左右
    • 同源策略限制
    • 仅在客户端中保存,不参与和服务器的通信
  • 不同点

    • 生命周期:localStorage: 存储的数据是永久性的,除非用户人为删除否则会一直存在;sessionStorage: 与存储数据的脚本所在的标签页的有效期是相同的,一旦窗口或者标签页被关闭,存储的数据也会被删除。
    • localStorage: 在同一个浏览器内,同源文档之间共享 localStorage 数据,可以互相读取、覆盖;sessionStorage 的作用域还被限定在了窗口中,也就是说,只有同一浏览器、同一窗口的同源文档才能共享数据,比如同一窗口中的两个同源的iframe元素,他们的 sessionStorage是可以共用的。

Cookie

  • 大小限制为4KB左右
  • 一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效
  • 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题

Session

每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,服务器就知道该用户的身份了。

  • Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
  • Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。

维持一个会话的核心就是客户端的唯一标识,即 session id

浏览器缓存

  1. 浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强缓存,强缓存如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器。比如某个css文件,如果浏览器在加载它所在的网页时,这个css文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个css,连请求都不会发送到网页所在服务器;
  2. 当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些http header验证这个资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回,但是不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源;
  3. 强缓存与协商缓存的共同点是:如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;区别是:强缓存不发请求到服务器,协商缓存会发请求到服务器。
  4. 当协商缓存也没有命中的时候,浏览器直接从服务器加载资源数据。

浏览器进程

浏览器是多进程的,新开一个tab页,基本上浏览器会新起一个进程(不排除有优化合并多个进程的可能)

  • 浏览器主进程:
    • 负责浏览器界面显示,与用户交互。如前进,后退等
    • 负责各个页面的管理,创建和销毁其他进程
    • 将Renderer进程得到的内存中的Bitmap,绘制到用户界面上
    • 网络资源的管理,下载等
  • 浏览器渲染进程(浏览器内核):一个tab页一个renderer进程,互不影响,用于页面渲染,脚本执行,事件处理
  • GPU进程:最多一个,用于3D渲染
  • 第三方插件进程:一个扩展插件对应一个进程

浏览器内核

GUI渲染线程

负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等,重绘和回流时会触发这个线程。重要的是,GUI线程和JS引擎线程互斥,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行

JS引擎线程

负责处理Javascript脚本程序

事件触发线程

归属于浏览器而不是JS引擎,事件循环机制就是基于这个线程

定时触发器线程

setInterval与setTimeout所在线程,浏览器定时计数器并不是由JavaScript引擎计数的,计时完毕后,添加到事件队列中,等待JS引擎空闲后执行。W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。

异步http请求线程

从Event Loop谈JS的运行机制

JS分为同步任务和异步任务,同步任务都在主线程上执行,形成一个执行栈,主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放置一个事件。一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。

macrotask和microtask

进一步,JS中分为两种任务类型:macrotask和microtask,在ECMAScript中,microtask称为jobs,macrotask可称为task

  • macrotask:每次执行栈执行的代码就是一个宏任务,浏览器为了能够使得JS内部task与DOM任务能够有序的执行,会在一个task执行结束后,在下一个 task 执行开始前,对页面进行重新渲染。属于:主代码块,setTimeout,setInterval等(可以看到,事件队列中的每一个事件都是一个macrotask)
  • microtask:在当前 task 执行结束后立即执行的任务,下一个task之前,在渲染之前。在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕。属于:Promise,process.nextTick等
  1. 执行一个宏任务(栈中没有就从事件队列中获取)
  2. 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  3. 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  4. 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  5. 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

JavaScript 模块化

JavaScript 不是一门模块化的语言,没有类的概念,至于为什么模块化,多人协作,代码复用性,可测试性,...

CommonJs

Node端的模块化规范,CommonJs用同步的方式加载模块。在服务端,模块文件都存在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。

主要有module、exports、require、global 四个环境变量
// 用require加载模块,用module.exports定义当前模块对外输出的接口
// 尽量不要用exports直接导出 
// math.js
var basicNum = 0;
function add(a, b) {
  return a + b;
}
module.exports = {
  add: add,
  basicNum: basicNum
}

// main.js 加载math.js 模块
var math = require('./math');
math.add(1, 2);

AMD

Asynchronous Module Definition,目前,主要有两个Javascript库实现了AMD规范:require.js 和 curl.js。

// 用require.config()指定引用路径等,用define()定义模块,用require()加载模块
// 定义math.js模块
define(function () {
    var basicNum = 0;
    var add = function (x, y) {
        return x + y;
    };
    return {
        add: add,
        basicNum :basicNum
    };
});
// 异步加载
require(['math'], function(math){
  var sum = math.add(1, 2);
});

CMD

此规范其实是在sea.js推广过程中产生的。AMD 推崇依赖前置、提前执行,CMD推崇依赖就近、延迟执行

// 定义模块 math.js
define(function(require, exports, module) {
    var add = function(a,b){
        return a+b;
    }
    exports.add = add;
});
// 加载模块
seajs.use(['math.js'], function(math) {
    var sum = math.add(1, 2);
});

// AMD 推崇依赖前置、提前执行
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) { 
    // 等于在最前面声明并初始化了要用到的所有模块
    if (false) {
      // 即便没用到某个模块 b,但 b 还是提前执行了
      b.foo()
    } 
});

ES6 Module

之前的几种模块化方案都是前端社区自己实现的,只是得到了大家的认可和广泛使用,而ES6的模块化方案是真正的规范。ES6 模块的功能主要由 export 和 import 组成。每一个模块都有自己单独的作用域,模块之间的相互调用关系是通过 export 来规定模块对外暴露的接口,

// 定义模块 math.js
var basicNum = 0;
var add = function (a, b) {
    return a + b;
};
export { basicNum, add };

// 引入模块
import { basicNum, add } from './math';

// 使用import命令的时候,用户需要知道所要加载的变量名或函数名。其实ES6还提供了export default命令,为模块指定默认输出,对应的import语句不需要使用大括号
// 多种形态
import fs from 'fs'
import {default as fs} from 'fs'
import * as fs from 'fs'
import {readFile} from 'fs'
import {readFile as read} from 'fs'
import fs, {readFile} from 'fs'

export default fs
export const fs
export function readFile
export {readFile, read}
export * from 'fs'

CommonJs 和 ES module 差异

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  • ES6 模块的设计**是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。
  • 由于 ES6 模块是编译时加载,使得静态分析成为可能。有了它,就能进一步拓宽 JavaScript 的语法,比如引入宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.