2022 知识图谱整理

梳理了一些知识图谱~

概览

详细描述

JavaScript

  • 基础

    • 原型与原型链

    • new 操作符

      1. 在内存中创建一个新对象
      2. 将对象内部的__proto__ 赋值为构造函数的 prototype 属性(原型链挂载)
      3. 将构造函数的this 指向新对象(this 绑定)
      4. 执行构造函数的代码
    • this 指向问题
      核心: 谁调用就指向谁

      1. 方法调用的时候, this 指向指向方法所在的对象。
      2. 当没有明确调用方的时候,this 就指向window,比如 setTimout 这种异步函数、匿名函数
      3. 箭头函数比较特殊,它在经过 babel 编译后,会用 _this 记录定义时候的this 对象,来实现一个固定this 的效果。
    • call/bind/apply
      这三个都是改变this 指向的方法。

      1. call、apply 几乎完全一样,只有第二个参数类型的区别。call 是多个参数传递,apply 是多个参数组成一个数组参数传递。
      2. bind 更类似于函数的延迟调用,传入一个作用域后返回一个新的函数,在调用新函数的时候传入对应参数。
    • 闭包
      闭包 =『函数』和『函数体内可访问的变量总和』
      核心: 当一个变量被内部函数使用的时候,就产生了一个闭包。
      一般用途:存储一些内部变量,如 ts 编译私有变量, 就是通过闭包实现的。
      缺点:内存常驻,无法通过GC 回收。

      • 柯里化
        可以理解为闭包的进阶用法,利用闭包和 apply/call 来达到延迟调用的目的。
        一般用于函数式库中的链式调用 如 lodash fp 中 sum(2)(3) = 5
    • 事件循环
      JavaScript 是单线程,非阻塞式的语言,为了实现非阻塞式的异步编程,就需要事件循环机制来处理任务。
      在一次完整的JavaScript任务中,分为 同步任务和异步任务,异步任务又分为宏任务和微任务。

      • 微任务
        优先级略微高点的异步任务,在同步任务执行完毕后,优先执行,代表如 promise.then 、mutationObserver 等
      • 宏任务
        在执行栈最底部调用,代表如 setTimeout、setInterval、IO 操作、UI 操作等。

      Node 中的事件循环
      Node 的事件循环和浏览器中的事件循环是两个不同的机制,它分为6个阶段,分别是

      • Timer, 执行到期的 setTimeout、setInterval 回调
      • IO 阶段,主要处理上一次循环残留的 callback
      • idle 阶段
      • poll: 等待回调
        • 执行回调
        • 执行定时器
          • 如果有到期的 setTimeout、setInterval,返回 Timer 阶段
          • 如果有 setImmediate,则前往 check 阶段
      • check 执行 setImmediate 的callback
      • close callbacks 执行一些close 的回调, 比如 server.close、socket.close
    • 关键帧回调

      • requestAnimationFrame
        多用于动画帧处理,在浏览器每次刷新的时候调用,以达到更流畅的动画效果
      • requestIdleCallBack
        在 React 的Fiber 架构中,有个任务调度的概念,这个方法就类似于 Fiber 任务调度
        如果硬件配置比较高,浏览器在执行完一帧任务后,会有一定的空闲时间,这个时间就可以通过 requestIdleCallBack 去调用,从而来实现 空闲时执行任务的目的,它不会影响主线程执行。
    • V8 的垃圾回收策略
      分代式垃圾回收机制,根据对象的存活时间将内存的垃圾回收进行不同的分代,然后对不同分代采用不同的垃圾回收算法
      新生代
      用于存放存活时间比较短的对象。再将新生代内存空间细分为两个空间 From 和 To,在程序执行过程中,会对From 空间的数据进行检查,如果发现有对象没有被使用(失活),就将此对象赋值到 To 空间中,如果有对象没有被其他地方引用,则对其进行垃圾回收(清除From),至此第一次线程任务执行完毕,From 和 To 完成身份互换。
      在第二次任务执行的时候,重复上述操作,回收失活对象。
      老生代
      当一个数据在 From、To 中完整的转移一次后,会认为是生命周期比较长的对象,在下一次垃圾回收的时候,会将其存储到老生代内存中(晋升)
      老生代的算法有所变更,会采用 标记清除标记整理 的方式来进行管理。垃圾回收器会基于 window 去遍历可访问的子节点,然后将这些节点标记为活动节点。如果发现某些属性不能访问或者无法遍历(失去作用域链),就对其进行垃圾回收。

    • ES6、ES7

      • let、const
        let、const 和var 的区别就在于他们俩不会变量提升,只会有一个暂存死区(在预编译阶段实现)
      • Promise
        简单点讲就是在构造函数执行的时候,对 .then 中的回调进行收集,存储到内部维护的 _callback 数组中,在执行 resolve 的时候循环调用回调。
        同时在内部维护三个状态 Pending rejected fulfilled, 用来控制任务状态。
      • Async、Await
        可以理解为 promise 的同步语法糖,可通过 async await 将 promise 转变成同步写法(实际还是异步)。
        在通过 babel 编译后,具体会通过 while 循环来实现。
      • Proxy
        Vue3 的核心监听方法就是通过 Proxy 来实现的, 可以监听一个 target,并绑定一个handle 对象,handle 对象中有 set、get 属性。
      • Symbol
    • 模块化

      • AMD
        requireJS 的默认加载规范,主要特征为依赖前置,在执行前就将依赖都加载完毕。
      • CMD
        seaJS 提出的加载规范,主要特征为随用随加载(依赖就近原则)。
      • UMD
      • CommonJS
        Nodejs 的模块规范,一个单独的文件就是一个模块,加载的时候使用 require() 来加载,返回内部的 exports 对象
      • ES6 Module
    • 跨页面通讯

      • postMessage
      • serviceWorker
  • Vue2

    • 基本原理
      基于发布订阅者模式以及观察者模式

      • 双向绑定原理
        Vue2 中通过 defineProperty 来监听 options.data 中的数据,为数据添加 getter/setter,使其变成响应式数据。
        当用户访问、修改响应式数据的时候,就会被拦截器拦截,从而进行后续的操作,如 watcher、dep 变更、diff 以及 patch。
        但是同时也存在一些问题,defineProperty 无法拦截到数组的原型链操作,如push、slice,或者对象的 delete 操作符,vue2 通过原型方法重新的方式来解决这些问题。
        当然好处就是兼容性好,支持到 IE8+。

      • Observe
        监听者,即内部通过 defineProperty来实现数据监听的一个函数。

      • Dep
        为发布订阅模式中的,订阅器,主要用于保存订阅者。
        Vue 会为每个属性绑定上监视器,当属性值被修改的时候(触发 setter/set),就触发该值对应的 Dep.notify 来通知 subs(订阅者数组,由多个 Watcher 订阅者组成的数组),

      • Watcher
        观察者,也是发布订阅模式中的订阅者。
        每个Vue 实例都会创建一个 Watcher 对象,Watcher负责接受 Dep 对象的变化,并且触发 re-render。

      • 依赖收集
        Dep 收集Watcher 到subs,并存储到每个响应式数据中的这个过程就叫做依赖收集

      • 虚拟DOM
        Vue2 采用了和 React 类似的虚拟Dom,一个虚拟DOM 就是包含了tag 信息、属性信息、依赖事件、子节点、父节点、兄弟节点的对象。
        虚拟Dom 的优点是可以通过 Diff 计算差异,生成新的DOM 节点,随后进行一次性更新真实DOM,减少浏览器重排时间,进而提高性能。

      • AST 语法树
        Vue2 采用 .vue 模板形式开发,通过 vue-template-loader 来编译文件的同时,就可以生成 AST 语法树并分析数据依赖。
        所谓 AST 语法树则和 虚拟DOM比较类似,是一个树形的DOM 节点列表。

      • For Key
        为什么列表循环中需要Key?
        Vue 的 Diff算法 & 就地复用策略决定。
        在 Diff 过程中,Vue 会对比 tag名称、属性等来判断节点是否更新,如果Key 存在的话,Vue 会优先使用 Key 进行判断,性能会好很多。

      • nextTick
        在下次dom 更新结束后执行延迟回调,内部采用微任务 > 宏任务 来实现,优先通过 promise.then/requestAnimateRequest 来做,如果不支持,则通过 setTimeout来实现。

    • Diff 算法
      Vue2 采用基于深度遍历的查找算法,然后同层对比,在对比同层的时候,采用单循环双指针同层对比(头头尾尾头尾)
      对比时优先对比Key,如果Key 相同则认为是同元素,不执行 update 操作。
      如果没有key(非列表元素)则对比 tagName/attrs/class 等具体属性,有差异则在 vNode中标记 update。

    • keep-alive 原理

  • Vue3

    • 基本原理
      vue3 中使用了 Proxy 来代替 defineProperty,最直接的好处就是 proxy 可以直接监听一个对象,而非一个属性,并且可以监听到数组的原型方法。
      proxy 中内置的拦截方法比较多, 基本可以满足所有拦截需求。
    • watch
      作用等同于 Vue2 的Watch,监听一个响应式数据,当此响应式数据发生变化的时候,触发对应的回调函数
    • watchEffect
      vue3 新增,区别于 watch,watch 是明确监听一个响应式数据,而 watchEffect 是隐式的监听内部数据
      ,并且在初始化的时候就立即执行回调函数。
      更像 React 里面的 useEffect,一个副作用函数。
    • watchPostEffect
      在DOM 更新完成后执行。
    • reactive
      Vue3 的核心监听函数,内部会递归调用 new Proxy 将 data 数据转化为 proxy 对象
    • proxy 拦截器
      Vue3 在创建Proxy 时,对对象进行拦截,使用了 set/get/deleteProperty/has/ownKeys 拦截器
      保证可以监听到对象的各种操作
    • VueX
    • Mobx
  • React

    • 基本原理

      • 与Vue 的区别
        1. 基本原理不同:React 与 Vue 的设计思路不同,React 是Push 的方式去通知框架数据发生了变更,Vue 是通过依赖收集和双向绑定自动
          监听数据变化,从而通知DOM 更新。
        2. DIFF 方式不同,React diff 采用的是fiber 加持下的单向链表依次对比,Vue 采用的是双向链表双指针头尾对比。
        3. React 存在 fiber 的time slice 调度,vue 没有
    • Time Slice

      1. 时间切片,因为 JavaScript 单线程的局限性,为了尽可能提高用户的观感执行速度,
        React 将比较耗时的任务拆分为微小地执行单元,通过内部实现的调度算法来决定先执行哪些比较重要的任务块。
    • Fiber 架构

      • 为了方便模拟JavaScript 调用栈,Fiber 提供了一种新的单向链表数据结构,用来替代原先的虚拟dom 节点 VNode,其中会包含一些节点信息、子节点信息、下一个节点信息,每个节点都是一个fiber 对象,模拟了调用栈帧后,方便在内存中记录执行状态,随时的中断或恢复
      • 在以往的版本中,React 是一边Diff 一边提交更新,现在 Fiber 设计了两个阶段
        1. Reconciliation 协调阶段
          此阶段可认为是 React 的Diff 阶段,此阶段会找出所有节点的变更,如节点的新增、删除、更新等,这些变更就被成为React 的副作用 (Effect),
          这个阶段会调用 constructor/shouldComponentUpdate/render 生命周期。
        2. Commit 提交阶段
          首先将上个阶段的Effect 一次性执行,此阶段不能被中断,必须同步执行,会触发 componentDidMount/componentDidUpdate/componentWillUnmount 生命周期。
      • 协调阶段如果时间片用完,React 会选择让出控制权,因为协调阶段做的事情不会导致用户可见的变更。
      • 而Commit 阶段中,用户的副作用(逻辑)操作被认为是优先级最高的,所以必须同步一次性按顺序执行。
    • 如何优化 React

      1. 使用 React.memo 来缓存组件
      2. 使用 useMemo、userCallback 来缓存大量计算
      3. 如果有必要,使用 React.PureComponent 来优化函数组件
        1. PureComponent 会进行浅比较来判断是否更新组件,如果 Props 的值相同,就不会更新组件,节省一些开支。
      4. 避免使用内联对象,内联对象每次render 后都会创建一个新的引用地址,会被 React 认为是 props 更新。
      5. 尽可能少的使用匿名函数,原因同上。
      6. 对一些组件延迟加载,如使用 React.lazy()
      7. 使用 React.Fragment 来创建 Fiber 节点,而非Dom 元素
  • Angular

    • 基本原理

      1. 不同于 Vue、React,Angular 继续使用 ng1 的数据脏检查来实现数据变动侦测,通过 zone.js 对一些用户关键操作,如setTimeout/form change/event 重写,在特定的时间
        遍历数据,检测哪些数据发生变化,并更新dom。
      2. Angular 并没有像 Vue、React 一样采用虚拟Dom, 它使用了 WebComponent 中的 ShadowDOM 来做组件隔离和DOM 渲染
      3. 相比 React 的函数式设计思想、Vue 的组合式设计思想,Angular采用了传统的程序设计,采用了 数据模型、控制器、视图的结构划分,通过依赖注入来维护关系,内部深度依赖了 RX.js 来进行任务流编程。
    • 依赖注入
      来自JAVA 的一种设计模式,在 Angular 中,通过 Typescript 的注解器来实现了 @Injection 方法,将模型传递给对应的被依赖的控制器。

    • AOT & JIT
      Angular 的编译模式,同样来自JAVA,分别为预先编译、运行时编译

  • Typescript

    • 类型校验
    • 装饰器
    • 元编程
  • 工具库

    • RxJS
    • Lodash

