Skip to content

Latest commit

 

History

History
535 lines (404 loc) · 27.4 KB

File metadata and controls

535 lines (404 loc) · 27.4 KB

Table of Contents generated with DocToc

Articles

Node.js

模块

require vs import

export vs export default

进程/线程

事件循环

事件循环/任务调度

setTimeout 问题

/*
 * 宏任务:
 * 1. I/O
 * 2. setTimeout/setInterval/setImmediate
 * 3. requestAnimationFrame
 *
 * 微任务:
 * 1. process.nextTick
 * 2. Promise.then/.catch/.finally
 */

// 注意,new Promise 在实例化的过程中所执行的代码都是同步进行的,而 then 中注册的回调才是异步执行的
// async 函数在 await 之前的代码都是同步执行的,可以理解为 await 之前的代码属于 new Promise 时传入的代码,await 之后的所有代码都是在 Promise.then 中的回调
setTimeout(() => {
    console.log(1)
}, 0)

new Promise((resolve) => {
    console.log(2)
    for (let i = 0; i < 100; i += 1) {
        if (i === 88) resolve()
    }
    console.log(3)
}).then(() => {
    console.log(4)
})
console.log(5)
// 2 3 5 4 1

V8

其他

JavaScript

基础

数据类型,原型/原型链

原型/原型链

JS 中可分为普通对象Object和函数对象Function。通过new Function产生的对象、声明的函数是函数对象,其他对象都是普通对象

prototype即原型对象,它记录着对象的一些属性和方法。 prototype对于父对象本身是不可见的,但子类可以完全访问。当通过new操作符创建新对象的时候,通常会把父类的prototype赋值给新对象的__proto__属性,子类就可以调用到继承的属性或方法。 原型链的形成真正是靠__proto__而非prototype,当 JS 引擎执行对象的方法时,先查找对象本身是否存在该方法,如果不存在,会在原型链上查找,但不会查找自身的prototype

function func() {}
func.prototype.foo = 'foo'
console.log(func.foo) // undefined

const f = new func()
console.log(f.foo) // foo

向上追溯原型链:

  1. f.__proto__ -> func.prototype
  2. func.prototype.__proto__ -> Object.prototype
  3. Object.prototype.__proto__ -> null

提升

// 函数声明会被提升
console.log(a) // ƒ a() { console.log('1') }
a() // 1
function a() { console.log('1') }
var a = function() { console.log('2' )}
console.log(a) // ƒ () { console.log('2' )}
// 但函数表达式不会被提升
console.log(a) //  undefined
a() // TypeError
var a = function() { console.log('2' )}
console.log(a) // ƒ () { console.log('2' )}
var a = function() { this.b = 1 }

a.prototype.b = 9

var c = new a()
var b = 2
a()

console.log(b)
console.log(c.b)

Map/WeakMap, Set/WeakSet

判断操作

How JavaScript works

  1. How JavaScript works: An overview of the engine, the runtime, and the call stack
  2. How JavaScript works: Inside the V8 engine + 5 tips on how to write optimized code
  3. How JavaScript works: Memory management + how to handle 4 common memory leaks
  4. How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding with async/await
  5. How JavaScript works: Storage engines + how to choose the proper storage API

Promise

/*
 * Some fact:
 * 1. 调用 resolve 或 reject 并不会终结 Promise 的参数函数的执行
 * 2. Promise 在 resolve 语句后面,再抛出错误,不会被捕获,等于没有抛出。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了
 * 3. new Promise 在实例化的过程中所执行的代码都是同步进行的,而 then 中注册的回调才是异步执行的
 * 4. async functions always return promises
 */

前端

React

其他

JSON.parse(JSON.stringify(obj)) // hack
// Issues with Date() when using JSON.stringify() and JSON.parse()
// https://stackoverflow.com/questions/11491938/issues-with-date-when-using-json-stringify-and-json-parse/
  • 防抖debounce: 事件被触发后 N 秒内不能重复执行。如果执行,则 N 重新计时
  • 节流throttle: 如果持续触发一个事件,则在一定的时间内只执行一次事件

扩展阅读

Redis

知识点

其他

