前端知识点
2022-03-17 16:46:09 36 举报
AI智能生成
根据面试题整理的知识点
作者其他创作
大纲/内容
Vue
1. v-if 与 v-for 与 v-show
vue2.x v-for 比 v-if 优先级高
外层包template标签
计算属性把不需要的数据过滤
vue3.x v-if 比v-for 优先级高
v-if
节点的删除创建
代码不常用时用 v-if
v-show
display: none隐藏,保留DOM节点
代码常用时用 v-show
2. 单页面应用和多页面应用区别及优缺点?
单页面
1. 单页面每一次页面的跳转,是通过JS把当前页面数据删除,然后渲染新页面的DOM结构
2. 跳转仅刷新局部资源 ,公共资源(js、css等)仅需加载一次
缺点:
1. 首屏时间稍慢(需要进行一个html请求和JS请求,两个都返回才能展示)
2. SEO差(搜索引擎只认识html中的内容,不认识js中的内容)
优点:
页面切换快
多页面
1. 每一次页面的跳转,客户端都会返回一个新的html
2. 跳转刷新所有资源,每个公共资源(js、css等)需选择性重新加载
缺点:
页面切换慢
优点
1. 首屏时间快(首个屏幕展现出来的时间),因为只经历过一个http请求,请求回来了,页面就展示出来了
2. SEO(搜索引擎优化)效果好
3. 虚拟DOM
why?
DOM操作很慢,轻微操作都有可能导致页面的重排和重绘,相当于DOM对象,js对象处理起来更快,而且更简单。
通过diff算法对比新旧vdom之间的差异
通过diff算法对比新旧vdom之间的差异
4. Vue2.x 响应式原理
为什么需要数据响应式?
数据响应式:一种为了驱动数据和视图更新的机制
为了数据驱动,使操作的数据影响到视图层的更新
1. 核心 Object.defineProperty
接受3个参数 (对象, key, 属性描述符)
2. 初始化会走 initState(vm) 方法
1> initProps(vm, opts.props)
遍历定义的 props 配置
一个是调用 defineReactive 方法把每个 prop 对应的值变成响应式可以通过 vm._props.xxx 访问到定义 props 中对应的属性
另一个是通过 proxy 把 vm._props.xxx 的访问代理到 vm.xxx 上
另一个是通过 proxy 把 vm._props.xxx 的访问代理到 vm.xxx 上
2> initMethods(vm, opts.methods)
遍历
1. 校验是否为函数,2. 与props重名校验,3. 是否以$或_开头
将函数绑定到 vm 上
3> initData(vm)
1. 先判断 data 是 function 还是 object, function 就会直接生成一个新对象,object 则会直接赋值
2. 遍历,与props和methods进行命名检测,不冲突则调用proxy方法,使之可以用vm(this) 访问
3. 调用 observe(data, true) 方法进行数据响应式
4> initComputed(vm, opts.computed)
1. 遍历,为每个属性添加watcher
2. 判断是否在vm上,不存在则绑定到vm上
3. 存在则与data, props 做重名校验
5> initWatch(vm, opts.watch)
1. 循环遍历调用 createWatcher 进行绑定监听
2. createWatcher 里面使用 vm.$watch
3. 扩展函数
1> proxy
简写:通过 Object.defineProperty 把 target[sourceKey][key] 的读写变成了对 target[key] 的读写
2> observe
1. 判断当前类型是Object还是VNode, 不满足则直接 return
2. 如果当前是响应式对象这直接返回该响应式对象(__ob__)
3. 不是则 new Observer 进行响应式监听
4. 返回ob(Observer类会为每一个对象添加'__ob__'属性,所以可以来判断他是否有子对象)
3> class Observer 类
1. this.dep = new Dep(), new一个Dep并绑定到当前ob实例上(一个对象一个Dep)
2. 调用 def 方法为当前对象添加 '__ob__' 属性
3. 判断是否为数组,数组则遍历每一项并调用 observe () 方法进行数组每一项判断
并且改变其数组的原型指向,指向到新设置的响应式原型(重写的监听数组方法的原型)
并且改变其数组的原型指向,指向到新设置的响应式原型(重写的监听数组方法的原型)
4. 对象则直接调用 walk 方法进行每一项调用defineReactive进行响应式监听
4> defineReactive
1. const dep = new Dep() 此时一个key对应一个dep
2. 调用 observe(val) 方法 返回 childOb,对象则返回Observer实例,否则undefined
同时该方法内如果是对象则递归进行 new Observer ,进行响应式绑定,疯狂套娃
同时该方法内如果是对象则递归进行 new Observer ,进行响应式绑定,疯狂套娃
3. Object.defineProperty 进行响应式绑定
get
dep.depend() (dep 和 当前watcher 互相添加映射关系)
childOb ? childOb.dep.depend() (子ob实例也要添加映射关系)
Array.isArray(value) ? dependArray(value) (如果value值为数组,也需递归遍历添加映射关系(防止数组里面存储的是值类型))
set
判断新值老值是否一样
设置最新的值
observe(newVal) 对新值进行响应式处理
dep.notify() 通知更新
5. Vue3.x 响应式原理
Vue2.x 初始化过程
1. 扩展mount方法,主要作用是生成render方法
src\platforms\web\entry-runtime-with-compiler.js
src\platforms\web\entry-runtime-with-compiler.js
1. 优先级 render > template > el
2. 没有render 的时候会调用 compileToFunctions 来根据 template 生成 render 函数
3. compileToFunctions 是最里面的一层,通过了究极闭包,最终会调用 baseCompile 方法,该方法又会调用 parseHTML方法生成AST树,parseHTML是JQuery作者写的
4. 该扩展方法最终就调用原生的$mount方法
2. 原型上定义patch和$mount方法
src\platforms\web\runtime\index.js
src\platforms\web\runtime\index.js
patch是通过createPatchFunction函数创建的
mount 方法里面会调用 mountComponent 方法执行挂载
mountComponent 方法内容
1. callHook(vm, 'beforeMount') 声明周期调用
2. 定义 updateComponent 组件更新函数
3. new Watcher() 进行当前组件的watcher 初始化
初始化结束后会立即执行一遍传入的组件更新函数
初始化结束后会立即执行一遍传入的组件更新函数
子主题
4. 调用 callHook(vm, 'mounted') 挂载完成
3. initGlobalAPI(Vue)
src\core\index.js
src\core\index.js
初始化全局API component/directive/filter/use/mixin/set/dellete/extend
4. Vue 构造函数声明 和 实例的属性、实例方法初始化
src\core\instance\index.js
src\core\instance\index.js
1. function Vue (options) {}
2. initMixin(Vue) // - _init
_init 内容
1. 选项合并:当前选项和全局选项进行合并
子主题
2. initLifecycle(vm) // - 初始化 $parent/$root/$children/$refs
3. initEvents(vm) // - 自定义事件的监听 $on/$off
4. initRender(vm) // - 初始化 $slots/$scopedSlots/_c/$createElement/$attrs/$listeners
5. callHook(vm, 'beforeCreate') // todo beforeCreate 生命周期调用
6. initInjections(vm) // - 数据响应式监听 resolve injections before data/props
7. initState(vm) // - 初始化 props/methods/data/computed/watch ----- 依次优先级
设置数据响应式
设置数据响应式
8. initProvide(vm) // - resolve provide after data/props
9. callHook(vm, 'created') // todo created 生命周期调用
10 最后调用 vm.$mount(vm.$options.el)进行挂载
3. stateMixin(Vue) // - $set/$delete/$watch 初始化 $data/$props声明
4. eventsMixin(Vue) // - $emit/$on/$off/$once
5. lifecycleMixin(Vue) // - _update/$forceUpdate/$destroy
6. renderMixin(Vue) // - $nextTick/_render
6. Vue3.x 初始化过程
2. packages\runtime-core\src\apiCreateApp.ts
3. packages\runtime-core\src\renderer.ts
createApp() => ensureRenderer() => createRenderer() => baseCreateRenderer() => reateAppAPI => mount() => render() => path() => processComponent() => mountComponent()
mountComponent => setupComponent() => setupStatefulComponent() => handleSetupResult() => finishComponentSetup()
1. 执行 packages\runtime-dom\src\index.ts 导出的 creteApp 函数
1. const app = ensureRenderer().createApp(...args)
先获取App实例
先获取App实例
2. mount扩展:获取根元素的dom节点
2. ensureRenderer() 调用 createRenderer() 返回一个渲染器
ensureRender
3. createRenderer() 调用 baseCreateRenderer() 返回一个对象
packages\runtime-core\src\renderer.ts
packages\runtime-core\src\renderer.ts
createRenderer
4. baseCreateRenderer()
1. cosnt patch = fn
定义patch函数,用于根据不同的节点类型匹配不同的处理函数
子主题
2. const render = fn
定义render函数,进行patch比较
3. const processComponent = fn
判断节点
1. 初始组件挂载 调用 mounComponent()
1. 初始组件挂载 调用 mounComponent()
2. 组件更新 调用 updateComponent()
4. const mounComponent = fn
1. 调用 setupComponent 进行组件配置
initProps
initSlots
调用 setupStatefulComponent() 进行数据处理
2. 调用 setupRenderEffect 进行依赖收集
组件更新函数
instance.update = effect(function componentEffect() {})
instance.update = effect(function componentEffect() {})
return { render, hydrate, createApp: createAppAPI(render, hydrate) }
5. createAppAPI()
返回函数 createApp
6. createApp()
1. 创建context上下文
给实例对象 app 赋值实例方法
1. use
2. mixin
3. component
4. directive
5. mount
1. 调用 createVnode 获的 VNode
2. 调用 render, 将vdom 转化成真实 dom, 并挂载到 rootContainer 上
6. unmount
7. provide
7. app 实例初始化完成 => mount() => render() => patch() => 节点类型匹配后调用processComponent() => 然后根据节点判断走初始化判断 调用 mountComponent() => 调用 setupComponent() 进行组件初始配置 => initProps, initSlots, 调用 setupStatefullComponent 进行数据处理 => proxy数据代理,执行组件的 setup() 函数,最后调用 handleSetupResult()进行兼容性处理 => 调用 finishComponentSetup() 进行optionAPI的兼容处理
7. Vue2.x 与 Vue3.x 的区别
1. Vue3.x 没有了静态方法,只有通过 createAPP 创建的实例方法(app.use/mixin/component/mount 例 Vue.use())
避免打包时把一些没有的代码加进去
2. 核心方法 Object.defineProperty变成 Proxy
proxy 是劫持对象而不用递归劫持数据
proxy 兼容性
3. 支持 Fragments,每个组件不需要一个根组件进行包裹,这样可以节省不必要的DOM结构
4. 数据响应式设置,以前在data里面的数据都会被响应式监听,但是现在只有自己设置的才会进行响应式监听,极大地降低了消耗成本
5. 所有代码都可以写在 setup 里面,相同的逻辑可以直接抽离出去,维护时不需要返回横跳
6. 算法优化:增加静态标记,Vue3采用二进制来标记节点类型,如diff是碰到静态节点类型的标记会直接跳过,而不需求深层次递归,优化性能
7. 增加 Teleport 标签,能够使指定内容挂载到指定dom节点下
8. 生命周期改变,去除 beforeCreate 和 created,增加 setup,其他的都加on,destroy 变成 Unmount
9. 没有watcher,用effect和使用到了响应式对象进行映射
8. Vue3 中 Teleport 的作用是什么
teleport定义:把自己包裹的内容渲染在自己想要渲染的指定元素下
如果在配合components使用的话,在做到根据自己需求指定渲染位置的体况下,依然跟组件保持父子组件关系,从而轻易的做到数据传递
如果在配合components使用的话,在做到根据自己需求指定渲染位置的体况下,依然跟组件保持父子组件关系,从而轻易的做到数据传递
内部默认使用 document.querySelector() 查询元素
可以多个teleport可以都指向同一标签,结果是按顺序添加
9. Vue3的composition api
1. setup(props, { solts, mixin })
0. 由于在执行 setup 时尚未创建组件实例,因此在 setup 选项中没有 this。这意味着,除了 props 之外,你将无法访问组件中声明的任何属性——本地状态、计算属性或方法
1. props 作为setup 的第一个参数返回,第二个参数是当前实例对象
2. 生命周期,watch,computed 都可以写在 setup 里面
2. 生命周期
setuo()
代替 beforeCreate 和 created
onBeforeMount
代替 beforeMount
onMount
代替 mounted
onBeforeUpdate
代替 beforeUpdate
onUpdated
代替 updated
onBeforeUnmount
代替 beforeDestroy
onUnmounted
代替 destroyed
onErrorCaptured
代替 errorCaptured
onRenderTracked
代替 renderTracked
onRenderTriggered
代替 renderTriggered
3. ref, toRefs, reactive, effect
10. Vue3中v-model的变化有哪些?
1. v-model 默认向下传递的值从 value 变成 modelValue
2. v-model 默认向下传递的方法从 update 变成 update:modelValue
3. 可以更换 v-model 的默认参数,例:v-model:title="title", 方法也就变成 this.$emit("update:title", value)
4. 取消了.sync修饰符的使用
11. Vue父子组件生命周期谁先谁后
Vue 遵循着 深度优先,所以优先子组件(从外到内再由内到外)
挂载阶段:父bc -> 父created -> 父bm -> 子bc -> 子created -> 子bm ->子mounted -> 父mounted
更新阶段:父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated(当父组件有数据 传递时才会触发)
销毁阶段:父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
相似问题:子组件的props与created()谁先触发?-》执行顺序beforeCreate ->inject -> Props -> Methods -> Data -> Computed -> Watch ->provide-> created
12. Vue组件通信
v-model
props, $emit, $on
bus总线
1. new 一个新的 Vue 对象
2. 利用其 $on(注册) 和 $emit(触发) 的特性来使用
provide,injected
$parend, $chirlrend
$refs
13. computed 和 watch
computed:
计算属性,监听内部用到的响应式对象,当对象值改变时,就会执行改回调函数,所以也具有缓存效果
watch:
监听某一个响应式对象
该对象改变时,watch的回调也会改变,回调函数有两个参数,新值和旧值
watch 可以是函数或者对象
对象可以设置deep 和 immediate
Vue 的模板编译原理(2和3差不多)
1. 模板编译,将模板代码转化为 AST
const ast = parse(template.trim(), options)
const ast = parse(template.trim(), options)
type 一共有三种类型, 元素节点/表达式/文本节点
使用parseHTML插件 栈
2. 优化 AST,方便后续虚拟 DOM 更新
optimize(ast, options)
optimize(ast, options)
markStatic(root)
3. 生成代码,将 AST 转化为runder 执行的代码
const code = generate(ast, options)
const code = generate(ast, options)
3.x 静态标记与优化
编译阶段优化
1. 静态提升
所有的静态节点全部放在render函数的外面
子主题
2. 补丁标记和动态属性记录
子主题
3. 缓存事件处理程序
为了避免每次子节点变化
4. 块block
createBlock
Vue3 新的Vnode结构
1. children 可以是数组或者文本
2. 新增 dynamicChildren 和 dynamicProps 用来存储动态属性和子节点
3. 新增 patcFlag 表示patch时应该比较什么内容
packages\shared\src\patchFlags.ts
4. 新增shapeFlag 表示当前组件的类型Teleport 或 Fragment
shared/src/shapeFlags.ts
6. type 表示节点类型,不再是数字
Vue3 patch
1. 根据类型走不同的path函数
2. 例:processFragment
1. 先获取patchFlag 和 dynamicChildren
let { patchFlag, dynamicChildren } = n2
let { patchFlag, dynamicChildren } = n2
2. 判断patchFlag的值需不需要更新
3. if (n1=== null)
1. 初始化 - 调用 mountChildren 进行子节点递归挂载(深度优先)
2. 更新
if (
patchFlag > 0 &&
patchFlag & PatchFlags.STABLE_FRAGMENT &&
dynamicChildren
)
patchFlag > 0 &&
patchFlag & PatchFlags.STABLE_FRAGMENT &&
dynamicChildren
)
是:调用 patchBlockChildren() 进行块级更新
遍历 dynamicChildren 进行patch比较
v-for遍历的节点不需要存放在dynamicChildren
v-for遍历的节点不需要存放在dynamicChildren
否:patchChildren() keyed / unkeyed
有key: patchKeyedChildren()
1. 先获取新老数组最后一项的索引
2. while循环遍历,去除头部相同的节点
3. while循环遍历,去除尾部相同的节点
4. 判断是否需要新增
6. 判断是否需要删除
7. 乱序,新老各剩几个节点,则进行挨个查找比较
a b c d
a b e c d
a b e c d
无可以: patchUnkeyedChildren()
JS
1. 节流和防抖分别是什么?在什么场景下使用?请分别实现一个节流函数和一个防抖函数
节流
定义:节省流量,将多次执行变成每隔一段时间执行。
防抖
定义:防止抖动,多次执行变为最后一次执行
防抖
节流
2. 怎么禁止让js读取cookie?怎么让cookie只在HTTPS下传输
设置HttpOnly
设置secure属性
当secure属性设置为true时,表示创建的 Cookie 会被以安全的形式向服务器传输,也就是只能在 HTTPS 连接中被浏览器传递到服务器端进行会话验证
3. 存储数据 什么样情况下用数组什么样情况下用对象
1. 对象查询复杂度O1,数组On,数组插入是O1
4. 装饰器
一种代码包代码的方式叫装饰器
在不改变对象自身的基础上,在程序运行期间给对象动态的添加职责
所以可以链式调用,俄罗斯套娃
5. null 和 undefined的区别
null
1. 和Java里面一样,null是一个对象,所以 typeof null 为object
2. null 转数值 为 0
undefined
1. 新增的基本数据类型,typeof undefined 为 undefined
2. undefined 转数值 为 NaN
null == undeined true;null ===undefined false
语义:null 表示一个空对象,undefined 表示原始状态值
算法
并查集
基础知识
维护连接关系
连通性(传递性)问题
染色法(Quick-Find算法)
集合连接操作
查找O1 连接On
实现
1. 定义一个集合,存放不同颜色
2. 初始化时遍历数据,为每个数据给上指定颜色
3. 定义个查找方法,查找指定数据的颜色
4. merge(a, b): 遍历所有点,把所有跟b颜色的点染成a的颜色
Quick-Union 算法
树形结构,节点连接
查找On 连接O1
实现
1. 定义一个集合,存放当前点的父节点编号
2. 初始化时遍历数据,初始每个节点的父节点为自己(此时每个节点就相当于一个根节点)
3. find() 如果当前的父节点是自己,则直接返回自己,否则递归向上查找,直至找到根节点
4. marge(a, b) 分别找a和b的根节点,如果两个根节点相等,则表示在同一个树,不相等则把a和b相连
优化
极端情况下,最后是一个链表,所以查找的速度和树高有关
优化策略:按秩优化:平均查找次数 总查找次数/总节点数
再次优化:路径压缩,减少中间商
find() 里面处理,找到根节点后,直接把当前节到根节点的所有节点都挂载到根节点上 f(x)= root
练习
题目
力扣547-省市操作,200-岛屿数,990-等式方程的可满足性,684-冗余连接,1319-连通网络的操作次数,128-最长连续序列,947-移除最多的同行或同列石头,1202-交换字符串中的元素
浏览器 与 网络
进程与线程
进程
定义:一个进程就是一个程序的运行实例。
详细解释,启动一个程序的时候,操作系统会为该程序创建一块内存,用来存放代码、运行中的数据和一个执行任务的主线程,我们把这样的一个运行环境叫进程
详细解释,启动一个程序的时候,操作系统会为该程序创建一块内存,用来存放代码、运行中的数据和一个执行任务的主线程,我们把这样的一个运行环境叫进程
线程
多线程可以并行处理任务,但是线程是不能单独存在的,它是由进程来启动和管理的,所以线程是依附于进程的,而进程中使用多线程并行处理能提升运算效率
进程与线程的关系
1. 进程中的任意一线程执行出错,都会导致整个进程的崩溃
2. 线程之间共享进程中的数据
3. 当一个进程关闭之后,操作系统会回收进程所占用的内存
4. 进程之间的内容相互隔离
浏览器时代
早期单进程浏览器时代
所有功能都在一个进程里面执行
缺点:
不稳定性
不流畅
不安全
早期多进程浏览器时代
子主题
目前多进程浏览器时代
浏览器多进程架构
浏览器进程:
主要负责界面显示、用户交互、子进程管理,同时提供存储等功能
渲染进程:
核心任务是将HTML, CSS, JS转换成与用户可交互的页面,排版引擎Blink 和 JS V8引擎也是在这个进程中,出于安全考虑,渲染进程都是处于沙箱模式下
GPU 进程:
页面绘制,最初是绘制3D CSS效果
网络进程:
负责页面的网络资源加载
插件进程:
负责插件的运行,因为插件容易崩溃,所以为了防止插件的崩溃影响到页面,单独抽离出一个插件的进程出来
缺点:
更高的资源占用因为每个进程都会包含公共基础结构的副本(如 JavaScript 运行环境),这就意味着浏览器会消耗更多的内存资源。
更复杂的体系架构浏览器各模块之间耦合性高、扩展性差等问题,会导致现在的架构已经很难适应新的需求了
更复杂的体系架构浏览器各模块之间耦合性高、扩展性差等问题,会导致现在的架构已经很难适应新的需求了
未来面向服务架构(SOA)
子主题
相关面试题
1. 为什么单进程浏览器当时不可以采用安全沙箱?
权限问题:一个进程使用了安全沙箱之后,该进程对于操作系统的权限就会受到限制,比如不能对一些位置的文件进行读写操作,而这些权限浏览器主进程所需要的,所以安全沙箱是不能应用到浏览器主进程之上的
2. 打开Chrome浏览器一个Tab页面,至少会出现几个进程?
至少四个:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程,当然还有复杂的情况
1. 页面中有iframe的话,iframe会单独在进程中
2. 有插件的话,插件也会开启进程
3. 多个页面属于同一站点,并且从a打开b页面,会共用一个渲染进程
4. 装了扩展的话,扩展也会占用进程
Chrome的默认策略是,每个标签对应一个渲染进程。但是如果从一个页面打开了新页面,而新页面和当前页面属于同一站点时,那么新页面会复用父页面的渲染进程。官方把这个默认策略叫process-per-site-instance
所以当一个页面崩溃了,会导致同一个站点的其他页面也奔溃,这是因为它们使用的是同一个渲染进程
3. 即使如今多进程架构,还是会碰到单页面卡死的最终崩溃导致所有页面崩溃的情况,讲一讲你的理解?
HTTP请求流程
整体流程
1. 构建请求
2. 查找缓存
在真正发起网络请求之前,浏览器会先在浏览器缓存中查询是否有要请求的文件
当浏览器发现请求的资源已经在浏览器缓存中存有副本,它会拦截请求,返回该资源的副本,并直接结束请求,而不会再去源服务器重新下载
3. DNS服务器解析域名(准备好IP和端口)
因为浏览器使用 HTTP 协议作为应用层协议,用来封装请求的文本信息;并使用 TCP/IP 作传输层协议将它发到网络上,所以在 HTTP 工作开始之前,浏览器需要通过 TCP 与服务器建立连接。也就是说 HTTP 的内容是通过 TCP 的传输数据阶段来实现的
4. 等待TCP队列
Chrome 有个机制,同一个域名同时最多只能建立 6 个 TCP 连接,如果在同一个域名下同时有 10 个请求发生,那么其中 4 个请求会进入排队等待状态,直至进行中的请求完成。
5. 建立TCP请求
一个完整的TCP连接生命周期包括了“建立连接”“传输数据”和“断开连接”三个阶段
子主题
6. 发起 HTTP 请求
子主题
7. 服务器处理请求
8. 服务器返回请求和断开连接
子主题
1. 客户端缓存有几种方式?浏览器出现 from disk、from memory 的 策略是啥?
客户端缓存
http缓存
强缓存
规则:浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存(cache-control和expires信息)
若命中直接从缓存中获取资源信息,包括缓存header信息,本次请求就不会与服务器进行通信
若命中直接从缓存中获取资源信息,包括缓存header信息,本次请求就不会与服务器进行通信
Cache-Control与Expires他们的作用是一样的,都是指明当前资源的有效期,
控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据
控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据
Expries是http1.0的标准,在HTTP/1.1之后被Cache-Control替代 Cache-Control的选择更多,如果同时设置的话,其优先级高于Expires
Expries的设置方式
Cache-Control的设置方式
Cache-Contro 的配置字段
Public:指示响应可被任何缓存区缓存。
Private:所有内容只有客户端可以缓存,也是Cache-Control的默认取值。
no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
max-age:也就是刚刚上面例子中用到的,max-age=xxx :缓存内容将在xxx秒后失效。
min-fresh:指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale:指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
Private:所有内容只有客户端可以缓存,也是Cache-Control的默认取值。
no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
max-age:也就是刚刚上面例子中用到的,max-age=xxx :缓存内容将在xxx秒后失效。
min-fresh:指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale:指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
协商缓存
规则:协商缓存最终由服务器来决定是否使用缓存,即客户端与服务器之间存在一次通信
协商缓存的标识也是在响应报文的HTTP头中和请求结果一起返回给浏览器的
控制协商缓存的字段分别有:Last-Modified / If-Modified-Since和Etag / If-None-Match
其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高
本地缓存
webStorage和cookie 以及indexDB
浏览器出现 from disk、from memory 的 策略是啥
from memory:内存中的缓存
不请求网络资源,资源在内存当中,一般脚本、字体、图片会存在内存当中
from disk:硬盘中的缓存
不请求网络资源,在磁盘当中,一般非脚本会存在内存当中,如css等
两者都是强缓存
三级缓存原理:
1、先查找内存,如果内存中存在,从内存中加载;
2、如果内存中未查找到,选择硬盘获取,如果硬盘中有,从硬盘中加载;
3、如果硬盘中未查找到,那就进行网络请求;
4、加载到的资源缓存到硬盘和内存;
2、如果内存中未查找到,选择硬盘获取,如果硬盘中有,从硬盘中加载;
3、如果硬盘中未查找到,那就进行网络请求;
4、加载到的资源缓存到硬盘和内存;
2. CORS 的简单请求和复杂请求的区别?
CORS:跨域资源共享,是一份浏览器技术的规范,用来避开浏览器的同源策略
CORS相关请求头设置
Access-Control-Allow-Origin :指示请求的资源能共享给哪些域。
Access-Control-Allow-Credentials: 指示当请求的凭证标记为 true 时,是否响应该请求。
Access-Control-Allow-Headers: 用在对预请求的响应中,指示实际的请求中可以使用哪些 HTTP 头。
Access-Control-Allow-Methods :指定对预请求的响应中,哪些 HTTP 方法允许访问请求的资源。
Access-Control-Expose-Headers: 指示哪些 HTTP 头的名称能在响应中列出。
Access-Control-Max-Age :指示预请求的结果能被缓存多久。
Access-Control-Request-Headers: 用于发起一个预请求,告知服务器正式请求会使用那些 HTTP 头。
Access-Control-Request-Method: 用于发起一个预请求,告知服务器正式请求会使用哪一种 HTTP 请求方法。
Origin :指示获取资源的请求是从什么域发起的。
Access-Control-Allow-Credentials: 指示当请求的凭证标记为 true 时,是否响应该请求。
Access-Control-Allow-Headers: 用在对预请求的响应中,指示实际的请求中可以使用哪些 HTTP 头。
Access-Control-Allow-Methods :指定对预请求的响应中,哪些 HTTP 方法允许访问请求的资源。
Access-Control-Expose-Headers: 指示哪些 HTTP 头的名称能在响应中列出。
Access-Control-Max-Age :指示预请求的结果能被缓存多久。
Access-Control-Request-Headers: 用于发起一个预请求,告知服务器正式请求会使用那些 HTTP 头。
Access-Control-Request-Method: 用于发起一个预请求,告知服务器正式请求会使用哪一种 HTTP 请求方法。
Origin :指示获取资源的请求是从什么域发起的。
简单请求:
1. 看http请求方法:HEAD、GET、POST
2. 看请求头:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type
其中Content-Typede的值只能是:application/x-www-form-urlencoded、multipart/form-data、text/plain
3. 不会触发CORS预检的请求称为简单请求
复杂请求:
只要不是简单请求那就是复杂请求
复杂请求表面上看起来和简单请求使用上差不多,但实际上浏览器发送了不止一个请求 其中最先发送的是一种"预请求",也就是options
此时作为服务端,也需要返回"预回应"作为响应, 预请求实际上是对服务端的一种权限请求,只有当预请求成功返回,实际请求才开始执行
此时作为服务端,也需要返回"预回应"作为响应, 预请求实际上是对服务端的一种权限请求,只有当预请求成功返回,实际请求才开始执行
3. Token 一般是存放在哪里? Token 放在 cookie 和放在localStorage、sessionStorage 中有什么不同?
Token:访问资源的凭证
一般是用户通过用户名和密码登录成功之后,服务器将登陆凭证做数字签名,加密之后得到的字符串作为 token
然后在用户登录成功之后会返回给客户端
一般是用户通过用户名和密码登录成功之后,服务器将登陆凭证做数字签名,加密之后得到的字符串作为 token
然后在用户登录成功之后会返回给客户端
将token存放在webStorage中的话,是可以通过同域的js来访问的 ,就会导致很容易受到xss攻击,特别是项目中引入很多 第三方js类库的情况下,如果js脚本被盗用,那攻击者就 可以轻易访问你的网站,webStorage作为一种储存机制,在传输过程中是不会执行任何安全标准的
如果是将token存放在cookie中,我们可以指定 httponly,来防止被Javascript读取,也可以指定secure,来保证token只在HTTPS下传输,缺点是不符合Restful 最佳实践,容易受到CSRF攻击
XSS攻击:cross-site Scripting 跨站脚本攻击
这是一种注入代码攻击 恶意攻击者在目标网站上注入script代码,当访问者浏览网站的时候通过执行注入的script代码达到窃取用户信息,盗用用户身份等
这是一种注入代码攻击 恶意攻击者在目标网站上注入script代码,当访问者浏览网站的时候通过执行注入的script代码达到窃取用户信息,盗用用户身份等
CSRF跨站点请求伪造(Cross—Site Request Forgery)
利用用户已登录的身份,在用户毫不知情的情况下,以用户的名义完成非法操作
利用用户已登录的身份,在用户毫不知情的情况下,以用户的名义完成非法操作
4. WebSocket 是怎么实现点对点通信和广播通信的?
定义:webSocket是一种全双工通信协议,让服务端和客户端通信变得简单 最大的特点是可以通过服务端主动推送消息到客户端
WebSocket 区分广播通信及点对点通信核心在于区分每一个连接的socket对象
广播通信需要对于非自身的所有连接的socket对象进行通信
点对点通信,通过关联用户及socket对象,且保存每一个socket连接 查找指定的socket对象来达到发送指定socket连接的目的
5. 浏览器的组成
6. 从输入URL到页面展示,这中间发生了什么
整体流程
1. 浏览器进程发出URL请求给网络进程
2. 网络进程接收到URL请求后,发起网络请求,然后服务器返回HTTP数据到网络进程,
网络进程解析HTTP响应头数据,并将其转发给浏览器进程
网络进程解析HTTP响应头数据,并将其转发给浏览器进程
3. 浏览器进程接收到网络进程的响应头数据后,
发送CommitNavigation消息到渲染进程,发送CommitNavigation时会携带响应头、等基本信息。
发送CommitNavigation消息到渲染进程,发送CommitNavigation时会携带响应头、等基本信息。
4. 渲染进程接收到CommitNavigation消息之后,便开始准备接收HTML数据,
接收数据的方式是直接和网络进程建立数据管道
接收数据的方式是直接和网络进程建立数据管道
5. 最后渲染进程会像浏览器进程“确认提交”,这是告诉浏览器进程,说我已经准备好接受和解析页面数据了
6. 最后浏览器进程更新页面状态
详细流程
1. 用户输入URL
浏览器会根据用户输入的信息判断是搜索还是网址,如果是搜索内容,就将搜索内容+默认搜索引擎合成新的URL;如果用户输入的内容符合URL规则,浏览器就会根据URL协议,在这段内容上加上协议合成合法的URL
用户输入完内容,按下回车键,浏览器导航栏显示loading状态,但是页面还是呈现前一个页面,这是因为新页面的响应数据还没有获得。
2. URL 请求过程
浏览器进程将构建请求行数据,然后IPC(进程间通信)将URL请求发送给网络进程
3. 网络进程获取到URL,先去本地缓存中查找是否有缓存文件,如果有,拦截请求,直接200返回;否则,进入网络请求过程
4. 网络进程请求DNS返回域名对应的IP和端口号,如果之前DNS数据缓存服务缓存过当前域名信息,就会直接返回缓存信息;否则,发起请求获取根据域名解析出来的IP和端口号,如果没有端口号,http默认80,https默认443。如果是https请求,还需要建立TLS连接
5. 在进程TCP连接的过程中,Chrome有个机制,同一个域名下最多只能建立6个TCP连接,如果在同一个域名下有10个请求发生,那么其中4个请求会进入等待转台,直至进行中的请求完成。如果请求个数小于6,会直接建立TCP连接
6. TCP三次握手建立连接,http请求加上TCP头部——包括源端口号、目的程序端口号和用于校验数据完整性的序号,向下传输。
7. 网络层在数据包上加上IP头部——包括源IP地址和目的IP地址,继续向下传输到底层
8. 底层通过物理网络传输给目的服务器主机,紧接着目的服务器主机网络层接收到数据包,解析出IP头部,识别出数据部分,将解开的数据包向上传输到传输层
9. 目的服务器主机传输层获取到数据包,解析出TCP头部,识别端口,将解开的数据包向上传输到应用层
10. 应用层HTTP解析请求头和请求体,如果需要重定向,HTTP直接返回HTTP响应数据的状态code301或者302,同时在请求头的Location字段中附上重定向地址,浏览器会根据code和Location进行重定向操作;如果不是重定向,首先服务器会根据 请求头中的If-None-Match 的值来判断请求的资源是否被更新,如果没有更新,就返回304状态码,相当于告诉浏览器之前的缓存还可以使用,就不返回新数据了;否则,返回新数据,200的状态码,并且如果想要浏览器缓存数据的话,就在相应头中加入字段 Cache-Control:Max-age=2000
11. 数据传输完成,TCP四次挥手断开连接。如果,浏览器或者服务器在HTTP头部加上如下信息,TCP就一直保持连接。保持TCP连接可以省下下次需要建立连接的时间,提示资源加载速度数据传输完成,TCP四次挥手断开连接。如果,浏览器或者服务器在HTTP头部加上Connection:Keep-Alive,TCP就一直保持连接。保持TCP连接可以省下下次需要建立连接的时间,提示资源加载速度
12. 网络进程将获取到的数据包进行解析,根据响应头中的Content-type来判断响应数据的类型,如果是字节流类型,就将该请求交给下载管理器;如果是text/html类型,就通知浏览器进程获取到文档准备渲染
Content-Type 的值是 application/octet-stream,显示数据是字节流类型的
text/html 页面
13. 浏览器进程获取到通知,根据当前页面B是否是从页面A打开的并且和页面A是否是同一个站点(根域名和协议一样就被认为是同一个站点),如果满足上述条件,就复用之前网页的进程,否则,新创建一个单独的渲染进程
14. 浏览器会发出“提交文档”的消息给渲染进程,渲染进程收到消息后,会和网络进程建立传输数据的“管道”,文档数据传输完成后,渲染进程会返回“确认提交”的消息给浏览器进程浏览器会发出“提交文档”的消息给渲染进程,渲染进程收到消息后,会和网络进程建立传输数据的“管道”,文档数据传输完成后,渲染进程会返回“确认提交”的消息给浏览器进程
15. 浏览器收到“确认提交”的消息后,会更新浏览器的页面状态,包括了安全状态、地址栏的 URL、前进后退的历史状态,并更新web页面,此时的web页面是空白页
16. 渲染进程对文档进行页面解析和子资源加载,HTML 通过HTM 解析器转成DOM Tree,CSS按照CSS 规则和CSS解释器转成CSSOM TREE,两个tree结合,形成render tree(不包含HTML的具体元素和元素要画的具体位置),通过Layout可以计算出每个元素具体的宽高颜色位置,结合起来,开始绘制,最后显示在屏幕中新页面显示出来
7. 浏览器如何渲染UI
1. 先将 HTML解析成一个DOM树
2. 将 CSS解析成 CSS Rule Tree
从右往左读取选择器
为什么 id选择器大于类选择器,类选择器大于元素选择器?匹配的选项由少到多
3. 根据DOM树和CSS规则来构造 Rendering Tree
4. 然后进入布局(Layout)。计算节点在页面上的位置
5. GPU 绘制
6. js解析
解析器遇到 script标记时立即解析并执行脚本。文档的解析将停止,直到脚本执行完毕
如果脚本是外部的,那么解析过程会停止,直到从网络同步抓取资源完成后再继续。
目前浏览器的script标签是并行下载的,他们互相之间不会阻塞,但是会阻塞其他资源(图片)的下载
所以为了用户体验,后来有了async和defer,将脚本标记为异步,不会阻塞其他线程解析和执行。
标注为“defer”的script不会停止文档解析,而是等到解析结束才执行
标注为“async”只能引用外部脚本,下载完马上执行,而且不能保证加载顺序
8. 重排和重绘
重绘不一定会引起重排,重排会引起重绘
重排:部分渲染树(或者整个渲染树)需要重新分析并且节点尺寸需要重新计算,表现为重新生成布局,重新排列元素
重绘:由于节点的几何属性发生改变或者由于样式发生改变,例如改变元素背景色时,屏幕上的部分内容需要更新,表现为某些元素的外观被改变
如何触发重排和重绘?
添加、删除、更新DOM节点
通过display: none隐藏一个DOM节点-触发重排和重绘
通过visibility: hidden隐藏一个DOM节点-只触发重绘,因为没有几何变化
移动或者给页面中的DOM节点添加动画
添加一个样式表,调整样式属性
用户行为,例如调整窗口大小,改变字号,或者滚动。
如何避免重绘或者重排?
通过改变class的方式来集中改变样式
通过createDocumentFragment创建一个文档碎片,然后在此节点上批量操作,最后插入DOM树中,因此只触发一次重排
提升为合成层
9. 同源策略,跨域
同源策略
安全机制,指"协议+域名+端口"三者相同
浏览器中的大部分内容都是受同源策略限制的,但是 img,link,script三个标签不受限制
跨域
jsonp
cors
Nginx 反向代理
WebSocke
window.name + iframe
location.hash + iframe
document.domain + iframe
postMessage
Node中间件代理(两次跨域)
10 WebSocket
定义:Websocket是一个全新的、独立的协议,基于TCP协议,与http协议兼容
优点:真正意义上的实时双向通信,性能好,低延迟
缺点:独立与http的协议,因此需要额外的项目改造,使用复杂度高,必须引入成熟的库,无法兼容低版本浏览器
11 Web Worker
作用:就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行
1. 主线程与Worker线程通过方法postMessage相互传递信息
2. 主线程与Worker线程通过事件onmessage接收相互传递的消息
3. Worker中引入第三方js使用方法importScripts([url,])
4. 主线程调用worker.terminate()结束线程
5. Worker线程通过调用this.close()结束自身线程
12 HTTP keep-alive
又称长链接,就是能在多次 HTTP 之间重用同一个 TCP 连接,从而减少创建/关闭多个 TCP 连接的开销
http 1.0中默认是关闭的,需要在http头加入"Connection: Keep-Alive"
目前大部分浏览器都是用http1.1协议,也就是说默认都会发起Keep-Alive的连接请求了
13. GET和POST的区别
GET
1. 数据在URL中,URL的长度最多为2048个字符(浏览器的限制,不是HTTP)
2. 可被缓存
3. 请求参数保留在浏览器历史记录中
4. 请求可被收藏为书签
5. 数据类型为ASCLL码
POST
1 数据在请求体中,长度没限制
2. 不能被缓存
3. 请求参数不能保存在浏览历史中
4. 不能收藏为标签
5. 数据类型无限制
14. HTTP状态码
1xx表示请求已被接受,但需要后续处理
100(Continue):客户端应继续发送请求
101 协议切换
2xx 表示请求已成功
200(OK):请求已成功
201(Created):请求已成功,并且有个新的资源根据请求需要而创建
202(Accepted):服务器已接收请求,但是尚未处理,比如POST一个资源应当返回201,但由于性能原因未能立即创建,可以返回202
204(No Content):服务器成功处理了请求,但不需要返回任何实体内容,204响应禁止包含任何消息体。浏览器收到该响应后不应产生文档视图的变化
205(Reset Content):服务器成功处理了请求,但不需要返回任何实体内容,205响应禁止包含任何消息体。 与204不同的是,返回此状态码的响应要求请求者重置文档视图
3xx 一般指重定向 Location
301(Moved Permanently):被请求的资源已永久移动到新位置,永久性跳转,搜索引擎记录,权重迁移
302(Found):在一个网站或网页在短时间内临时移到其它位置的情况下使用,临时性跳转,容易网址劫持
304(Not Modified):一般用于静态文件的缓存
4xx 一般是客户端出错
400(Bad Request):一般是参数不正确
401(Unauthorized):未授权 登录
403(Forbidden):服务器拒绝执行此请求 无权限
404(Not Found):一般是请求路径错误,导致资源找不到
405(Method Not Allowed):请求方法不一致
413(Request Entity Too Large):一般是请求数据大小超过服务器设置的大小
5xx 一般是服务器错误
500(Internal Server Error):后台服务错误
502(Bad Gateway):收到了无效响应,一般是服务器重启时出现
504(Gateway Time-out):加载超时
15. HTTP 报文
请求行
方法 路径 http版本号
请求头
host: 主机域名
Connection: keep alive
cookie
Accept-Encodeing: gzip
Accrpt-Language:zh-cn
content-type: text/html、text/xml、text/plain、text/css、text/javascript、image/gif、image/jpeg、image/png、application/json、multipart/form-data
请求体
16.OSI七层模型
子主题
17. 怎么防止篡改参数
参数加密(参数存放签名),服务端接收后对除签名外的其他参数进行加密,然后对比,一致则合法
基于timestamp的方案
每次请求加上时间戳,接收后两次时间对比,超出某一个界限则认为请求无效
基于nonce的方案
基于IP,时间戳等生成一个随机字符串
webpack优化
入口 entry
多入口时entry是个对象
输出 output
plugins
webpack-dev-server
webpack-dev-server提供了一个简单的 web 服务器, 并且能够实时重新加载
html-webpack-plugin
htmlwebpackplugin会在打包结束后,⾃动⽣成⼀个html⽂件,并把打包⽣成的js模块引⼊到该html中
配置
filename
template
inject
true 默认值,script标签位于html文件的 body 底部
body script标签位于html文件的 body 底部
head script标签位于html文件的 head中
false 不插入生成的js文件,这个几乎不会用到的
body script标签位于html文件的 body 底部
head script标签位于html文件的 head中
false 不插入生成的js文件,这个几乎不会用到的
copy-webpack-plugin
将静态文件复制到构建目录
配置
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
to: config.build.assetsSubDirectory,
ignore: ['.*']
mini-css-extract-plugin
extract-text-webpack-plugin(webpack4已放弃此插件)
extract-text-webpack-plugin(webpack4已放弃此插件)
css样式分离插件
optimize-css-assets-webpack-plugin
css压缩插件
其他配置
assetsSubDirectory: 'static', // todo 把所有的静态资源打包到 dist下的 assets文件夹下
assetsPublicPath: '/AIOBS/', // todo 代表生成的index.html文件,里面引入资源时,路径前面要加上 /AIOBS/,也就是assetsPublicPath的值 ``
assetsRoot: path.resolve(__dirname, '../dist'), // todo 在指定目录下输出资源文件
优化
tree shaking
消除不需要的引用。只能用于ES6模块
optimization: {
// 使用tree-shaking
usedExports: true, // mode为production时,默认开启
},
// 使用tree-shaking
usedExports: true, // mode为production时,默认开启
},
Scope Hoisting
分析出模块之间的依赖关系,把那些被引用了一次的模块合并,减少代码体积
3 升 4 相关问题
webpack-dev-server 版本低 需升级
webpack4 中把 webpack-cli 抽离出来了,所以需要单独安装 webpack-cli3.x版本
html-webpack-plugin 不兼容 需升级
eslint-loader 版本低 升级
webpack4 需要使用vue-loader 15.0.0 至少。所以升级vue-loader
需安装vue-loader的plugin
plugins: [
// todo 先读取compiler.option.module.rule,找到给.vue或.vue.html文件进行配置的那些个rule,然后把vueRule放到最后(里面包含了你配置的vue-loader)
new VueLoaderPlugin()
],
// todo 先读取compiler.option.module.rule,找到给.vue或.vue.html文件进行配置的那些个rule,然后把vueRule放到最后(里面包含了你配置的vue-loader)
new VueLoaderPlugin()
],
删除 webpack.optimize 和 CommonsChunkPlugin 配置,原因是已经被启用
重新添加splitChunks配置,位置在 optimization 属性下
// maxSize: 2048000, // todo 将大于maxSize的大块拆分成较小的部分。零件的尺寸至少为minSize
// minSize: 1000000, // todo 生成块的最小大小(以字节为单位
cacheGroups: { // todo 缓存组
vendor: { // todo 抽取来自 node_modules 文件夹下的第三方代码,优先级权重为10
name: "vendor",
test: /[\\/]node_modules[\\/]/,
chunks: "all",
minChunks: 2,
priority: 10 // 优先级
},
common: { // todo 抽取来自 src 文件夹下的代码,优先级权重为5
name: "common",
test: /[\\/]src[\\/]/,
chunks: "all",
minChunks: 2,
priority: 5
}
}
// minSize: 1000000, // todo 生成块的最小大小(以字节为单位
cacheGroups: { // todo 缓存组
vendor: { // todo 抽取来自 node_modules 文件夹下的第三方代码,优先级权重为10
name: "vendor",
test: /[\\/]node_modules[\\/]/,
chunks: "all",
minChunks: 2,
priority: 10 // 优先级
},
common: { // todo 抽取来自 src 文件夹下的代码,优先级权重为5
name: "common",
test: /[\\/]src[\\/]/,
chunks: "all",
minChunks: 2,
priority: 5
}
}
4 放弃的插件
extract-text-webpack-plugin CSS样式分离的插件
参考文献:
你所知道的3xx状态码
如何理解HTTP响应的状态码?
HTTP 响应代码(MDN)
0 条评论
下一页