CSS

  • 基础

    • 选择器

    • 盒模型

      • 标准模型
      • 怪异模型
    • BFC

    • 自适应布局

    • Flex

  • Sass

  • Less

工程化

  • WebPack

    • 构建流程

      1. 初始化参数
      2. 开始编译
      3. 从入口开始分析代码、加载文件
      4. 完成文件编译,执行插件
      5. 输出资源
    • Loader & Plugins

      • Loader 是文件加载所用,Plugins 是各种各样的插件
  • Rollup

    • 摇树优化
  • Vite

前端优化

  • http 优化

    1. 代码压缩,减少体积
    2. 服务器开启 Gzip
    3. splitChunks 拆包,按需加载
    4. 图片使用内联或者雪碧图
    5. 开启http2 首部压缩
    6. 合理使用 http 缓存
    7. 使用 nginx 中间件,将多个请求合并
    8. 利用 CDN 加速 vender
  • 交互优化

    1. 减少页面的重排
    2. 优化动画效果,减少用户等待感知
    3. 骨架屏优化
    4. 图片懒加载

前端安全

  • XSS 注入
    • 即通过不安全的输入框、请求参数等,将攻击代码传输到服务器
    • 一般情况下,后端框架会去做 xss 过滤校验,如果需要,前端可以在用户输入的地方进行一次前置性过滤
    • 不过此方法依然不安全,前端代码是可见的,用户可任意篡改
  • CSRF 请求伪造
    • 即攻击者通过使用用户cookie 模拟用户请求
    • 服务器可每次生成一个 token,存储在 session 中,跟随每次请求返回,客户端在下次请求的时候将这个token 传递给后端校验,用过一次后失效,生成新的token 。