计算机

计算机网络

http 数据分隔 CLRF(\r\n)

TCP/UDP

TCP/UDP/IP

调优

TCP 连接和挥手过程:

tcp 连接和挥手过程

TIME_WAIT是主动关闭方在收到被动关闭方发的FIN包之后处于的状态, 这个包是主动关闭方收到的最后一个包了, 在收到这个包之后还不能直接就把连接给关闭了, 还得等待一段时间才能关闭, 等待时间为2MSL

为什么要等待一段时间呢? 主要是两个原因:

  1. 在收到最后一个包之后主动关闭方还得发一个ACK回去, 这个ACK可能会丢包, 如果丢包, 对方还需要重新发最后一个FIN包, 如果收到重新发过来的FIN包的时候这边连接已经关闭, 则会导致连接异常终止;
  2. 不过第 1 点也不会造成太大的问题, 毕竟数据已经正常交互了。但是有另外一点风险更高, 就是如果不等待2MSL的话, 那么如果正好一个新连接又建立在相同的端口上, 那么上次的FIN包可能因为网络原因而延时的包,这个时候才送达该端口, 导致下一次连接出现问题;

所以一定要有一个TIME_WAIT的状态等待一段时间, 等待的MSL时间RFC上面建议是 2 分钟

但是如果你的服务是一个高并发短连接服务, TIME_WAIT可能会导致连接句柄被大量占用, 而你又相信服务内部是一个非常稳定的网络服务, 或者即使有两个连接交互出现故障也可以接受或者有应用层处理, 不希望有那么多的TIME_WAIT状态的连接, 一般有两种方式:

  1. 在建立连接的时候使用SO_REUSEADDR选项
  2. /etc/sysctl.conf中加入如下内容:
# 表示开启 TCP 连接中 TIME-WAIT sockets 的快速回收,默认为 0,表示关闭
net.ipv4.tcp_tw_recycle = 1
# 表示开启重用。允许将 TIME-WAIT sockets 重新用于新的 TCP 连接,默认为 0,表示关闭
net.ipv4.tcp_tw_reuse = 1
# 对于本端断开的 socket 连接,TCP 保持在 FIN-WAIT-2 状态的时间。对方可能会断开连接或一直不结束连接或不可预料的进程死亡。默认值为 60 秒
# 即 MSL。断开连接四次挥手时,最后会等待 2MSL 后释放文件句柄
net.ipv4.tcp_fin_timeout = 1
# 在每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目
net.core.netdev_max_backlog = 4000

然后执行/sbin/sysctl -p生效参数

扩展阅读

HTTPS

连接基本过程:

  1. 客户端请求服务端,服务端给出自己证书
  2. 浏览器从证书中拿出服务端公钥 A
  3. 浏览器生成自己的对称密钥 B,用公钥 A 加密 B 后传输给服务端
  4. 服务端用私钥 C 解密,获取到对称密钥 B
  5. 之后两端通讯使用对称密钥 B 加密

证书合法性检查:

  1. 首先,证书中包含:签发机构 CA、数字签名(用 CA 私钥加密摘要)、证书持有者公钥 A、签名的 hash 算法
  • 数字签名的由来:明文 -> hash 运算 -> 摘要 -> CA 私钥加密 -> 数字签名
  1. 其次,浏览器内置了 CA 的根证书,包含 CA 的公钥
  2. 浏览器收到服务端证书以后:
  • 检查证书颁发机构是否存在,然后找到 CA 证书、CA 公钥
  • 用 CA 公钥解密数字签名,解出被加密的证书摘要 AA
  • 用证书中提供的 hash 算法,计算出当前证书的摘要 BB
  • 比较 AA 和 BB
  • 以上有任意一步失败,则会认为证书被伪造

SSH

DNS/CDN、代理

网络攻击

算法和数据结构

算法

难点

数据结构

架构

消息队列

微服务

稳定性

Linux

其他

React 虚拟 DOM

class Test {
  constructor() {
    this.echo = () => {
      console.log('echo in constructor')
    }
  }

  echo() {
    console.log('echo')
  }
}

Test.echo // error
new Test().echo() // echo in constructor