url渲染 1、进行DNS解析,域名到对应的ip地址,dns解析耗时,可用dns-prefetch预解析优化
2、TCP三次握手,建立TCP链接 - c -> s 发送询问 - s -> c 回复询问,并询问 - c -> s 回复询问 四次挥手 - 主 -> 被 关闭主动通道,只能被动接收 - 被 -> 主 收到关闭消息 - 被 -> 主 关闭主动通道 - 主 -> 被 收到关闭消息 https建立TLS加密 - 验证证书,确认加密方式 五层因特网协议栈 - 从应用层的发送http请求,到传输层通过三次握手建立tcp/ip连接,再到网络层的ip寻址,再到数据链路层的封装成帧,最后到物理层的利用物理介质传输
浏览器缓存机制 - 强制缓存 - 浏览器直接从缓存中读取文件,不需要发送请求 - http1.0 响应头 => expires 绝对时间,浏览器时区和服务器时区不一致时 => 缓存失效 - http1.1 响应头 => cache-control 相对时间 - 协商缓存 - 浏览期发送请求,服务器决定是否使用缓存 - Last-Modified/if-Modified-Since 时间粒度是秒 - Etag/If-None-Match 根据文件内容生成一个标记
获取html文件,构建DOM树
下载css文件,构建style树
DOM树和style树组合成渲染树
下载js文件,运行js
js运行会阻塞DOM树的渲染 4、 layout布局、绘制像素
queue stack
promise
promise 异步编程的一种解决方案,可以将异步回调写法变成链式调用写法,流程更加清晰,代码更加优雅
三个状态,两个过程,一些方法
pending、fulfilled、rejected
pending -> fulfilled == resolve
pending -> rejected == reject
then 接收两个回调,成功回调,失败回调
catch 接收一个失败回调,也可以抛出代码错误
Promise.all 接收一个promise数组,都成功时返回成功的数组,有一个失败,返回失败的错误
Promise.race 返回第一个改变状态的结果
Promise.allSettled 所有promise实例结束后才会返回,成功的返回value,失败的返回err
Promise.any 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
all和race传入的数组中如果有会抛出异常的异步任务,那么只有最先抛出的错误会被捕获,并且是被then的第二个参数或者后面的catch捕获;但并不会影响数组中其它的异步任务的执行。
ata.filter(({id}) => {
return selectedIds.includes(id);
})
const ids = {};
selectedIds.forEach(id => ids[id] = 1);
data.filter(({id}) => {
return !!ids[id];
})
debounce
function debounce(fn, wait){
let timer = null;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(fn, wait);
}
}
throttle
function (fn, delay) {
let prev = null;
let timer = null;
return function() {
const now = Date.now();
if(prev && now - prev > delay) {
clearTimeout(timer);
timer = sertTimeout(fn, delay);
} else {
fn.apply(this, arguments)
prev = Date.now();
}
}
}
quickSort
function quickSort(arr) {
if(arr.length <= 1) return arr;
const pivotIndex = Math.floor(arr.length / 2);
const pivot = arr.splice(pivotIndex, 1);
let left = []
let right = [];
for (let i = 0; i < arr.length; i++) {
if( pivot > arr[i]) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return quickSort(left).concat(pivot, quickSort(right));
}
// 空间换时间 o(n2) => o(n)
d
react
react UNSAVE_
componentWillMount
componentWillReceiveProps
componentWillUpdate
挂载阶段
constructor
static getDerivedStateFromProps(nextProps, prevState)
render
componentDidMount
更新阶段
getDerivedStateFromProps
shouldComponentUpdate(nextProps, nextState)
render
getSnapshotBeforeUpdate(prevProps, prevState)
componentDidUpdate(prevProps, prevState, snapshot)
卸载阶段
state -> setState
react fiber
基于浏览器的单线程调度算法
16之前使用的是递归,很难中断,16之后使用循环
fiber 一种将递归diff,拆分成无数个小任务的算法,他随时能够中断,恢复。停止恢复的时机取决于当前帧内还有没有时间用于计算
time slice
时间分片基于可中断、重启的fiber架构,中断当前的渲染,执行紧急任务,保证页面的流畅运行
redux
store
state
action
action creator
reducer
dispatch
1、用户通过dispatch方法发出action
2、store自动调用reducer,接收action和当前的state,返回新的state
3、state改变,store调用监听函数,更新view
react-redux
provider 从最外部封装整个应用,向connect模块传递store
connect 连接react和redux
获取state
将state和action通过props的方式传入原组件
监听state变化
react-thunk
异步中间件
使dispatch可以传递一个函数
把redux流程外的逻辑塞到了流程内
script 标签中增加corssorigin属性
react hooks
useState
useEffect
useRef
useCallback
useMome
useContext
useReducer
闭包问题,过时的闭包问题
useEffet中拿不到最新的state
异步更新问题
super
子类调用super,传递this,使子类this获取父类中的属性和方法
TypeScript
diff
.js \ .ts
支不支持ES6
弱类型 / 强类型
运行时暴露错误 / 编译时暴露错误
接口是什么?
类是什么?
创建对象的模版,具有逻辑实体,有属性和方法
封装、继承、多态、抽象
使用class创建
装饰器
一种特殊类型的声明,可用于类,方法,访问器,属性,参数
用@符号为前缀的函数,
以声明的方式将注释和元数据添加到现有的代码中
泛型
可重用组件方法的工具,创建处理多种数据类型的组件
定义时用标示,引用时用具体类型替换
interface和type的区别
基本类型
number,string,boolen,null,undefined,symbol
类型断言
可以用来手动指定一个值的类型, 断定这个变量的类型是啥
<类型>值 or 值 as 类型
类型推导 - ts根据一定的定义可以推导出变量的类型
类型保护 - 对于多类型的变量,当使用typeOf判断之后可以确定变量的类型
类型别名 - type 声明一个别名 类似接口
函数重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
可以重复定义一个函数的类型
declare
声明一个变量的定义,编译完会删除
用于声明第三方库暴露的变量
闭包
当函数可以访问并记住所在的词法作用域时,就产生了闭包。
闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,内部函数访问外部函数的局部变量,利用闭包可以突破作用域链,将函数内部的变量和方法传递到外部。
闭包特性:
(1)函数内再嵌套函数
(2)内部函数可以引用外层的参数和变量
(3)参数和变量不会被垃圾回收机制回收 (过时了)
面向对象oop
面向对象编程就是把需求抽象成一个对象,对这个对象进行分析,为其添加对应的特征属性和行为方法,我们将这个对象称为类
如何优雅的写出符合W3C的代码
合理的使用html标签,语义化标签,块标签,行内标签,行内块标签
规范化书写css顺序,几何形状类型,位置类型,样式类型,尽量少的嵌套css
尽量使用ES6等新语法书写js,代码简洁,易读
合理的书写注释
变量命名的规范化,语义化
前端安全
XSS 跨· cross site scripting
类型
储存型 存到数据库-》用户获取数据-》执行 评论、商品评价
反射型 存到url上-》服务端获取-》返回给前端-》前端执行 跳转
DOM型 存到url上-》前端获取参数-》执行
防御
字符转义,
dengerouslySetInnerHTML/v-html
cookie的httpOnly
csp
验证码
CSRF 跨站请求伪造 cross site request forgevies
方式
get请求 通过img
post请求 通过自执行的form
a链接 引导用户点击
防御
请求中添加token
双重cookie验证
同源检测
webpack - 对webpack的理解 - 是一个模块打包工具,管理项目中的模块依赖,进行合并,拆分,编译成静态资源 - loader和plugin的区别 - loader是转换器,本质是一个函数,对接收到的内容进行转换,对其他类型的资源进行转义等预处理工作,在rules中配置,比如ts-loader,scss-loader - plugin是扩展器,是一个插件,对webpack的功能进行扩展,在plugins中配置,比如 html-webpacl-plugin,unlifyjs-webpack-plugin - webpack热更新的原理 - 热更新又叫热替换,这个机制可以做到不刷新浏览器的情况下,用变更的模块替换旧的模块,达到视图的自动更新 - 核心就是通过webSocket建立服务端与客户端的链接,当服务端监听到文件变动时,向客户端推送消息,客户端拉取最新文件,进行增量更新
vue vue.js是采用的数据劫持结合发布者-订阅者模式的方式,通过object.defineProperty()来劫持各个属性的setter/getter 在数据变动时,发布消息给订阅者,触发相应的监听回调
具体步骤: 1)需要observe(观察者)的数据对象进行遍历,包括子属性对象的属性,都加上setter和getter,这样的话, 给这个对象的某个值赋值,就会触发setter,那么就能监听到数据的变化 2)compile(解析)解析模版指令,将模版中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数, 添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图 3)watcher(订阅者)是observer和compile之间通信的桥梁,主要做的事情是 1>在实例化时往属性订阅器(dep)里面添加自己 2>自身必须有一个update()方法 3>待属性变动dep.notice()通知时,能够调用自身的update()方法,并触发compile中绑定的回调, 4)mvvm作为数据绑定的入口,整合observer,compile和watcher来监听自己的model数据变化,通过compile来解析编译模版, 最终利用watcher搭起observer和compile之间的通信桥梁,达到数据变化->更新视图:视图交互变化->数据model变更的双向绑定效果
渐进式框架
vue和react一样都是一个渲染UI的js库,本身是不做路由管理、数据管理的,如果需要可以增加插件进行渐进式开发
vue的声明式渲染
声明一个组件的实例,绑定数据,方法,在html模版中进行插值绑定,实现数据与视图的绑定,不用操作DOM进行数据的初始化和更新
MVC/MVVM
MVC 用户操作-》控制器controller-》数据模型model-》视图view-》用户操作
MVVM 视图view 《-》视图模型viewModel 《-》 数据模型model
VM就是基于controler上封装了一层,帮助用户实现了一些逻辑
computed和watch的区别
computed计算属性,依赖其他属性值,当依赖属性变化时重新计算,有缓存
watch监听,当监听属性变化时执行异步操作,比如请求数据
vue中跟数组赋值
使用vue重写的数组splice方法,
使用vm.set方法
vue生命周期
beforeCreate 组件创建之前
created 组件实例创建完成 可以请求数据
beforeMount 组件挂载之前 可以请求数据
mounted 组件挂载完成 可以请求数据
beforeUpdate 更新之前
updated 更新完成
beforeDestory 卸载之前
destoryed 卸载完成
activited 组件激活时调用,keep-alive专属
deactivited 组件失活时调用,keep-alive专属
对keep-alive的理解
vue内置的一个组件,可以使被包含的组件保留状态,阻止被重复渲染
一般跟路由组件结合使用,用于缓存路由组件
两个属性include/exclude
两个方法 activited/deactivited
vue中组件通信
props
$emit
全局事件总线 b u s . bus. b u s . emit/ b u s . bus. b u s . on
vuex
SSR的优缺点
vue-rouder的路由模式
hash 使用URL 哈希值作为路由,支持所有浏览器
hash实现的原理
url中的hash值,只是客户端的一种状态,不会向服务器发送
hash值改变,都会在浏览器访问历史中增加一个记录,因此能通过浏览器按钮控制hash
可以通过 拼接hash的url,或者修改localtion.hash,改变hash值
通过hashchange事件监听hash的变化,从而实现路由跳转
history 依赖HTML5 history api和服务端配置
history实现的原理
HTML提供的两个API history.pushState(),history.replaceState()在不刷新浏览器的情况下,操作浏览器的历史记录
pushState,replaceState实现url的变化
使用popState事件监听url的变化触发路由跳转
支持所有js运行环境,如nodejs服务端
proxy与Object.definedPropProperty区别
proxy监听对象的变化,可以直接监听数组的变化
proxy返回的是新对象,直接操作对象达到目的,denfineProperty需要遍历属性操作
proxy有兼容性问题
虚拟DOM的原理
用js对象模拟真实DOM树,对真实DOM进行抽象
使用diff算法对比两颗虚拟DOM树的差异
将差异的部分更新成真实的DOM
虚拟DOM的优缺点
优点
性能优化,保证性能下限,性能普世性,在不用手动优化的情况下,也能保持不错的性能
无需手动操作DOM
跨平台,与浏览器DOM无关,例如服务端渲染
缺点
首次渲染慢,初始渲染需要虚拟DOM计算,生成大量的真实DOM
无法进行极致优化
虚拟DOM中key的作用
key是虚拟DOM对象中列表数据的标示,在进行虚拟DOM的diff算法是,有很大作用
当列表数据发生变化时,通过key进行虚拟DOM的diff算法
当key没有变时
item没有变,直接使用真实DOM
item变了,对原来真实的DOM进行数据更新
当key变了
key为index的问题
添加/删除/排序 -》 产生没有必要的真实DOM更新 -》页面渲染没问题,效率低
如果item有输入框 -》 产生错误的真实DOM更新 -》页面渲染有问题
解决,使用唯一标示,比如id
vue3.0
proxy -》 Object.defineProperty
模版,更改了作用域插槽,改成了函数的形式,避免了插槽的变化引起父组件的更新
对象式的组件声明方式,对typescript的结合更加友好
vue与react的比较
react的jsx语法vue的.vue语法,都需要编译后使用
都使用了虚拟DOM
基本单位都是组件
都是渐进式框架
react是单项数据流MVC模式,vue是双向数据绑定MVVM模式
发布-订阅模式(观察者模式?)
发布者
缓存的订阅者列表
发布消息,遍历缓存列表中的订阅者,调用订阅者的方法
obj.list = [] obj.listen = function obj.trigger = function
函数柯里化
是一种函数的高阶用法,用于函数转换,可以将一个函数多次调用,保存之前调用的参数变量
具体原理就是返回多个包装器
如何理解 HTML 语义化
让人更易懂
让机器更易懂,利于SEO
在没有css时,能展现出基本的结构样式
script 标签中 defer 和 async 的区别
script :会阻碍 HTML 解析,只有下载好并执行完脚本才会继续解析 HTML。
async script :解析 HTML 过程中进行脚本的异步下载,下载成功立马执行,有可能会阻断 HTML 的解析。
defer script:完全不会阻碍 HTML 的解析,解析完成之后再按照顺序执行脚本。
作用域链 函数内部可以直接读取全局变量 在函数外部自然无法读取函数内的局部变量。 对象访问变量时,先在自身作用域下查找,找不到时会一级一级地向上寻找所有父对象的变量。这就是作用域链
原型链 每个对象都有一个隐式原型__proto__,指向创建该对象的函数的原型prototype 访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链。
闭包 函数作为返回值,函数作为参数传递。 闭包就是能够读取其他函数内部变量的函数 只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。 它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。