- TCP和UDP的区别
- GET和POST的区别
参考 GET和POST两者的区别参考 面试官:说一下 GET 和 POST 的区别?
- GET 参数通过 URL传值,参数可见且不够安全,不能用来传递敏感信息,而 POST 参数放在 Request body 中,参数不可见,相对而言比较安全;
- GET 请求在 URL 中传送的数据大小是有限制的(一般不超过2k-4k,取决于浏览器),而 POST 请求中的数据大小长度根据后台配置文件设定,理论上没有限制;
- GET 在浏览器回退时是无害的,而 POST 在浏览器回退时会再次提交请求;(GET 会将请求参数放在请求的 URL 中,回退操作实际上浏览器会从之前的缓存中拿结果,POST 每次调用都会创建新的资源)
- GET 请求会被浏览器主动 cache,而 POST 除非手动设置,否则不会;(浏览器缓存分为强缓存和协商缓存)
- GET 产生的 URL 地址可以被 Bookmark,而 POST 不可以;(GET 请求会把参数带到 URL 中,可以此保存浏览器书签) GET 请求参数会被完整地保留在浏览器历史记录里,而 POST 中的参数不会被保留;(道理同上)
- GET 请求只能进行 URL 编码,而 POST 支持多种编码方式; 对参数的数据类型,
- GET 只接受 ASCII 字符,而 POST 没有限制;(URL 是 HTTP 的一个首部,根据约定,一定是 ASCII 字符的)
- GET 请求产生一个 TCP 数据包,而 POST 请求产生两个数据包;
- 浏览器会自动缓存GET请求,而POST方法需要手动设置(响应头添加cache-control或者expires)。
- RFC标准定义POST缓存应该使请求实体无效。
- 上面的可以缓存指RFC标准定义的,实际某些浏览器可能无论如何都不会去缓存POST(如Firefox)
- 301和302的区别
- npm管理
package-lock冲突处理
其实删除 lock 不是很安全的操作,你可以先 stash 你的 package.json,然后全盘接收 别人的 package-lock,然后把你的 package.json pop 出来,解决冲突后,重新安装一下,更新 package-lock,再提交。
- 大文件上传
利用Blob.prototype.slice()分割切片
- 观察者模式和订阅发布模式的区别
- scoped实现
vue中的scoped属性的效果主要通过PostCSS转译实现
PostCSS给一个组件中的所有dom添加了一个独一无二的动态属性,然后,给CSS选择器额外添加一个对应的属性选择器来选择该组件中dom,这种做法使得样式只作用于含有该属性的dom——组件内部dom。
- instanceof实现
function _instanceof(L, R) { if (typeof R !== 'function') { return false } R = R.prototype while(true) { if (L === null) return false if (L === R) return true L = L.__proto__ } } 复制代码
- Object.create
- new实例继承(缺点:对于null的结果不准)
Object.create = function(o) { if (typeof o !== 'object' || typeof o !== 'function') throw('TypeError: Object prototype may only be an Object or null') function Fn() {} Fn.prototype = o return new Fn() } 复制代码
- 浏览器属性__proto__
Object.create = function(o) { if (typeof o !== 'object' || typeof o !== 'function') throw('TypeError: Object prototype may only be an Object or null') const obj = {} obj.__proto__ = o return obj } 复制代码
- 父子组件生命周期执行顺序
创建
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
结合源码,子组件的构造函数是在render中进行createComponent的,但是render的执行在mounted函数中,而mounted函数中会先调用beforeMounte,随后才会创建渲染watcher执行render及update(patch)。
更新
父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
销毁
父beforeDestroyed -> 子beforeDestroyed -> 子destroyed -> 父destroyed
- attrs 和 listeners
attrs和listeners用于透传数据
<!-- A组件 --> <B :name="name" @click="xx"></B> 复制代码
<!-- B组件 attr只会透传B中`props中未定义的数据 --> <C v-bind="$attrs" v-on=“$listeners”></C> 复制代码
- webpack性能优化
- loader配置include/exclude缩小范围
- babelloader缓存
- happyPack开启多线程
- 组件封装原则
- 单一职责
- 通用原则
- 开放封闭
- keep-alive生命周期
- activated 组件激活(创建时也会)(在mounted之后)
- deactivated 组件失活(和beforeDestroy,destroyed互斥)
- 常见的请求content-type
- application/x-www-form-urlencoded 默认编码(Get和Post)
- multipart/form-data 表单文件
- application/json JSON
- http2.0
- 二进制数据帧
在http2.0中,在Http层又多分出了一层叫二进制分帧层,在这层会将待发送数据进行分帧,有不同的帧类型(head帧,data帧),每个帧中会封装它的数据信息,例如length,type,streamid,payload。
- 数据流
一个http数据可能会被分割成多个二进制帧,我们可以称其为数据流,其实也就是一个完整的消息,其唯一标识streamid。
- 多路复用
TCP发送数据的单位是数据包,在Http1.0中直接将数据字符串传递给TCP进行传输,所以得接收端完成接收才能确认这一次请求完成。通过上面的二进制分帧层对数据进行分帧封装后,数据就有了流标识,所以接收端不再需要接收完整数据后来确认当前数据属于哪个请求。所以就可以复用TCP连接,将多个数据流并行传递,并且接收端发送端的数据也可以并行,现在一个tcp可以同时传输多个http数据了,这就是多路复用。
注意这边所说的多路复用只是解决了应用层http的队首阻塞(在同一个TCP连接中需要等上一个hhtp响应才能进行下一个请求)但是没有解决TCP队首阻塞的问题(TCP需要序列号应答码机制来防止丢包)
- head压缩
http2.0会对首部字段进行压缩(大致原理有点像密码本,通过索引来替代对应的值。并且索引可以动态生成,比如第一次传输的head值进行算法生成对应索引,第二次就传递索引就行,这也算一种缓存实现。
- 服务端推送
服务端可以主动推送,这就为预发送提供机会。
- 流量控制及优先级控制
- web环境中强制要求https
- http3.0
- 使用udp替代tcp
- http和udp之间引入新协议quic协议(因为UDP无法做到可靠传输,所以通过quic来实现多路复用,安全加密及拥塞控制)
- csp
- hash,chunkhash,contenthash的区分
- 图片优化
- base64
- 雪碧图
- 压缩
- CDN
- 懒加载
- 预加载
- webp(document.createElement('canvas').toDataURL('image/webp', 0.5).indexOf('data:image/webp'))
- 响应式图片(picture source srcset sizes)
- 渐进式图片
- 骨架屏
几种方案
- puppeteer自动生成
- vue-content-loader自己定制(原理是通过svg简化骨架屏的css)
- UI生成骨架图
两个场景
- 路由页面(组件)中使用(结合请求时间,生命周期等实现)
- 首页渲染(可以独立在html中添加提高首屏渲染)
- treeShaking
记录下对treeshaking的进一步理解
- treeshaking从webpack2加入,webpack4可以0配置使用
- treeshaking需要mode为production才会生效(主要是TerserPlugin的功劳)
- treeshaking实现包括三步:1. 分析依赖 2. 标记可以treeshaking部分 3. 使用terser进行压缩shaking
- package的sideEffects属性标记是否允许副作用,也可以指定允许副作用的数组(对子模块也会生效),默认为true
- s
- ideEffects设置为false表明不允许副作用,副作用代码将被清除
// utils.js export const a = 'a' console.log('sideeffects') export const b = () => { console.log('b') } // main.js import { a, b } from './utils.js' // 1. ab都未被实际使用,所以会被清除 // 2. 如果允许副作用console会保留 如果不允许副作用console也会被清除(相当于不执行utils) 复制代码
- treeshaking只对ESM生效,因为静态分析是treeshaking的基础
- 导出的变量就算只被赋值也算是使用
// utils.js export const a = 'a' console.log('sideeffects') export const b = () => { console.log('b') } // main.js import { a } from './utils.js' // cache可能没被使用,无论sideeffect是否为true都会执行utils并且a被打包 const cache = a 复制代码
- TCP
- 三次握手四次挥手
- 拥塞控制
- 流量控制
- 慢开始 拥塞避免 快重传 快恢复
- 滑动窗口
- 丢包重发机制
- 微前端
原理:基于路由懒加载(import())及动态路由(addRouter),在导航守卫中进行拦截实现动态加载。微前端不同模块之间的通信可以通过vuex进行。
- webpack优化
- 高版本node webpack
- 缓存(loader-cache optimization的cache)
- 多进程(happyPack thread-loader optimization的thread)
- 明确范围(如babel-loader的include exclude)
- 查找路径(alias)
- hardsourcewebpackplugin
- 预编译(DLLPlugin)
- 缩减编译目标(Externals)
- treeshaking
- 动态polyfill
- speedmeasurewebpackplugin
- webpackbundleanalyse
- PurgeCSSPlugin(结合MiniCssExtractPlugin)
- 引用计数的问题
- 无法回收循环引用的对象
- 时间开销大(因为要时刻监控引用数值的修改)
- 内存泄漏
- 全局变量
- 闭包(闭包对象)
- 事件监听未销毁
- 循环引用
- vue组件更新
- 父组件update 子组件不一定update(仅由自身数据驱动renderWatcher决定)
- 父组件的renderWatcher并不一定出发子组件的renderWatcher,在patch中对于组件会执行updateChildComponent,仅仅做template之外的一些数据校验更新,子组件的重新执行仅仅依赖其数据(包括data及代理的props)
- localstorage sessionStorage cookie 区别
- iframe点击劫持
top指向
// 禁止被嵌入,否则自动跳转 // 顶层窗口(window) === 自身窗口(window) window.top === window.self 复制代码
- 校验
/^(.+)@(.+).(.+)$/i 复制代码
/(<([^>]+)>)/ig 复制代码
- 评论输出安全
实际可以直接使用text输出{{}},在后端可以做转义,前端可以使用textNode来转义
let textNode = document.createTextNode('<span>by zhangxinxu</span>'); let div = document.createElement('div'); div.append(textNode); console.log(div.innerHTML); 复制代码
<span>by zhangxinxu</span> 复制代码
- ESM和commonJS模块入口
{ "name": "moduleA", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "exports": { "import": "./dist/esm/index.js", "require": "./dist/cjs/index.js" } } 复制代码
笔记
1. 高阶组件
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。
高阶组件的概念来自React。其用于扩展组件但不修改基础组件,解决mixin的不足
- mixin带来隐式依赖。
- mixin是侵入式的,多次扩展将提高组件的复杂性。
因为React组件即函数,所以高阶组件其实就是高阶函数,其接受组件为参数,再返回新的组件(函数)
function WithConsole (WrappedComponent) { return class extends React.Component { componentDidMount () { console.log('with console: componentDidMount') } render () { return <WrappedComponent {...this.props}/> } } } 复制代码
但是对于Vue来说,高级组件的实现会比较复杂。因为我们一般编写Vue组件是通过声明对象式的
export default { // ... } 复制代码
虽然Vue在执行的时候会将我们定义的对象作为组件选项传入生成构造函数(所以Vue组件本质也是函数),但是这步在框架中进行,所以我们只能通过函数式组件来作为高阶组件
export default function WithConsole (WrappedComponent) { return { mounted () { console.log('I have already mounted') }, // 要点1 props: WrappedComponent.props, render (h) { return h(WrappedComponent, { // 要点2 on: this.$listeners, attrs: this.$attrs, props: this.$props }) } } } 复制代码
当需要处理slot的时候,还会更加麻烦一些。
2. 正向代理反向代理
- 正向代理(forward proxy):是一个位于客户端和目标服务器之间的服务器(代理服务器),为了从目标服务器取得内容,客户端向代理服务器发送一个请求并指定目标,然后代理服务器向目标服务器转交请求并将获得的内容返回给客户端。
正向代理,其实是"代理服务器"代理了"客户端",去和"目标服务器"进行交互。
- 反向代理(reverse proxy):是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请
- 求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
反向代理,其实是"代理服务器"代理了"目标服务器",去和"客户端"进行交互。
正向代理用途
- 突破访问限制
- 提高访问速度
- 隐藏客户端真实IP
反向代理用途
- 隐藏服务器真实IP
- 负载均衡
- 提高访问速度
- 提供安全保障
区别
- 正向代理其实是客户端的代理,帮助客户端访问其无法访问的服务器资源。反向代理则是服务器的代理,帮助服务器做负载均衡,安全防护等。
- 正向代理一般是客户端架设的,比如在自己的机器上安装一个代理软件。而反向代理一般是服务器架设的,比如在自己的机器集群中部署一个反向代理服务器。
- 正向代理中,服务器不知道真正的客户端到底是谁,以为访问自己的就是真实的客户端。而在反向代理中,客户端不知道真正的服务器是谁,以为自己访问的就是真实的服务器。
- 正向代理和反向代理的作用和目的不同。正向代理主要是用来解决访问限制问题。而
- 反向代理则是提供负载均衡、安全防护等作用。二者均能提高访问速度。
3. 跨域cookie
- 跨域请求不会自动携带cookie,需要主动配置相应的请求头携带cookie
xhr.withCredentials= true; 复制代码
- 图片可以通过crossOrigin属性设置为use-credentials携带cookie
4. 单点登录
单点登录(Single Sign On,SSO)是指在多个独立且又相互信任应用系统环境下,对多个应用系统提供访问控制属性,其中一个应用系统将用户认证信息映射到其他应用系统中,多个系统共享用户认证数据。简言之,即用户通过登录一个应用系统,就可以访问其他所有相互信任的应用系统,实现用户单点多系统登录。
5. JWT
JWT和SSO属于不同的两个概念,SSO指实现多系统共享认证的系统设计,而JWT属于实现用户认证的一种具体实现方式。SSO中的认证很多时候就是采用的JWT认证实现。
根据官网的定义,JSON Web Token(以下简称 JWT)是一套开放的标准(RFC 7519),它定义了一套简洁(compact)且 URL 安全(URL-safe)的方案,以安全地在客户端和服务器之间传输 JSON 格式的信息。
参考 JSON Web Token 入门教程参考 Server端的认证神器——JWT(一)
6. 高阶函数
高阶函数
高阶函数是对其他函数进行操作的函数,操作可以是将它们作为参数,或者是返回它们。
简单来说,高阶函数是一个接收函数作为参数或将函数作为输出返回的函数。
例如,Array.prototype.map,Array.prototype.filter 和 Array.prototype.reduce 是语言中内置的一些高阶函数。
7. 中间件
经常听后端同学说中间件,但是一直不知道什么叫做中间件,网上对于概念的解释也比较多。其中看到一种广义解释是
中间件(Middleware)是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的
在NodeJS中,中间件主要是指封装http请求细节处理的方法
例如在express、koa等web框架中,中间件的本质为一个回调函数,参数包含请求对象、响应对象和执行下一个中间件的函数
参考 面试官:说说对中间件概念的理解,如何封装 node 中间件?
8. EventSource
EventSource用于监听服务端的单向数据推送(区别于websocket的双工通信),很适合应用于视频播放、直播推送等实现。
基本使用
// 开启连接 自动调用open方法(跨越需要配置CORS) var source = new EventSource(url, { withCredentials: true }) // 接收消息(可与后端约定message类型) source.addEventListener('message', function (event) { // ... }, false) // 处理错误 source.addEventListener('error', function (event) { }, false) // 关闭连接 source.close(); 复制代码
9. serverless
看了一些ServerLess概念的文章,感觉也不是很理解。说下自己的模糊看法吧:Serverless是一种设计思想,将处理服务器相关的处理都高度封装配置即可用,开发者只需要通过函数式编程关注业务代码即可形成一个完整应用。而服务器,数据库等配置管理等都通过平台提供的服务来接入即可,无需开发者处理。
10. 低代码
低代码开发平台(英语:Low-Code Development Platform,简称LCDP),是一种方便产生应用程序的平台软件,软件会开发环境让用户以图形化接口以及配置编写程序,而不是用传统的程序设计作法。此平台可能是针对 某些种类的应用而设计开发的,例如数据库、业务过程、以及用户界面(例如网页应用程序)。这类平台可能可以产生完整且可运作的应用程序,也可能在一些特殊的情形下仍需要编写程序。低代码开发平台可以减少传统代码的数量,加速商业应用软件的完成时间。常见的好处是让比较多的人可以参与软件的开发,不只是那些有程序设计技巧的人。低代码开发平台也可以让设置、训练及布置的初期成本降低[1]。
11. DevOps
DevOps(Development和Operations的组合词)是一种重视“软件开发人员(Dev)”和“IT运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。通过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。