浏览器

  • 页面加载过程

  • JavaScript 的预编译

  • 重绘、重排
    浏览器在发现DOM 元素发生变化的时候会重新渲染。

    • 当发现DOM 的空间属性发生变化(如 zIndex、显示隐藏、位置变化、大小变化)的时候,会引起 DOM 重排。
    • 当发现 DOM 的颜色等不影响布局的属性发生变化时,会引起 DOM 重绘。
    • 重排一定会引起重绘,重绘不会引起重排
  • 缓存

    • 强缓存
      如 Cache-Control/Expires ,浏览器判断缓存是否过期,如果没有过期就直接使用缓存信息,不经过服务器确认。
      其中 Cache-Control 的 max-age 优先级高于 Expires。
      当发现缓存已过期的时候,就检查协商缓存。
    • 协商缓存
      目前用的比较多的缓存策略,浏览器请求一次服务端,服务端返回对应的返回头,浏览器通过 header 信息来检查是否需要更新资源,常见的控制协商缓存的字段有:
      • etag 优先级较高
      • if-none-match
      • last-modified 最后修改时间,如果一致,服务端返回 304
      • if-modified-since
  • 跨域

    • 同源策略
      浏览器的安全策略决定只能同源进行post、put 等高危操作,如果发现不同源,则拦截该请求,这个策略即同源策略。

    • 解决跨域

      • CORS
        在服务端设置请求头 access-control-allow-origin 白名单,如果设置为 * 则代表允许所有域请求。
        开启跨域后,需要设置 withCredentials 为 true ,cookie 才可以正常携带。
      • JSONP
        很古老的技术,原理是通过get 请求一个script 脚本,返回一个函数,前端接收到后执行,因为get 请求没有跨域问题,基本淘汰。
      • 网关代理
        比较优雅的解决方案,通过网关代理,将不同域的请求转化为同域,以解决跨域。比如通过 nginx 中的 rewrite 转发。
        在webpack dev 中的proxy 也是基于代理做的。
    • 简单请求和复杂请求
      请求方法为 GET、POST、HEAD,且请求头中只包含下列字段的请求,就叫做简单请求,

      • Accept
      • Accept-Language
      • Content-Language
      • Content-Type
      • DPR
      • Downlink
      • Save-Data
      • Viewport-Width
      • Width
    • Option 嗅探
      在跨域发出复杂请求前, 浏览器会触发一个 Option 类型的请求,用来鉴定是否可以正常通讯。

