1. 框架类:
vue
- MVVM:MVVM是Model-View-ViewModel的简写,MVC改进版,vm是模式的核心,它是连接view和model的桥梁,通过数据绑定将 模型 转为 视图,通过 DOM 事件监听将 视图 转为 模型,即双向绑定。不同于 MVC 的单向通信,只能通过 C(Controller)来双向控制。
- 原理:
- 数据响应:Object.defineProperty利用setter、getter劫持数据,监听数据变化后,通知需要更新的地方做更新;
- 依赖收集:发布订阅,Observe监听器,Watcher订阅者,Dep消息订阅器;
- 指令解析器Compile:每个节点元素进行扫描和解析,用正则对带有 '{{变量}}' 这种形式的指令进行处理,初始化成一个订阅者Watcher;
- 过程:首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。
- 参考vue的双向绑定原理及实现。
- 关于vue源码:Vue源码系列-Vue中文社区
- v-key的作用(diff 算法):"就地复用"策略,高效的更新虚拟DOM;
- 父子组件生命周期:父
beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted - 监听子组件生命周期:
@hook:mounted="onListenMounted" - 组件通信
- prop
- $emit
- 事件总线,发布订阅
- vuex
- provide/inject
- Vue.use():调用插件内部的install方法,并将Vue实例作为参数传入;
- Vue添加全局功能:
- Vue.use
- Vue.prototype
- 全局混入mixin
- this.$root
- directive 自定义组件
- 钩子函数:bind、inserted、update、componentUpdated、unbind
- 函数参数:el、binding、vnode、oldVnode
- 组件按需加载:
// vue异步组件
component: require('@/pages/login')
// 结合 webpack 做一些加工处理
component: r => require.ensure([], () => r(require('@/components/home')), 'chunk')
// es6
component: () => import('@/pageslogin')
- 动态渲染图片:把图片路径用require()调用,或提前 import 图片实例;
- 数组变更方法:Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新,pop、push、unshift、shift、splice、reserve、sort;
- $set:在实例创建之后添加新的属性到实例上,它不会触发 响应式 更新,需要使用
Vue.set(object, key, value)来重新添加响应式; - Vue.extend():vue的一个构造器,继承自vue。可用于即用即显的弹框;
- Methods、computed、watch 区别:methods 在调用时才会计算。computed 当依赖的数据变化时才会计算, 当数据没有变化时, 它会读取缓存数据;异步无法监听数据的变化。watch 会在属性变化后重新计算,支持异步,对象内部值的变化可指定
deep: true来监听。 - 同时 watch 多个值:先用computed返回需监听的值,然后对这个计算属性进行监听
computed: {
watchInfo(){
return {
age: this.age,
name: this.userInfo.name
}
}
},
watch: {
watchInfo(val){
// doing somthing..
}
},
- 插槽简写方式
- 具名插槽
// 父组件 <child-component> <template v-slot:header><h1>这是头部内容</h1></template> <!-- 简写 --> <template #footer><p>这是底部内容</p></template> </child-component> // 子组件 <template> <slot name="header"></slot> </template>- 作用域插槽
// 父组件 <child-component> <template v-slot:content="slotProps"> <p>{{ slotProps.text }}</p> </template> <!-- 简写 --> <template #content="slotProps"><p>{{ slotProps.content.text }}</p></template> </child-component> // 子组件 <template> <slot :content="info"></slot> </template> - 怎样给插槽传递事件
// 子组件 child-component <div> <slot :onClick="onClick"></slot> </div> methods: { onClick(){ // do something } } // 父组件 <div> <child-component> <template #default="{onClick}"> <button @click="onClick">点击</button> </template> </child-component> </div> - data为什么是函数:为了达到数据隔离,由于组件可以复用,当组件被实例化后,属性也会被创建在原型链上,因此需要用data 返回一个可独立维护的数据拷贝;
- nextTick 实现方式,Promise.resolve(),渐弱:setTimeout();修改模型数据后,对更新后的Dom处理,需要放在 nextTick 中;
- axios 原理:axios可用于浏览器和 node.js 中,它会根据当前环境选择实现方式。如果是浏览器环境中,会基于XMLHttpRequests实现axios。如果是node.js环境,就会基于node内置 http模块 实现axios;
- 路由实现方式及原理:hash模式,根据
window.location.hash读取地址变化,监听 hashchange 事件来响应;history模式,通过H5新增的两个apiwindow.history.pushState、window.history.replaceState来实现路由切换。参考:vue-router 原理; - 路由 history 模式刷新404:由于失去了“#”,前端的路由在浏览器刷新页面时,会请求服务端同样的路由,就会出现404,需要在服务端增加一个覆盖所有情况的候选资源,例如index.html;
- 路由守卫
- 全局:router.beforeEach((to, from, next) => {})、router.afterEach((to, from) => {})
- 路由独享守卫:beforeEnter: (to, from, next) => {})
- 组件内的守卫:beforeRouteEnter(to, from, next)、beforeRouteUpdate(to, from, next)、beforeRouteLeave(to, from, next) 页面离开前询问
- Vuex:state、mutation、action
- Vuex、v-model 绑定:
- v-model直接绑定 state 的值
- 借用Computed的set、get访问器进行操作
computed: { getNickName: { get() { return this.$store.state.nickName }, set(val) { this.$store.commit('setName', val) } } } - Vue2、Vue3
- Object.defineProperty 改为 Proxy
- Teleport 允许在 DOM 中选择节点渲染 HTML
- 动态样式
- 优化:
- v-for 遍历必须加 key
- computed 和 watch 区分使用场景
- v-if 和 v-show 区分使用场景
- 长列表 虚拟滚动
- 对象层级不要过深
- 路由懒加载
- 错误信息收集:
Vue.config.errorHandler = error => { errors.push({time: Date.now(), content: error.stack}) }
vue3
-
生命周期
beforeCreate===>setup()created=======>setup()beforeMount===>onBeforeMountmounted=======>onMountedbeforeUpdate===>onBeforeUpdateupdated=======>onUpdatedbeforeUnmount==>onBeforeUnmountunmounted=====>onUnmounted
-
为什么要用 Proxy API 替代 defineProperty API:
Object.defineProperty只能遍历对象属性进行劫持,如果嵌套对象,需要深层监听,造成性能问题Object.defineProperty检测不到对象属性的添加和删除Object.defineProperty需要额外重写数组 APIProxy直接可以劫持整个对象,并返回一个新对象,我们可以只操作新的对象达到响应式目的Proxy可以直接监听数组的变化(push、shift、splice)
-
实现原理:
- 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
- 通过Reflect(反射): 对源对象的属性进行操作。
- MDN文档中描述的Proxy与Reflect:
- Proxy:Proxy - JavaScript | MDN
- flect:Reflect - JavaScript | MDN
- 伪代码:
new Proxy(data, { // 拦截读取属性值 get (target, prop) { return Reflect.get(target, prop) }, // 拦截设置属性值或添加新属性 set (target, prop, value) { return Reflect.set(target, prop, value) }, // 拦截删除属性 deleteProperty (target, prop) { return Reflect.deleteProperty(target, prop) } }) proxy.name = 'tom'
react
- 事件绑定 this 丢失:绑定事件时,传递的不是字符串,而是一个方法,onClick 即为中间变量,render 方法执行过程会丢失原来的 this 引用;
- hook
- 路由封装:react 路由封装及页面授权
小程序
- 压缩、组件传参(设计模式)、胶囊按钮的位置
- setData 同步还是异步(数据同步,界面渲染异步)
- 双线程模型:
- 渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本,经由微信客户端(Native)做中转
- 技术选型:为什么双线程
- 外部样式引用:externalClasses
- behavior:类似 mixin
- wxs 文件的功能
- 数据驱动:WXML先转成JS对象,然后再渲染出真正的Dom树。通过setData修改数据,产生的JS对象对应的节点就会发生变化,此时可以对比前后两个JS对象得到变化的部分,然后把这个差异应用到原来的Dom树上,从而达到更新UI的目的,这就是“数据驱动”的原理。
- 与vue双向邦定的区别
Webpack
-
Plugin
- webpack整体是一个插件架构,所有的功能都以插件的方式集成在构建流程中,通过发布订阅事件来触发各个插件执行。webpack核心使用Tapable来实现插件(plugins)的binding(绑定)和applying(应用)。
- Compiler 模块是 webpack 的支柱引擎,它通过 CLI 或 Node API 传递的所有选项,创建出一个 compilation 实例。它扩展(extend)自 Tapable 类,以便注册和调用插件。大多数面向用户的插件首先会在 Compiler 上注册。
-
配置项: entry、output、module( loader )、plugins、devServer、resolve、devtool、optimization。
-
多入口配置
- entry 选项配置多入口的目录,同时配置 HtmlWebpackPlugin 生成对应 html 模板。chunks 表示 html 文件的入口chunks;
- vendor 是指提取涉及 node_modules 中的公共模块,manifest 是对 vendor 模块做的缓存
-
多个loader对同一资源进行处理,他们之间如何通信
- webpack4之后,可以用 this.data 共享数据
2. CSS:
- 布局
- 左侧固定,右侧自适应宽度;
- 垂直水平居中;
- 圣杯布局
- 样式实现
- 三角形、正方形;
- 异常的处理
- 移动端兼容行高 line-height (Android、IOS)
- margin 溢出
- 移动端布局兼容
- rem
- 盒模型
- 普通盒模型 content 包含 padding,IE盒模型 content 不包含 padding
- 伪类、伪元素
- 伪类:向选择器增加特殊状态效果:active、focus 等
- 伪元素:用于创建文档树以外的元素并为其添加样式
- BFC:块级格式化上下文
- 触发条件:
- body 根元素
- 浮动元素:float 除 none 以外的值
- 绝对定位元素:position (absolute、fixed)
- display 为 inline-block、table-cells、flex
- overflow 除了 visible 以外的值 (hidden、auto、scroll)
- 解决问题:
- float带来的高度塌陷
- margin重叠
- 触发条件:
3. JavaScript:
-
原始类型 => 装箱拆箱
-
对象构造
-
原型链、闭包 => 垃圾回收(标记清除)
-
关于正则:
-
面向对象的基本特征:
- 封装、继承、多态
- 继承(原型继承、构造继承、组合继承等)
-
数据类型的判断(
typeof,instanceof,constructor,Object.prototype.toString.call()) -
js线程、事件循环 Event Loop
- 同步任务
- 异步任务
- 宏任务:setTimeout, setInterval, I/O 操作, UI 渲染
- 微任务:Promise.then/catch/finally, process.nextTick(Node.js), MutationObserver
栈中代码 => 微任务 => 宏任务 => 微任务 => 宏任务 => ...- try/catch 操作只能捕获当次事件循环内的异常,对异步执行时抛出的异常将无能为力
-
常见排序:冒泡(比较相邻两数,换位),选择排序(每次选最小的数交换到前面),快排(选择一个基准数分前后区,递归该操作),桶排序(数据分配到有限数量的桶里,把非空桶拼接起来)
-
this 绑定(new操作符、bind等、上下文调用绑定、默认绑定window)
-
cookie、sessionStorage、localStorage:
- cookie 可以在一级域名内跨域读写,storage不行,参考 实现跨域Cookie共享的三要素
- cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,参考 Cookie中的httponly的属性和作用
-
app交互
-
- new 关键字实现(return若为自定义的object、array,会代替构造函数中创建的对象)
- call、apply、bind 模拟实现
- 防抖节流原理
-
模块化:主要是用来抽离公共代码,隔离作用域
- IIFE:自执行函数,在一个单独的函数作用域中执行代码
- AMD:使用requireJS 来编写模块化
- CommonJS:nodejs 中自带的模块化
require('fs'); - webpack(require.ensure):webpack 2.x 版本中的代码分割
- ES Modules:ES6 引入的模块化,支持
import、export - require是“运行时加载”,只有在代码真正运行的时候才会去加载对应需要的东西,所以不能做到编译时就把想加载的模块加载进来,即不能做到编译时静态化
- import是编译时调用,所以必须放在文件开头
-
JS编译解析的流程
- 语法分析,生成抽象语法树(AST)和执行上下文:
- 生成 AST 需要经过两个阶段:
- 第一阶段是分词(tokenize),又称为词法分析
- 第二阶段是解析(parse),又称为语法分析
- 预编译,解释器 lgnition 生成字节码
- 解释执行,第一次执行,解释器 lgnition 通常会一行行执行代码,解释过程中,若发现一段代码被重复执行多次,即为热点代码,则 编译器 TurboFan 会把该段热点的字节码编译为机器码,再次执行这段被优化的代码时,只需要执行编译后的机器码就可以了,这样就大大提升了代码的执行效率。这就是 即时编译(JIT)
- ES6 转 ES5 原理:
- Parser 解析:将 ES6 语法解析为 AST 抽象语法树,主要是通过 babylon 插件来完成。
- Transformer 转换:将零散的 AST 语法通过配置好的 plugins 和 presets 转换成新的 AST 语法,由 babel-transform 插件完成。plugins 和 presets 通常在 .babelrc 文件中配置。
- Generator 生成:将新的 AST 语法树对象再生成浏览器都可以识别的 ES5 语法,这一步主要是由 babel-generator 插件完成。
- 语法分析,生成抽象语法树(AST)和执行上下文:
-
设计模式:
- 发布订阅 (Publish Subscribe Pattern) -- 多个订阅者对象同时监听某一个主题对象,这个主题对象状态变化时,会通知所有订阅者对象,使它们能够自动更新自己的状态
- 代理模式 (Proxy Pattern) -- 当对一个对象的访问不能直接引用时,可通过一个称之为 “代理” 的中间层来实现间接引用。通过引入代理对象来间接访问一个对象
-
- 箭头函数与普通函数的区别
- 没有this,会捕获其所在的上下文的this值
- 使用call、bind等绑定无效
- 不能作为构造函数,不能使用 new
- 不绑定arguments,用rest参数...解决
- 没有原型属性
- 不能当做Generator函数,不能使用yield关键字
- Set、Map 操作方法
- Map、WeekMap 区别:
- Map 对key强引用,不会被垃圾回收掉
- WeekMapWeekMap 对key弱引用,能被垃圾回收及时清除掉,导致weakmap中的这对key-value也会消失
var map = new Map(); { let a = {} map.set(a, 'something'); } console.log(map);var wmap = new WeakMap(); { let b = {} wmap.set(b, 'something week'); } console.log(wmap); - 运算符(扩展运算符... 可选链?. 空值合并?? )
- Proxy
- 作为构造函数,
Proxy接受两个参数,第一个参数是所要代理的目标对象,第二个参数是一个配置对象,可以设置目标对象的set、get行为
let proxy = new Proxy({}, { get: function(target, propKey) { return 35; } }); proxy.time // 35 proxy.name // 35 proxy.title // 35 - 作为构造函数,
- Class 和 构造函数的区别:
- 类和模块的内部,默认就是严格模式
- Class 不存在变量提升
- Class 的方法默认不可枚举
- Class 必须使用 new 调用
- ES5 中的继承先创造子类的实例对象this,然后再将父类的方法添加到this上面;Class 先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。
- 箭头函数与普通函数的区别
-
继承的实现方式
- 原型链继承
- 构造函数继承
- 组合继承:结合构造函数和原型链
- 原型式继承:临时创建一个构造函数,以现有对象作为原型,实例化对象并返回
- 寄生式继承:在原型式继承的基础上,在内部增强对象并返回
- class extend
-
统计帧率FPS
- 1s内
requestAnimationFrame调用的次数
- 1s内
4. TypeScript:
- Declare关键字:第三方库没有.d.ts声明文件的时候,我们可以通过declare来写申明文件,可以声明该模块,甚至声明一个值为any的同名的变量,然后我们就可以直接使用。
- 泛型:泛指某一类型,更像是一个类型变量,由尖括号包裹<T>
- interface、type:interface描述数据结构,用type描述类型
5. Node.js:
- handleCount
- koa、中间件
6. HTTP:
- 超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求 - 响应协议,归属于应用层协议,主要解决如何包装数据。
- HTTP请求的结构
- 请求行:请求方法、URI、HTTP协议版本
GET /index.html HTTP/1.1 - 请求头:描述请求正文 Host: www.enjoytoday.cn Connection: keep-alive User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36
- 空行
- 请求数据:存放POST请求类型的请求正文
username=ZhangSan&sex=male
- 请求行:请求方法、URI、HTTP协议版本
- 三次握手、四次挥手
- TCP、UDP
- TCP面向连接,高可靠,适用于文件传输等:网页浏览等 http 请求、文件传输;
- UDP无连接,低开销,速度快,适用于实时通信等:音频/视频会议、实时播放、广播。
- 安全:xss、csrf
- 跨域: JSONP、CORS(预检请求)、代理
- 网图地址没有后缀也能正常显示:浏览器根据数据包的 Content-Type 来决定如何解析数据
- GET 和 POST:
- HTTP 协议 未规定 GET 和POST的长度限制
- GET的最大长度显示是因为 浏览器和 web服务器限制了 URI的长度
- cookie, session和token:参考 Cookie、Session和Token的区别
- cookie存储在浏览器本地,会被js篡改,不安全,单个4K,最多20条;
- session存储在服务端,根据客户端cookie等信息进行甄别,占用服务器的性能;
- token是来自服务端的令牌,保存在客户端,发送请求时在服务端比对;
7. 浏览器:
浏览器的渲染原理
- 根据 html 文档,构建一棵 DOM 树,由元素及其附加属性组成。
- 对 CSS 解析,生成 CSSOM 规则树,样式规则。
- 根据 DOM 树和 CSSOM 规则树构建渲染树 Render Tree。由一些包含颜色和大小等属性的矩形组成。
- 根据 Render Tree 来布局,计算各节点的位置、大小,此过程也就是“重排”。
- 绘制。遍历render树,调用 Paint 方法使用 UI 基础组件绘制出来。这个过程并非是等 html 完全解析完再执行,而是解析完一部分就执行显示一部分。如下图,
JavaScript 的加载,解析,执行 都会阻塞文档的解析;
CSS 是并行下载,不会阻塞后面 JS 的下载,但会阻塞后面 JS 的执行;
CSS 不会阻塞 DOM 的解析,但会阻塞 DOM 渲染。
因此,script 标签被建议放在body 标签底部,CSS 被建议放在头部。
重绘重排
- 重排,重新排列,意味着重新计算文档中元素的位置和几何信息(元素的位置、大小),会影响部分或整个页面的布局。元素的重排将导致DOM中所有子元素和其他兄弟元素重新排列。
- 重绘是更改元素的可见性,但是不影响元素的布局。例如可见性、背景色、轮廓等。
- 如何减少重排和重绘:
- 尽量避免
style的使用,对于需要操作DOM元素节点,重新命名className,更改className名称。 - 如果增加元素或者
clone元素,可以先把元素通过documentFragment放入内存中,等操作完毕后,再appendChild到DOM元素中。 - 不要经常获取同一个元素,可以第一次获取元素后,用变量保存下来,减少遍历时间。
- 尽量少使用
dispaly:none,可以使用visibility:hidden代替,dispaly:none会造成重排,visibility:hidden会造成重绘。 - 不要使用
Table布局,因为一个小小的操作,可能就会造成整个表格的重排或重绘。 - 使用
resize事件时,做防抖和节流处理。 - 对动画元素使用
absolute / fixed属性。 - 批量修改元素时,可以先让元素脱离文档流,等修改完毕后,再放入文档流。
- 尽量避免
缓存机制
- 浏览器的缓存过程:
-
域名解析,DNS缓存:域名查找IP地址的过程就是dns解析,这个过程会对网络请求带来一定的损耗,浏览器第一次解析后会将其缓存起来,即 DNS缓存。
- 下次识别到相同地址时,会先查找本地缓存,优先使用本地缓存;
- DNS缓存不存在,读取系统的hosts文件查找对应映射关系,若存在,则域名解析到此完成;
- 本地hosts文件不存在映射关系,查找本地DNS服务器,若存在,域名到此解析完成;
- 本地DNS服务器未找到,向服务器发送请求解析IP。
-
内存缓存(memory缓存):缓存于本地内存中,页面关闭,内存释放;
- HTTP缓存(强缓存和协商缓存):硬盘缓存,最主要的缓存方式,可控且优化空间大的一个缓存部分,也是面试中常问的一个缓存环节;
- 服务端缓存(CDN缓存):CDN节点解决了跨运营商和跨地域访问的问题,访问延时大大降低。浏览器本地缓存的资源过期之后,会向服务器发起资源申请,优先转向 CDN 边缘节点请求资源,CDN 中的缓存可用,直接返回,不可用或者过期,CDN 边缘节点会向源服务器发出回源请求,从而来获取最新资源,并做缓存。
-
- HTTP缓存的命中方式:
- 根据 http 中的 header 判断是否命中强缓存,若命中,则直接从本地缓存中获取资源,不发送服务器请求;
- 强缓存未命中时,浏览器发送服务端请求,通过请求头验证是否命中协商缓存,若命中,则返回请求,但不返回资源,而是通知浏览器从本地加载资源;
- 都未命中,直接从服务器加载资源。
- 强缓存:
- 利用 Expires(HTTP/1.0)、Cache-Control(HTTP/1.1)这些请求头参数,控制资源过期时间。到了HTTP/1.1,Expires已经被Cache-Control替代,所以,这两个字段同时存在时,Cache-Control优先级高于Expires。
- Cache-Control 主要取值:
- max-age:指定一个时间长度,在这个时间段内缓存是有效的,单位是s。
- s-maxage:同 max-age,覆盖 max-age、Expires,但仅适用于共享缓存,在私有缓存中被忽略。
- public:所有内容都将被缓存(客户端和代理服务器都可缓存)
- private:所有内容只有客户端可以缓存,Cache-Control的默认取值
- no-cache:在使用已缓存的数据前,发送带验证器的请求到服务器,不是字面意思上的不缓存。
- no-store:禁止缓存,所有内容都不会被缓存,既不使用强制缓存,也不使用协商缓存,每次请求都要向服务器重新获取数据。
- Cache-Control 主要取值:
参考 浏览器缓存命中策略。
- 使用时,在Web服务器返回的响应中添加
Expires、Cache-ControlHeader。 - 控制台显示为,状态码 Status: 200, size: (from cache)。
- 利用 Expires(HTTP/1.0)、Cache-Control(HTTP/1.1)这些请求头参数,控制资源过期时间。到了HTTP/1.1,Expires已经被Cache-Control替代,所以,这两个字段同时存在时,Cache-Control优先级高于Expires。
- 协商缓存:
- 某个资源的请求没有命中强缓存,会向服务器发送请求验证协商缓存是否命中,若命中,浏览器会收到304的响应,就会从缓存中加载资源。
- 大部分web服务器都默认开启协商缓存,同时启用 Last-Modified,If-Modified-Since (资源在服务器上最后修改时间)和 ETag、If-None-Match (资源的唯一标识)控制。
- 控制台显示为,状态码 Status: 304 Not Modified 。
8. 性能优化:
9. 功能设计:
扫码登录
- PC端进入页面,请求服务端获取二维码ID。
- 服务端生成相应的二维码ID,设置二维码的过期时间、状态等。
- PC端获取二维码ID,展示二维码。
- 手机端扫描二维码,获取二维码ID。
- 手机端将手机端token和二维码ID发送给服务端,确认登录。
- 服务端校验手机端token,根据手机端token和二维码ID生成PC端token
- PC端通过轮询方式请求服务端,通过二维码ID获取二维码状态,如果已成功,返回PC token,登录成功。
登录方式
Cookie+Session- 服务端创建
SessionId并保存,在HTTP请求响应头中通过Set-Cookie头信息,将SessionId写入Cookie中。后续页面访问会自动带上Cookie,服务端进行比对; - 当对接客户端体量大时,也需存放大量
SessionId,增加服务器压力;Cookie在浏览器中无法避免CSRF攻击。
- 服务端创建
- Token 登录
- 首次登录后,服务器会生成一个 Token 并返回给客户端,由客户端自由保存,客户端后续访问时,只需带上这个 Token 即可完成身份认证;
- SSO单点登录
- 在同一平台下的多个应用系统中,用户只需登录一次,即可访问所有相互信任的应用系统。
- 未登录情况下访问页面A,会重定向到认证中心,在认证中心登录完成后,再带上授权码
ticket重定向到页面A,同时将认证中心的登录态写入Cookie。并在A页面服务器中用ticket向认证中心确认,通过后将登录信息写入Cookie(同时存在认证中心、A页面的Cookie)。
- OAuth 三方登录
- 以微信为例,运营者在微信平台注册账号后,得到 appid 等。用户进入业务页面A后,选择微信登录,会跳转到微信的 OAuth 授权登录页,并附上A页面地址,当用户授权登录后,会从当前微信授权页重定向回A页面,这时带上了临时票据
code; - A页面拿到
code后,向调用微信API申请token,验证成功后微信会下发一个token,A页面服务器可据此拿到微信用户相关信息; - A页面登录成功后,会将登录态写入
Cookie,以作后续凭证。
- 以微信为例,运营者在微信平台注册账号后,得到 appid 等。用户进入业务页面A后,选择微信登录,会跳转到微信的 OAuth 授权登录页,并附上A页面地址,当用户授权登录后,会从当前微信授权页重定向回A页面,这时带上了临时票据
10. 规范:
- 命名: 小驼峰、下划线、短横杠; 图片命名,推荐用 page-type-name_index 方式命名,如 home-icon-check_1.jpg、friend-banner-top_3.jpg
- css: 尽量避免内联样式; 0 后面不加单位,小数点前不加 0; 不用标签名做选择器; 若一个样式表内多处使用相同样式,应提取公用,如: display: flex; justify-content: center; align-items: center;
- js 采用封装,减少重复代码; wx:key 注入id 等唯一标识; 不涉及到 dom 上的数据交互时,避免使用 this.setData,以 this.data 代替; 减少 this.setData 的单独调用,尽量合并,一次调用; 小程序中不需要用到的 钩子函数,应删掉,避免触发不必要的监听执行; 生命周期函数内,减少实际操作代码,可单独抽出写作 function; console.log() 在完成调试后,应及时删除,以免控制台输出太多;
- git 提交时的 标题 应尽量涵盖此次所有的变动,能使项目其他人检索到; 一次提交过多时,可分次提交;
- 其他 缩进: 用两个空格来代替制表符(tab)-- 保证在所有环境下获得一致展现的方法; 无用的代码及时删除; 图片使用前需压缩,不超200k; 推荐使用 mark 插件标记代码段;
相关面经:\ 时隔一年半,我,一个卑微的前端菜鸡,又来写面经了。\ 阿里社招两年前端面经。
/**
*
* ┏┓ ┏┓
* ┏┛┻━━━━━┛┻┓
* ┃ ┃
* ┃ ━ ┃
* ┃ ┳┛ ┗┳ ┃
* ┃ ┃
* ┃ ┻ ┃
* ┃ ┃
* ┗━┓ ┏━┛ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*
*/