后端

Node

Python

  • flask

PHP

  • CI
  • lumen

通用

网络协议

  • TCP

    • 三次握手
      • 客户端发送 syn请求,进入 syn_send 状态,等待确认
      • 服务端接受到 syn 请求,发送 syn + ack 包,进入 syn_recv 状态
      • 客户端接受到 syn+ack 后,发送 ack 包,双方建立连接
    • 四次挥手
      • 客户端发送 fin 给服务端,服务端进入 fin-wait 状态
      • 服务端发送 ack 给客户端,进入 close-wait 状态
      • 服务端发送 ack+fin 给客户端,进入last-act 状态
      • 客户端 发送 act 给服务端,进入 closed,关闭连接
  • UDP
    和 TCP 相比,UDP 是一种无连接协议,不需要建立链接的单向发送包,不需要维护状态,比如实时语音聊天

  • HTTP

    • 状态码
      • 200 成功
      • 301 永久重定向
      • 302 临时重定向
      • 304 资源未修改,使用缓存
      • 400 请求错误
      • 401 需要认证
      • 403 权限问题,拒绝请求
      • 404 不存在
      • 500 服务器错误
      • 502 网关错误
      • 504 超时
    • HTTP 2.0
      新增了多路复用、首部压缩、服务端推送。
    • HTTPS
      网关设置端口为 443,并且配置 SSL 公钥证书,优点是会进行隧道加密。

Rest API

常见的的Rest 请求类型分为

  • get
  • post
  • put
  • patch
  • delete

其中 get、put、delete 都应该是幂等操作

设计模式

  • 工厂模式
  • 代理模式
  • 观察者模式

算法

  • DFS
    深度优先算法,Vue、React 的Diff 查找中都使用此算法,在遍历的时候优先查找一个分支,当最终节点没有子节点的时候,重新返回父级查找兄弟节点。

  • BFS
    广度优先算法