前端面试宝典(持续更新)

一、Web端

https://www.nowcoder.com/discuss/588372

1.float如何清除浮动

(1)父元素上加上overflow:auto/hidden。

(2)父元素加一个伪元素 .father:after{content: '', clear: both}

2.闭包的原理及作用   

(1)闭包是通过JS的链式作用域,函数内的局部变量只有内部函数能访问到,所以要对外暴露一个函数内部的局部变量时,就会用到闭包。

(2)一般用于页面内的计时器和计数器

a)计时器的使用场景是函数防抖,当频繁触发计时器时,可以把计时器放到函数内,计时器的创建和销毁都通过闭包的形式对外暴露,这样可以在频繁调用计时器时,做到函数防抖。同时保持全局清洁,不会被其他函数的调用破坏计时器的逻辑。

b)计数器是把作为累加的变量保存在一个函数内,同时通过闭包完成累加和对外暴露,以此保证全局清洁,以及计时器的安全性。

3.跨域访问如何解决

由于JavaScript的同源策略,A域名下的Javascript不能操作B,C域名下的对象。

协议不同,域名不同,端口号不同。

(1)跨域资源共享 CORS

后端在response header中添加【Access-Control-Allow-Origin:origin的地址/*】允许跨域。

(2)使用jsonp,生成script标签,但只能是GET请求。axios?

4.万能居中

(1)display: flex; justify-content: center; align-items: center;

(2)margin:0;

(3)top: 50%;  translateY: -50%;

(4)line-height: 100%;

(5)text-align: center;

5.vue/angular中的指令是什么

a)vue

(1)除了默认设置的核心指令( v-model 和 v-show ), Vue 也允许注册自定义指令。

(2)vue指令可以定义为全局的或者局部的。

全局:

Vue.directive('self_defined_name',{  bind:function(el,binding){  //do someting  },  inserted: function(el,binding){  //do something  },}

局部:

new Vue({  el:'#app',  directives:{    self_defined_name1:{        bind:function(el,binding){          //do something        }        inserted:function(el,binding){                  //do something        },    }    self_defined_name2:{        bind:function(el,binding){          //do something        }        inserted:function(el,binding){                  //do something        },    }  }})

(3)钩子函数:bind inserted update componentUpdated unbind

(4)钩子函数参数:el binding对象(name value oldValue expression arg modifiers) vnode oldVnode(仅在update componentUpdated中使用)

b)angular

(1)angular的指令分为组件,结构型指令和属性型指令

(2)组件继承于directive,所以组件也属于指令

(3)属性型指令可以使用ng g d 文件名,来在前端工程中生成一个指令控制器文件。文件中需要使用修饰器@Directive+选择器,来指定指令的name。在@Input中,获取传递给指令的参数。在构造函数construction会返回el,通过el.nativeElement来获取指令所在的元素。

(4)结构型指令,在构造函数中会返回TemplateRef和ViewContainer,TemplateRef表示内嵌的template模板元素,ViewContainer是视图容器,可以通过ViewContainer的createEmbeddedView或者clear方法来控制内嵌的template模板元素是否显示。

(5)指令与组件共有的钩子

1) ngOnChanges - 当数据绑定输入属性的值发生变化时调用

2) ngOnInit - 在第一次 ngOnChanges 后调用

3) ngDoCheck - 自定义的方法,用于检测和处理值的改变

4) ngAfterContentInit - 在组件内容初始化之后调用

5) ngAfterContentChecked - 组件每次检查内容时调用

6) ngAfterViewInit - 组件相应的视图初始化之后调用

7) ngAfterViewChecked - 组件每次检查视图时调用

8) ngOnDestroy - 指令销毁前调用

6.webpack和gulp的相同点和不同点

(1)webpack和gulp都是前端工程化工具

(2)webpack是打包工具,gulp是构建工具

7.flex - 弹性布局

(1)flex-direction:设置主轴方向,默认水平

(2)flex-warp:是否换行

(3)justify-content:主轴位置 flex-start center flex-end space-between space-around

(4)align-items:交叉轴位置 flex-start center flex-end baseline stretch

(5)align-content: 多根轴线的对齐方式 flex-start center flex-end space-around space-between stretch

b) 设置在项目上的6个属性

(1)order

(2)flex-grow

(3)flex-shrink

(4)flex-basis

(5)flex

(6)align-self

8.css相关,动画

9.ES6有哪些新功能

https://segmentfault.com/a/1190000016068235

(1)新增let和const。let不支持变量提升,const在声明时必须被赋值

(2)模板字符串

`This demonstrates the output of HTML content to the page,

including student's ${name}, ${seatNumber}, ${sex} and so on.`

(3)箭头函数,省略声明函数时的function,参数括号,return

(4)设置函数默认值,function printText(text='default')

(5)对象解构 const{name,age,sex}=student;

(6)for...of 用于遍历一个迭代器;for...in 用来遍历对象中的属性

10.Promise的用法

11.async和await的用法

12.map,filter,each等的用法,是否返回新数组

参考链接:https://www.cnblogs.com/jiangweichen88/p/10509054.html

(1)concat (返回新数组)

(2)join(返回字符串,逗号分隔)

(3)push(返回数组新长度,改变原数组)

(4)pop(返回去掉的最后一个元素,改变原数组)

(5)shift(返回去掉的第一个元素,改变原数组)

(6)unshift(返回新增的第一个元素,改变原数组)

(7)slice(返回新数组,指定下标start至end(不包括该元素))

(8)splice(返回被删除的数组,改变原数组)

(9)substr, substring(两个参数,substr第二个参数是留多少个字符;substring含头不含尾)

(10)sort(),按照 Unicode code 位置排序,默认升序,返回新数组

(11)reverse()方法用于颠倒数组中元素的顺序。返回的是颠倒后的数组,会改变原数组

(12)indexOf 和 lastIndexOf

(13)every(返回true/false)

(14)some(返回true/false)

(15)filter(返回新数组)

(16)map(返回新数组)

(17)forEach(方法)

ES6:

(1)find

(2)findIndex

(3)fill

(4)copyWithin

(5)from

(6)of

(7)entries

(8)values

(9)keys

(10)includes

13.vue双向数据绑定原理

vue双向数据绑定是用到了数据劫持和发布-订阅者模式

(1)Object.defineProperty(object, key, {setter(), getter()})

(2)

14.虚拟DOM?

15.lodash

16.rxjs

17.响应式编程

18.性能优化

(1)尽量把<html>写在上面,<script>写在下面

(2)尽量减少网络请求次数,合并API。

http缓存,合并压缩css,js,img等资源。

首页懒加载,首先只部分加载,问下滑动时再继续加载。

(3)将JS文件合并,并且将JS中的无用的语句删掉

(4)减少闭包的使用

(5)个人信息,菜单等可以缓存到localstorage中

(6)减少构造函数(new关键字)的使用

(7)将全局变量存进局部变量使用

(8)使用js创建的dom元素必须append到template上,否则不会回收

(9)switch > if;  ===>==; for > for of(ES6) > for in(ES5)

19.HTML5为什么只需要写<!DOCTYPE HTML>?

HTML 4.01 中的 doctype 需要对 DTD 进行引用,因为 HTML 4.01 基于 SGML。而 HTML 5 不基于 SGML,因此不需要对 DTD 进行引用,但是需要 doctype 来规范浏览器的行为。其中,SGML是标准通用标记语言,简单的说,就是比HTML,XML更老的标准,这两者都是由SGML发展而来的。BUT,HTML5不是的。

20.浏览器内核

一个完整的浏览器包括浏览器的内核和浏览器的外壳,浏览器的核心部分 —— 内核 主要分为两个部分:渲染引擎(Render Engine)和JS引擎,由于JS引擎越来越独立,所以现在我们所指的浏览器内核只指渲染引擎。

渲染引擎: 负责取得网页的内容(HTML、XML、图象等等)、整理信息(例如加入CSS等),以及计算网页的显示方式然后会输出至显示器或打印机。

JS引擎: 执行JavaScript代码的程序或解释器,JS引擎可以实现为标准解释器或即时编译器,它以某种形式将JavaScript编译为字节码。

常见的浏览器内核

Webkit内核:Safari,Chrome

Trident内核:IE,Firefox、360

21.BFC - 块级格式化上下文

https://zhuanlan.zhihu.com/p/25321647

具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。

通俗一点来讲,可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。

只要元素满足下面任一条件即可触发 BFC 特性:

body 根元素

浮动元素:float 除 none 以外的值

绝对定位元素:position (absolute、fixed)

display 为 inline-block、table-cells、flex

overflow 除了 visible 以外的值 (hidden、auto、scroll)

1. 同一个 BFC 下外边距会发生折叠

2. BFC 可以包含浮动的元素(清除浮动)

3. BFC 可以阻止元素被浮动元素覆盖

22.数组去重

(1)ES6:new Set[] + Array.from

(2)ES5:for + splice

(3)forEach + indexOf(v, i+1)> -1? - ES5   includes - ES6

(4)对象属性

(5)filter()+ indexOf()==index

23.原型和原型链

https://www.nowcoder.com/discuss/588372

24.手写Promise.all

https://blog.csdn.net/The_upside_of_down/article/details/103285400

25.vue和angular的生命周期

vue

beforeCreate, created, beforeMount, mounted, beforeUpdate, upadated, beforeDestroy, destroyed

angular

(1)constructor

(2)ngOnChanges

(3)ngOnInit

(4)ngDoCheck

(5)ngAfterContentInit

(6)ngAfterContentChecked

(7)ngAfterViewInit

(8)ngAfterViewChecked

(9)ngOnDestroy

26.sass预处理

https://blog.csdn.net/hope93/article/details/85232727

(1)变量$

(2)后代选择器

(3)父选择器

(4)子组合选择器,子相邻选择器,子全体选择器

(5)属性嵌套

(6)默认变量值

(7)文件导入

(8)混合器 @mixin @include

(9)选择器继承

27.Lint

28.单元测试

29.微前端

## Integration dev/test with the main `otr-website` project before publishing `@otr/website-common` package

1. The simplest strategy: Edit `otr-website/node_modules/@otr/website-common/fesm5/otr-website-common.js` directly, after verified back-port the changes to website-common source code.

2. The `npm link` strategy:

    - Build website-common with watch flag: `./node_modules/.bin/ng build --watch --project=website-common`

    - Then symlink website-common: `cd dist/website-common/ && npm link`

    - In root directory of otr-website, run `npm link @otr/website-common`, then restart ng serve(eg `npm run start-plus`).

    - After dev/test done, cleanup the symlink: `npm unlink --no-save @otr/website-common && npm install`

    - Reference: https://willtaylor.blog/complete-guide-to-angular-libraries/

30.yarn和npm的区别

https://www.jianshu.com/p/254794d5e741

(1)yarn更快,a)npm下载依赖时,是按照队列逐个下载依赖,而yarn是同步下载依赖。b)yarn可以离线下载之前已经缓存过的依赖,不需要每次都重复下载。

(2)yarn安装的版本统一,不同于npm的package.json文件里的^,~,实际安装依赖的时候可能会出现版本不同的情况,yarn在安装时会生成yarn.lock,指定安装依赖的版本号。

(3)下载依赖时,控制台只输出必要信息,相关错误信息不会像npm那样淹没在log中。

31.session,cookie,token

https://blog.csdn.net/qq_36894974/article/details/105322171?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522161044390216780265496621%252522%25252C%252522scm%252522%25253A%25252220140713.130102334.pc%25255Fall.%252522%25257D&request_id=161044390216780265496621&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~hot_rank-1-105322171.first_rank_v2_pc_rank_v29&utm_term=cookie

32.SSO单点登录集成

(1)首先会跳转到第三方登录页面,登录成功后会跳转回管理系统,并回传code。

(2)前台将appId和appSecret传入后台,获取到登录token。

(3)前台将登录code,登录token发给后台,获取登录态token。

(4)使用登录态token,获取当前用户信息。

33.如何准确判断一个变量的数据类型

(1)在JS中,有5中基本数据类型(null, undefind, boolean, string, number)一种复杂数据类型(Object-Array Function,Date)

(2)使用typeof判断,可以判断出number, string, boolean, function, undefined

NaN和Infinity是number,

arr, json, reg, null, date, error是object

(3)instanceof能判断出一个对象是否是另一个类的实例。

(4)使用Object.prototype.toString.call

先用for in遍历一个object,然后对里面的每个属性的value用上面的方法判断类型,放到数组里,然后用join(',')做拼接。

34.mutation为什么必须是同步的

我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。

35.数组扁平化 - 遍历数组arr,若arr[i]为数组则递归遍历,直至arr[i]不为数组然后与之前的结果concat。 

(1)ES6的Generator 函数

(2)reduce函数,参数:total, currentItem, currentIndex, array

reduce+concat

(3)flat(Infinity)直接数据扁平。

(4)join(',') split(',')  toString() split(',')

(5)forEach()+Array.isArray(item)+push

(6)es6的扩展运算符能将二维数组变为一维, arr = [].concat(...arr);

36.apply和call的区别

call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象

obj.myFun.call(db,'成都','上海');     // 德玛 年龄 99 来自 成都去往上海obj.myFun.apply(db,['成都','上海']); // 德玛 年龄 99 来自 成都去往上海 obj.myFun.bind(db,'成都','上海')(); // 德玛 年龄 99 来自 成都去往上海obj.myFun.bind(db,['成都','上海'])();   // 德玛 年龄 99 来自 成都, 上海去往 undefined

37.async和await

上面这段代码async中使await 摇色子()先执行,等到三秒后执行完再把得到的结果赋值给左边的n,也就是说test函数需要三秒钟才执行完成,所以test函数是异步的,因此前面必须写async

38.观察者模式和发布订阅者模式的区别

代码:https://www.jianshu.com/p/594f018b68e7

(1)观察者模式(观察者和被观察者),发布订阅者模式(发布者,订阅者,多了一个调度中心)

(2)观察者和被观察者,是松耦合的关系;发布者和订阅者,则完全不存在耦合。

39.观察者模式如何实现

js观察者模式 - 大正与疯 - 博客园 (cnblogs.com)

(1)document.body.addEventListener("click", function() {

    alert("Hello World")

},false )

document.body.click() //模拟用户点击

(2)vue底层原理,重写setter方法

40.发布订阅者模式如何实现

发布者订阅模式

例如如我们关注了某一个公众号,然后他对应的有新的消息就会给你推送,

//发布者与订阅模式

var shoeObj = {}; // 定义发布者

shoeObj.list = []; // 缓存列表 存放订阅者回调函数

// 增加订阅者

shoeObj.listen = function(fn) {

shoeObj.list.push(fn); // 订阅消息添加到缓存列表

}

// 发布消息

shoeObj.trigger = function() {

for (var i = 0, fn; fn = this.list[i++];) {

fn.apply(this, arguments);//第一个参数只是改变fn的this,

}

}

// 小红订阅如下消息

shoeObj.listen(function(color, size) {

console.log("颜色是:" + color);

console.log("尺码是:" + size);

});

// 小花订阅如下消息

shoeObj.listen(function(color, size) {

console.log("再次打印颜色是:" + color);

console.log("再次打印尺码是:" + size);

});

shoeObj.trigger("红色", 40);

shoeObj.trigger("黑色", 42);

41.vue3.0相较于vue2.0的有点

(1)3.0比2.0 快2倍,virtual DOM 完全重写,放弃 Object.defineProperty ,使用更快的原生 Proxy;默认进行懒观察(lazy observation)。

https://juejin.cn/post/6844904088119853063

在 2.x 版本里,不过数据多大,都会在一开始就为其创建观察者。当数据很大时,这可能会在页面载入时造成明显的性能压力。3.x 版本,只会对「被用于渲染初始可见部分的数据」创建观察者,而且 3.x 的观察者更高效。

(2)3.0兼容IE12以上

(3)3.0去掉了filter, 么有beforeCreate created,用setup取代

42.vue定义一个过滤器

43.v-for中为什么要使用key

https://www.jianshu.com/p/4bd5e745ce95

可以复用。

vue使用diff算法,当有一组多选选项时,如果在第一个插入一个新的选项,diff算法会对操作前后的dom进行对比,他不会把已选中的状态各往后移一位,而是位数保持不变,这样会造成错误。如果增加key标识组件的唯一性,则可以更加高效的更新虚拟DOM。

44.vue通信

vue组件间通信六种方式(完整版) - SegmentFault 思否

(1)props / $emit 适用父子组件通信:

这种方法是 Vue 组件的基础,相信大部分同学耳闻能详,所以此处就不举例展开介绍。

2.ref 与 $parent / $children :适用父子组件通信

ref :如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例

$parent / $children :访问父 / 子实例

3.EventBus($emit / $on) :适用于父子、隔代、兄弟组件通信

这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。

1、初始化——全局定义

      全局定义,可以将eventBus绑定到vue实例的原型上,也可以直接绑定到window对象上.

//main.js

//方式一

Vue.prototype.$EventBus =new Vue();

//方式二

window.eventBus =new Vue();

2、触发事件

//使用方式一定义时

this.$EventBus.$emit('eventName', param1,param2,...)

//使用方式二定义时

EventBus.$emit('eventName', param1,param2,...)

3、监听事件

//使用方式一定义时

this.$EventBus.$on('eventName',(param1,param2,...)=>{

//需要执行的代码

})

//使用方式二定义时

EventBus.$on('eventName',(param1,param2,...)=>{

//需要执行的代码

})

4、移除监听事件

      为了避免在监听时,事件被反复触发,通常需要在页面销毁时移除事件监听。或者在开发过程中,由于热更新,事件可能会被多次绑定监听,这时也需要移除事件监听。

//使用方式一定义时

this.$EventBus.$off('eventName');

//使用方式二定义时

EventBus.$off('eventName');

4.$attrs/$listeners :适用于隔代组件通信

childCom1的$attrs:{{$attrs}}

$attrs :包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用。

$listeners :包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件

如上图所示$attrs表示没有继承数据的对象,格式为{属性名:属性值}。Vue2.4提供了$attrs , $listeners 来传递数据与事件,跨级组件之间的通讯变得更简单。

简单来说:$attrs与$listeners 是两个对象,$attrs 里存放的是父组件中绑定的非 Props 属性,$listeners里存放的是父组件中绑定的非原生事件。

5.provide / inject :适用于隔代组件通信

祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。

6.Vuex :适用于父子、隔代、兄弟组件通信。

45.Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store (仓库)。 store 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。

Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

改变 store 中的状态的唯一途径就是显式地提交 ( commit ) mutation 。这样使得我们可以方便地跟踪每一个状态的变化。

主要包括以下几个模块:

State :定义了应用状态的数据结构,可以在这里设置默认的初始状态。

Getter :允许组件从 Store 中获取数据, mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。

store.getters.changePassword

Mutation :是唯一更改 store 中状态的方法,且必须是同步函数。

this.$store.commit('edit',15)

Action :用于提交 mutation ,而不是直接变更状态,可以包含任意异步操作。

this.$store.dispatch('aEdit',{age:15})

Module :允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。

46.虚拟 DOM 的实现原理

将DOM转化为Virtual DOM,一个JSON对象,将耗费性能的DOM操作转化为JSON对象之间的比较,减少DOM数重绘和重排的次数,可以提高性能。

他会比较两个JSON中,同级之间Virtual DOM的区别,提取出需要更新的真实DOM操作。

虚拟dom相当于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的dom操作,从而提高性能。

【具体实现步骤如下】

用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中

当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异

把2所记录的差异应用到步骤1所构建的真正的DOM树上,视图就更新了。

【好处】

通过classname或cssText一次性修改样式, 而非一个一个改

离线模式: 克隆要操作的结点, 操作后再与原始结点交换, 类似于虚拟DOM

避免频繁直接访问计算后的样式, 而是先将信息保存下来

绝对布局的DOM, 不会造成大量reflow

div不要嵌套太深, 不要超过六层


用 JavaScript 对象模拟真实的 DOM 树,对真实 DOM 进行抽象;

diff 算法 - 比较两颗虚拟 DOM 树的差异;

Pach 算法 - 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。

实现diff算法

https://mp.weixin.qq.com/s/w2b9Wn7QWXhy2qf2JX3Kbw

分为三部:

(1)将模板(HTML)转化为Render(json对象),有四个属性:tagName, proporties, children, key。

(2)diff.js中,将两棵tree进行diff,node和property两个方面,同时记录一个patchList,他是一个二维数组,每个元素里面记录了当前tree的层级里的修改类型【node的增删改,property的增删改,text的修改】以及具体的修改值【key,value】

(3)patch.js中,将上面的patchList记录的操作,遍历dom,逐层进行对应的修改。

47.组件中 data 为什么是一个函数

因为组件是用来复用的,且 JS 里对象是引用关系,如果组件中 data 是一个对象,那么这样作用域没有隔离,子组件中的 data 属性值会相互影响,如果组件中 data 选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,组件实例之间的 data 属性值不会互相影响;而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。

48.vue-router路由守卫

https://www.cnblogs.com/qdlhj/p/9838426.html

(1)全局前置守卫 beforeEach (to, from, next)

页面登录判断,管理员权限判断

(2)路由独享守卫 beforeEnter

(3)组件内的守卫

beforeRouteEnter, beforeRouteUpdate, beforeRouteLeave

a)清除计时器 b)提醒关闭前保存表单 c)提醒将跳转到外部网站

https://github.com/linxner/front-end-basics/blob/master/Vue.md

导航解析流程

导航被触发。

在失活的组件里调用 beforeRouteLeave 守卫。

调用全局的 beforeEach 守卫。

在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。

在路由配置里调用 beforeEnter。

解析异步路由组件。

在被激活的组件里调用 beforeRouteEnter。

调用全局的 beforeResolve 守卫 (2.5+)。

导航被确认。

调用全局的 afterEach 钩子。

触发 DOM 更新。

调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

守卫方法参数

to: Route: 即将要进入的目标 路由对象

from: Route: 当前导航正要离开的路由

next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。

next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。

next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

49.深拷贝与浅拷贝

深拷贝

(1)用 JSON.stringify 把对象转换成字符串,再用 JSON.parse 把字符串转换成新的对象。

(2)Object.assign()拷贝

当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

(3)通过jQuery的extend方法实现深拷贝

let obj2=$.extend(true,{},obj1);

(4)lodash.cloneDeep()实现深拷贝

50.数据防抖节流的方法和场景

防抖:一般用在搜索栏的自动补全,

节流:一般用在onResize,mouseMove,onScroll等频繁调用的场景,频繁操作点赞,取消点赞

当 Event loop 执行完 Microtasks 后,会判断 document 是否需要更新。因为浏览器是 60Hz 的刷新率,每 16ms 才会更新一次。

然后判断是否有 resize或者 scroll,有的话会去触发事件,所以 resize和 scroll事件也是至少 16ms 才会触发一次,并且自带节流功能。

作者:Java永远滴神

链接:https://www.jianshu.com/p/efd91b819000

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

51.css 动画

transition

(1):hover 改变宽高时,可以设置transition来设置

img{transition-property:height;transition-duration:1s;transition-delay:1s;transition-timing-function:ease;}

animation

div:hover {animation:1s rainbow infinite;}

div:hover {animation-name:rainbow;animation-duration:1s;animation-timing-function:linear;animation-delay:1s;animation-fill-mode:forwards;animation-direction:normal;animation-iteration-count:3;}

div:hover {animation-play-state:running/paused;}

keyframe

@keyframes rainbow{0% {background:#c00}50% {background:orange}100% {background:yellowgreen}}

目前,IE 10和Firefox(>= 16)支持没有前缀的animation,而chrome不支持,所以必须使用webkit前缀

也就是说,实际运用中,代码必须写成下面的样子。

div:hover {-webkit-animation:1s rainbow;animation:1s rainbow;}@-webkit-keyframes rainbow{0% {background:#c00;}50% {background:orange;}100% {background:yellowgreen;}}@keyframes rainbow{0% {background:#c00;}50% {background:orange;}100% {background:yellowgreen;}}

52.实现一个bind函数

函数柯里化

53.实现一个Promise

54.Generator

5.2 ES6 Generator 函数 | 菜鸟教程 (runoob.com)

(1)function后面有个* 号。

(2)函数内部有yield表达式。

55.路由守卫

(1)全局守卫 router.beforeEach

是否需要登录

(2)独享守卫 router.beforeEnter

个别页面需要权限校验

(3)页面内守卫 router.beforeRouterEnter, router.beforeRouterUpdate, router.beforeRouterLeave.

离开页面清空计时器,离开页面前提示是否保存

56. $route和$router的区别

$router为Vue Router实例,想要导航到不同URL,则使用$router.push方法

$route为当前router跳转对象,里面可以获取name、path、query、params等

57.修改第三方库的样式    /deep/ >>>

58.防止模板渲染时闪动

59.gulp

gulp是一个前端工程化工具,类似于一个自动化脚本的工具。

它里面可以定义很多task,启动一个task后,会结合gulp的一些插件对项目文件进行处理,并用pipe()来进行同步处理。

原生API:

gulp.src(globs[, options]) 返回符合匹配规则的虚拟文件对象流(Vinyl files)。

gulp.dest(path[, options]) 用来指定要生成的文件的目录,目录路径为path。

gulp.task(name[, deps], fn) 定义一个流任务,任务名为name。

gulp.watch(glob[, opts], tasks) 监视文件的变化,执行操作。

Gulp插件

gulp-scss 编译css文件(注意:windows下使用 gulp-sass)

gulp-connect 来启动一个服务器

gulp-concat 合并js文件

gulp-uglify js文件压缩

gulp-rename重命名

gulp-minify-css 压缩css

gulp-babel 将es6代码转成es5

webpack和gulp有什么区别

gulp是基于流的构建工具:all in one的打包模式,输出一个js文件和一个css文件,优点是减少http请求,万金油方案。gulp强调的是前端开发的工作流程,我们可以通过配置一系列的task,定义task处理的事务(例如文件压缩合并、雪碧图、启动server、版本控制等),然后定义执行顺序,来让gulp执行这些task,从而构建项目的整个前端开发流程。

PS:简单说就一个Task Runner。

webpack是模块化管理工具:all in js,使用webpack可以对模块进行压缩、预处理、打包、按需加载等。webpack是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源(图片、js文件、css文件等)都看成模块,通过loader(加载器)和plugins(插件)对资源进行处理,打包成符合生产环境部署的前端资源。

PS:webpack is a module bundle

60.MVVM

MVVM支持双向绑定,意思就是当M层数据进行修改时,VM层会监测到变化,并且通知V层进行相应的修改,反之修改V层则会通知M层数据进行修改,以此也实现了视图与模型层的相互解耦

61.安全检查

(1)API必须有身份校验Token。

(2)对于敏感数据,例如银行账号、交易流水,在进行操作时必须二次校验,不能存储在公有云上。

(3)个人信息的获取要最小化收集,符合中国个人信息保护法。

a)最小化收集 b)提供给其他机构 c)不得披露个人信息

(4)注意XSS攻击

(5)上传文件的类型,大小

(6)前台弹报错信息只能为一般信息,不能包括后台具体log日志。

62.http错误码

200:请求成功

201:服务器成功创建了信息

202:服务器成功接收信息,没处理

203:非授权信息,服务器成功处理了请求,但返回信息来自另一个服务器

204:返回无内容

fetch发送post请求的时候,总是发送2次,第一次状态码是204,第二次才成功?

原因很简单,因为你用fetch的post请求的时候,导致fetch 第一次发送了一个Options请求,询问服务器是否支持修改的请求头,如果服务器支持,则在第二次中发送真正的请求。

205:返回无内容,且需要重置表单后重新提交

206:服务器已处理部分GET请求

301:资源(网页等)被永久转移到其他URL, 返回值中包含新的URL, 浏览器会自动定向到新URL

302:临时转移. 客户端应访问原有URL

304: Not Modified. 指定日期后未修改, 不返回资源

400:请求的url不存在,前端有语法错误

401:认证错误

403:服务器拒绝请求

404:请求的页面不存在

408:请求超时

500:服务器内部错误

501:服务器不具备完成请求的功能,识别不了请求。

63.业务

某奢侈品牌车企,经理配车,经理配临时车,交接,保养

经理配车是为每位经理,每年申请一辆新的车。经理配车模块有三个页面:

第一个页面是申请人的基本信息,员工号(可以checkId,带出基本信息),姓名,部门,工作地点等信息,电话号和手机号可以修改。target car是根据当前申请人等级推荐的目标车辆,current car是当前已申请的车。然后选择是申请第一辆车/第二辆车,跳转到第二个页面。

第二个页面是选车页面,他上面的tab可以来切换车系,然后中间区域是选车型,颜色,内饰,加装项(Senior Manager以上级别),底部是当前选择的配置是否在车库中有现车,可以点击申请新车按钮,或者点击现车弹出弹框进行车辆选择。

第三个页面是当前申请车辆的信息,以及预算,包括超出自己级别时的月租金,下面是审批流,可以点击draft保存草稿或者点击apply进行申请。

经理配临时车可以选择申请原因,等待第一辆车,事故或者其他。可以在ATC Stock中选择一辆车。

申请单的5种状态:application,draft,approved,declined,modify。

申请后,车辆会经过release(出库),good receive(给到4S店),registration(上牌),handover(交接)


交接/维修保养使用手机端完成。

交接和维修保养的首页都是待提交/已提交的车辆列表,可以显示当前用户名下的车。

【交接】:(1)申请人/车辆信息,填写总行驶里程,是否加油/清洗等信息(2)车辆的文本(钥匙,车牌,年检标,交强险标,用户手册,三包手册,保修手册)(3)零件(警示三角标志,备胎,千斤顶,急救包)(4)整车状况(掉漆,玻璃,车灯)(5)交接员交接(保险卡,通行卡,是否有重大维修)(6)轮胎情况(品牌,使用时间,损伤)(7)车身照片,品牌维修厂以外 的维修记录

【保养】:(1)申请人信息,实际申请人信息,可以checkId(2)查看对应实际申请人的车辆,根据车架号,车牌号选择需要保养的车辆(3)常规保养项(4)非常规保养项(5)夏/冬胎保养(6)选择经销商

64.Event Loop

https://www.jianshu.com/p/03b89adb3ddd

(1)先同步,后异步

(2)先微任务(Promise),后宏任务(setTimeout)

执行时,会先从上到下的扫一遍,同步执行。

然后执行微任务,注册宏任务,执行宏任务时,如果有微任务,则先执行微任务,再执行宏任务。

65.js垃圾回收机制

(1)垃圾:指没有被引用的对象。

(2)根:全局变量,函数内部的参数/局部变量

(3)垃圾回收算法:标记清除法。他会从根开始,查看所有的子代变量,是否再引用链上,如果不在的,就会被删除掉

(4)只要是可达的,对象就会常驻内存,所以需要特别注意内存泄漏问题,常见的内存泄漏:

闭包会发生内存泄漏是因为内部函数会把外部函数的局部变量的作用域变为自身的作用域内。这样就算外部函数执行环境都销毁了,内部的局部变量还是会保留。

除非内部的匿名函数解除对活动变量的引用(解除对匿名函数的引用),才可以释放内存。

// 创建函数 还未调用

var creatFun = outerFun(7)

// 调用函数

var result = creatFun(8)

// 解除对匿名函数的引用

creatFun =null

内部算法

基本的垃圾回收算法称为“标记-清除”,定期执行以下“垃圾回收”步骤:

垃圾回收器获取根并“标记”(记住)它们。

然后它访问并“标记”所有来自它们的引用。

然后它访问标记的对象并标记它们的引用。所有被访问的对象都被记住,以便以后不再访问同一个对象两次。

以此类推,直到有未访问的引用(可以从根访问)为止。

除标记的对象外,所有对象都被删除。

66.构造函数实现原理

61.阻止默认行为

阻止事件传播(冒泡): e.stopPropagation()

阻止默认行为: e.preventDefault()

62.http缓存

http://www.wewyy.com/archives/444

Http缓存

http缓存分为强缓存(Expires和Cache-Control)和协商缓存(ETag-第一次请求后台返回 和If-None-Match-第二次请求后台返回 / Last-Modified和If-Modified-Since)

Etag生成:在nginx中生成,序列号中有两部分,前面是文件修改时间,后面是content size。

也可以在express配置动态接口,计算hash。

Cache-Control:no-cache 都需要最新的/ max-age=0 则需要校验etag和last-modified

优先级:

当Cache-Control设置为max-age=xx并且同时设置Expires时,Cache-Control的优先级更高

当ETag和Last-Modified同时存在时,服务器先会检查ETag,然后再检查Last-Modified,最终决定返回304还是200

63.CSRF攻击

<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

iframe

64.为什么直接操作DOM会变慢?触发了重绘和重排。

dom的几何形状发生变化或者浏览器窗口大小发生变化,就会引发重排。

dom的样式,比如颜色等发生变化时,会引发重绘。

实例

display:none: 会让元素完全从渲染树中消失,渲染的时候不占据任何空间, 不能点击,

visibility: hidden:不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,不能点击

opacity: 0: 不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,可以点击

继承:

display: none和opacity: 0:是非继承属性,子孙节点消失由于元素从渲染树消失造成,通过修改子孙节点属性无法显示。

visibility: hidden:是继承属性,子孙节点消失由于继承了hidden,通过设置visibility: visible;可以让子孙节点显式。

性能:

display: none : 修改元素会造成文档回流,读屏器不会读取display: none元素内容,性能消耗较大

visibility:hidden: 修改元素只会造成本元素的重绘,性能消耗较少读屏器读取visibility: hidden元素内容

opacity: 0 : 修改元素会造成重绘,性能消耗较少


65.HTTP/2多路复用

https://segmentfault.com/a/1190000011172823

Keep-Alive: Keep-Alive解决的核心问题:一定时间内,同一域名多次请求数据,只建立一次HTTP请求,其他请求可复用每一次建立的连接通道,以达到提高请求效率的问题。这里面所说的一定时间是可以配置的,不管你用的是Apache还是nginx。

解决两个问题: 串行文件传输(采用二进制数据帧); 连接数过多(采用流, 并行传输)

66.三次握手/四次挥手

https://www.jianshu.com/p/d3725391af59

67.http和https:

http: 最广泛网络协议,BS模型,浏览器高效。

https: 安全版,通过SSL加密,加密传输,身份认证,密钥

https相对于http加入了ssl层, 加密传输, 身份认证;

需要到ca申请收费的证书;

安全但是耗时多,缓存不是很好;

注意兼容http和https;

连接方式不同, 端口号也不同, http是80, https是443

连接步骤:

(1)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。

  (2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。

  (3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。

  (4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。

  (5)Web服务器利用自己的私钥解密出会话密钥。

  (6)Web服务器利用会话密钥加密与客户端之间的通信。

中间人攻击过程如下:

服务器向客户端发送公钥。

攻击者截获公钥,保留在自己手上。

然后攻击者自己生成一个【伪造的】公钥,发给客户端。

客户端收到伪造的公钥后,生成加密hash值发给服务器。

攻击者获得加密hash值,用自己的私钥解密获得真秘钥。

同时生成假的加密hash值,发给服务器。

服务器用私钥解密获得假秘钥。

服务器用加秘钥加密传输信息

防范方法:

服务端在发送浏览器的公钥中加入CA证书,浏览器可以验证CA证书的有效性

68.xss与csrf攻击

xss一般可能出现在iframe,点击一个链接,或者评论区,我写了一段脚本,然后提交,这样其他人看到我的评论的时候,就都会呗脚本注入攻击。

目的一般是获取cookie或者浏览器里的缓存,再就是劫持input和submit获取提交的表单信息。

防范:

(1)浏览器将禁止页面的Javascript 访问带有 HttpOnly 属性的Cookie

http  字段 cookie的httponly属性。若此属性为true,则只有在http请求头中会带有此cookie的信息,而不能通过document.cookie来访问此cookie。

(2)输入/输出检查。在 XSS 防御中,输入检查一般是检查用户输入的数据中是否包含 <,> 等特殊字符,如果存在,则对特殊字符进行过滤或编码,这种方式也称为 XSS Filter。

csrf:

浏览器所持有的 Cookie 分为两种:

Session Cookie(会话期 Cookie):会话期 Cookie 是最简单的Cookie,它不需要指定过期时间(Expires)或者有效期(Max-Age),它仅在会话期内有效,浏览器关闭之后它会被自动删除。

Permanent Cookie(持久性 Cookie):与会话期 Cookie 不同的是,持久性 Cookie 可以指定一个特定的过期时间(Expires)或有效期(Max-Age)。

可以在一个<img>的src设置成一个删除的get请求,这样有cookie的话,会直接删除。

比如我知道一个博客删除自己所有博客的请求,是一个get请求,那么我在看其他博客的时候,如果点进一个恶心网站,里面有一个<img>里的src是哪个删除所有博客的get请求,那么所有博客会直接删除。

防范:Referer Check

根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。通过 Referer Check,可以检查请求是否来自合法的”源”。

比如,如果用户要删除自己的帖子,那么先要登录 www.c.com,然后找到对应的页面,发起删除帖子的请求。此时,Referer 的值是 http://www.c.com;当请求是从 www.a.com 发起时,Referer 的值是 http://www.a.com 了。因此,要防御 CSRF 攻击,只需要对于每一个删帖请求验证其 Referer 值,如果是以 www.c.com 开头的域名,则说明该请求是来自网站自己的请求,是合法的。如果 Referer 是其他网站的话,则有可能是 CSRF 攻击,可以拒绝该请求。

验证码,token

69.页面回退刷新 (HTML5的新API扩展了window.history)

70.在非简单请求且跨域的情况下,浏览器会发起options预检请求。

https://blog.csdn.net/qq_33712668/article/details/90551359

关于简单请求和复杂请求:

1 简单请求

简单请求需满足以下两个条件

请求方法是以下三种方法之一:

HEAD/GET/POST

HTTP 的头信息不超出以下几种字段

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type: 只限于 (application/x-www-form-urlencoded、multipart/form-data、text/plain)

2 复杂请求

非简单请求即是复杂请求

常见的复杂请求有:

请求方法为 PUT 或 DELETE

Content-Type 字段类型为 application/json

添加额外的http header 比如access_token

在跨域的情况下,非简单请求会先发起一次空body的OPTIONS请求,称为"预检"请求,用于向服务器请求权限信息,等预检请求被成功响应后,才发起真正的http请求。

71.移动端适配

<meta name="viewport" content="width=device-width, initial-scale=1.0">

(设置 initial-scale=1 其实是让 dips 像素与 CSS 像素的比例达到 1:1)

rem, em, 百分比

框架的栅格布局

media query媒体查询

判断机型, 找出样本机型去适配. 比如iphone以6为样本, 宽度375px, dpr是2

我们举个简单例子,MacBook Pro 13.3 英寸的显示器分辨率是 2560 x 1600,这个 2560px 就是我们前面说的设备上的物理像素值,而浏览器全屏显示的宽度只有 1280px,这个就是 dips

72.为什么以iPhone6为标准的设计稿的尺寸是以750px宽度来设计的呢?

iPhone6的满屏宽度是375px,而iPhone6采用的视网膜屏的物理像素是满屏宽度的2倍,也就是dpr(设备像素比)为2, 并且设计师所用的PS设计软件分辨率和像素关系是1:1。所以为了做出的清晰的页面,设计师一般给出750px的设计图,我们再根据需求对元素的尺寸设计和压缩。

73.iPhoneX适配

<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">

viewport-fit取值如下:  (auto默认)

viewprot-fit:contain;页面内容显示在safe area内

viewport-fit:cover,页面内容充满屏幕,需要设置css如下:

body {

    padding-top: constant(safe-area-inset-top);   //为导航栏+状态栏的高度 88px

    padding-left: constant(safe-area-inset-left);   //如果未竖屏时为0

    padding-right: constant(safe-area-inset-right); //如果未竖屏时为0

    padding-bottom: constant(safe-area-inset-bottom);//为底下圆弧的高度 34px

}


74.媒体查询

https://www.cnblogs.com/nyw1983/p/11409219.html

@media mediatype and/not/only(media feature) { CSS-Code }

mediatype:

all 适用于所有类型

print 适用于打印机和打印预览

screen 适用于电脑屏幕、平板电脑、智能手机等

speech 适用于屏幕阅读器

@support

https://blog.csdn.net/liaobangxiang/article/details/80706922

75.关于图片

https://zhuanlan.zhihu.com/p/66331977

jepg是有损压缩,去除了人眼看不到的像素。

png是无损压缩,他压缩后可以恢复原图。(最优)

svg是矢量图,体积小,边缘圆滑,可以看到具体的编写代码。

76.webRTC 浏览器视频通话技术

https://javascript.ruanyifeng.com/htmlapi/webrtc.html

用户可以通过navigator.getUserMedia({video: true, audio:true}, onSuccess, onError)来获取音视频数据

在<video src="aaa">标签中将onSuccess返回的stream通过window.URL.createObjectURL(stream)转换成url。

这样video标签里就能调用摄像头,调用时会和用户确认相机调用权限。

通讯使用RTCPeerConnection技术

77.什么是Bom?有哪些常用的Bom属性?

https://www.jianshu.com/p/573783b203b4

Bom是浏览器对象模型,他把浏览器抽象成一个对象,window是最顶层的对象。

window有两个常用的:添加监听函数【load】,在页面load的时候执行初始化方法,

第二个,是setTimeout()和setInterval()

location.assign 记录浏览历史,所以可以实现后退功能

location.replace 不记录浏览历史,所以不可以实现后退功能。

78.link与@import的区别

参考答案

link是 HTML 方式, @import是 CSS 方式

link最大限度支持并行下载,@import过多嵌套导致串行下载,出现FOUC

link可以通过rel="alternate stylesheet"指定候选样式

浏览器对link支持早于@import,可以使用@import对老浏览器隐藏样式

@import必须在样式规则之前,可以在 css 文件中引用其他文件

import循环引用:

http://www.ruanyifeng.com/blog/2015/11/circular-dependency.html

79.简述一下原型 / 构造函数 / 实例

原型(prototype): 一个简单的对象,用于实现对象的属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个JavaScript对象中都包含一个__proto__(非标准)的属性指向它爹(该对象的原型),可obj.__proto__进行访问。

构造函数: 可以通过new来新建一个对象的函数。

实例: 通过构造函数和new创建出来的对象,便是实例。实例通过__proto__指向原型,通过constructor指向构造函数

这里来举个栗子,以Object为例,我们常用的Object便是一个构造函数,因此我们可以通过它构建实例。

// 实例

const instance = new Object()

80.seo优化

合理的title、description、keywords:搜索对着三项的权重逐个减小,title值强调重点即可,重要关键词出现不要超过2次,而且要靠前,不同页面title要有所不同;description把页面内容高度概括,长度合适,不可过分堆砌关键词,不同页面description有所不同;keywords列举出重要关键词即可

语义化的HTML代码,符合W3C规范:语义化代码让搜索引擎容易理解网页。

81.实现一个Vue自定义指令懒加载

https://mp.weixin.qq.com/s/36oBZMd-m-2k5EKPghfG3A

是指图片的懒加载。http://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html

82.webpack的热替换HMR

https://blog.csdn.net/qq593249106/article/details/84928595

通过在插件plugins里webpack的热替换插件webpack.hotModuleReplacementPlug(),并且在index.js入口文件中,添加module.hot.accept('被监听.js', function(){

替换index.js中的所有dom

})

关于css的热替换,可以使用 style-loader和css-loader。

83.webpack-dev-server

https://www.cnblogs.com/longlongdan/p/12391740.html

84.socket

85.ES6 import 和 require的区别

(1)require是函数,在文件里的任意地方都可使用,import是编译时导入,只能是在最上面,否则报错,会有提升至最头部定义。

(2)requre会对简单数据类型浅拷贝,源文件的值改变,不会影响到引用的变量的值;import是值引用,源文件的变量值的改变,会影响到引用文件内变量值的改变

86.bundle.js的底层原理 (源码)

https://blog.csdn.net/qq_40036736/article/details/93979791

87.vue双向绑定数组

cnblogs.com/wangweianger/p/10318255.html

他会重写Array的原型方法中的push, pop, splice, reverse方法,在Object.defineProperty(data, key, value())中注册watcher。

88.浏览器进程架构

1、浏览器是多进程

2、不同类型的标签页都会开启一个新的进程

3、相同类型的标签页是会合并到一个进程

以Chrome浏览器中为例,当你打开一个 Tab 页时,其实就是创建了一个进程(chrome使用多个进程来隔离不同的标签页。默认每一个tab页都是一个进程,互不影响)当然浏览器也会有自己的优化机制,比如打开多个空白的标签页,在chrome的任务管理器里面,就会发现把这些空白页,都合成了一个进程,所以一个tab标签页对应一个进程也不是绝对的

一个进程中可以有多个线程,比如渲染线程、JS 引擎线程、HTTP 请求线程等等。

当你发起一个请求时,其实就是创建了一个线程,当请求结束后,该线程可能就会被销毁。


浏览器内核(浏览器渲染进程)

浏览器内核是通过取得页面内容、整理信息(应用CSS)、计算和组合最终输出可视化的图像结果,通常也被称为渲染引擎。

浏览器内核是多线程

浏览器渲染进程会开启多个线程协作完成,包括以下两种线程:

主线程(下面的都是线程啊!这只是线程的分类)

js引擎线程 : 编译运行js程序

GUI 渲染线程:渲染和绘制页面

【 html,css文档解析模块 : 解析页面文本,DOM/CSS模块 : 负责dom/css在内存中的相关处理 ,布局和渲染模块 : 负责页面的布局和效果的绘制(内存中的对象)】

分线程

定时器管控和触发线程: 负责定时器的管理

DOM事件管控和触发线程 : 负责事件的管理

异步HTTP 请求线程 : 负责Ajax请求

详细介绍

GUI渲染线程

主要负责页面的渲染,解析HTML、CSS,构建DOM树,渲染成RenderObject树,布局和绘制等。

当界面需要重绘或者由于某种操作引发回流时,将执行该线程。

当RenderObject树需要更新样式属性时,即发生重绘(Repaint);

当RenderObject树中的元素规则尺寸,布局或显示隐藏等发生变化,即发生回流(reflow)

GUI渲染线程与JS引擎线程是相互排斥的

因为JS引擎线程在执行的过程中可能会发生重绘和回流,

所以GUI渲染线程执行时,JS引擎线程会被挂起,等待GUI渲染线程执行完毕之后,JS引擎线程执行

JS引擎线程执行时,GUI渲染会被挂起,当任务队列空闲时,主线程才会去执行GUI渲染。

JS引擎线程

主要负责处理 JavaScript脚本,执行代码。

也主要负责执行准备好待执行的事件(即定时器计数结束,或者异步请求成功并正确返回时,它们将依次进入任务队列,等待 JS引擎线程的执行)

当然,该线程与 GUI渲染线程互斥,当 JS引擎线程执行 JavaScript脚本时间过长,将导致页面渲染的阻塞。

定时器触发线程(定时器计时)

负责执行异步定时器一类的函数的线程,如: setTimeout,setInterval。

主线程依次执行代码时,遇到定时器,会将定时器交给该线程处理,当计数完毕后,事件触发线程会将计数完毕后的事件加入到任务队列的尾部,等待JS引擎线程执行。

事件触发线程(将计数完毕或触发点击的事件【触发回调】加入callback queue)

主要负责将准备好的事件交给 JS引擎线程执行。

比如 setTimeout定时器计数结束, ajax等异步请求成功并触发回调函数,或者用户触发点击事件时,该线程会将整装待发的事件依次加入到任务队列的队尾,等待 JS引擎线程的执行

异步http请求线程

负责执行异步请求一类的函数的线程,如: Promise,axios,ajax等。

主线程依次执行代码时,遇到异步请求,会将函数交给该线程处理,当监听到状态码变更,如果有回调函数,事件触发线程会将回调函数加入到任务队列的尾部,等待JS引擎线程执行。

相对于单进程浏览器,多进程浏览器的优势

避免单个页面奔溃影响整个浏览器

避免第三方插件奔溃影响整个浏览器

多进程充分利用多核优势

方便使用沙盒模式隔离插件等流程,提高浏览器稳定性

稳定性解释:

Google Chrome将插件或是网络应用放在与浏览器本身不同的进程中。在一个渲染引擎中的崩溃并不会影响浏览器本身或是其他网络应用。这意味着操作系统可以并发的运行网络应用来提高响应速度,如果一个特定的网络应用程序或是插件停止响应时浏览器本身并不会被死锁。这也意味着我们可以在一个严格意义上的沙箱内运行渲染引擎进程,帮助减少发生错误时造成的损失。

可以让你在不需要重启浏览器的情况下终止任何停止响应网络应用或插件。

使用多进程意味着Google Chrome可以有自己的任务管理器,你可以通过右击浏览器标题栏打开。这个任务管理器可以让你跟踪每个网络应用和插件的资源使用率,而不是针对整个浏览器。

针对以上原因,Google Chrome浏览器的多进程构架与单进程浏览器相比有更强的健壮性,更快的响应速度,同时更安全。

89.浏览器渲染过程

https://www.cnblogs.com/chenyoumei/p/9156849.html

90.Node事件循环

Node.js 在主线程里维护了一个事件队列,当接到请求后,就将该请求作为一个事件放入这个队列中,然后继续接收其他请求。当主线程空闲时(没有请求接入时),就开始循环事件队列,检查队列中是否有要处理的事件,这时要分两种情况:如果是非 I/O 任务,就亲自处理,并通过回调函数返回到上层调用;如果是 I/O 任务,就从线程池 中拿出一个线程来处理这个事件,并指定回调函数,然后继续循环队列中的其他事件。

当线程中的 I/O 任务完成以后,就执行指定的回调函数,并把这个完成的事件放到事件队列的尾部,等待事件循环,当主线程再次循环到该事件时,就直接处理并返回给上层调用。 这个过程就叫事件循环 (Event Loop),其运行原理如下图所示:

至此,对于 Node.js 的单线程模型,我们应该有了一个简单而又清晰的认识,它通过事件驱动模型实现了高并发和异步 I/O,然而也有 Node.js 不擅长做的事情:

上面提到,如果是 I/O 任务,Node.js 就把任务交给线程池来异步处理,高效简单,因此 Node.js 适合处理I/O密集型任务。但不是所有的任务都是 I/O 密集型任务,当碰到CPU密集型任务时,即只用CPU计算的操作,比如要对数据加解密(node.bcrypt.js),数据压缩和解压(node-tar),这时 Node.js 就会亲自处理,一个一个的计算,前面的任务没有执行完,后面的任务就只能干等着 。

在事件队列中,如果前面的 CPU 计算任务没有完成,后面的任务就会被阻塞,出现响应缓慢的情况,如果操作系统本身就是单核,那也就算了,但现在大部分服务器都是多 CPU 或多核的,而 Node.js 只有一个 EventLoop,也就是只占用一个 CPU 内核,当 Node.js 被CPU 密集型任务占用,导致其他任务被阻塞时,却还有 CPU 内核处于闲置状态,造成资源浪费。

因此,Node.js 并不适合 CPU 密集型任务。

浏览器和Node的事件循环:https://www.jianshu.com/p/b221e6e36dcb(浏览器会先执行完promsie的then,而Node会同步跑完所有的事件后,再执行promise 的then)。

浏览器Event Loop先同步任务,然后先执行所有的微任务,然后执行宏任务。

Node Event Loop会把I/O任务放到其他线程执行,注册完成的回调函数,执行完后将回调函数放回事件队列,等待再次执行。

91.除vuex其他的状态管理?

(1)provider inject (2)自定义写一个,主要是emit方法

92.vuex中大文件如何进行状态管理?

93.简单请求?options请求?

94.时间复杂度?

95.typescript的抽象类

(1)一个类是抽象的话,他不能实现,只能在子类中实现。

(2)抽象类中的一个方法是抽象的话,他不能写实现,需要在子类中写实现。

96.Typescript

https://www.jianshu.com/p/ae672b7a26e3

(1)三大特性:编译型语言:编译为 js 后运行,单独无法运行; 强类型语言; 面向对象的语言;

(2)优势:类型系统实际上是最好的文档,大部分的函数看看类型的定义就可以知道如何使用;

可以在编译阶段就发现大部分错误,这总比在运行时候出错好;

增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等;

总结:TypeSctipt增加了代码的可读性和可维护性。

(3)一看到使用 : 指定变量的类型,就是用的typescript。

(4)void 类型的变量只能赋值为 undefined 和 null

let unusable: void=undefined;

undefined 类型的变量只能被赋值为 undefined,null 类型的变量只能被赋值为 null

(5)数组

let list: number[] = [1,2,3];         let list: Array<number> = [1, 2, 3];

(6)元组

let arr: [string,number]=['name',20];

(7)symbol

let sym2=Symbol("key");     let sym3=Symbol("key"); 

sym2===sym3; // false, symbols是唯一的

(8)联合类型

let stringOrNumber: string|number;

(9)类型断言(Type Assertion)可以用来手动指定一个值的类型。 let strLength: number=(<string>someValue).length;

(10)字符串字面量类型

(11)接口定义

(12)接口-任意属性 (定义了任意属性,那么确定属性和可选属性都必须是它的子属性)

(13)接口-只读属性

(14)typescript的箭头函数

(15)可选参数

(16)默认参数

(17)剩余参数

(18)函数重载

(19)类的继承

(20)存取器

(21)访问修饰符

(22)抽象类/方法

(23)类实现接口 implement

(24)泛型约束

(25)声明文件declare

当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。

96.链表 https://www.cnblogs.com/zhoumingjie/p/11594991.html

(1)链表的定义,双向链表

(2)链表是否有环 (1.查看是否出现重复node 2.使用双指针)

(3)链表环的入口

(4)链表的应用(1.大数据的修改 2.轮播图和导航列表)

97.手写loader

(1)可以在src中直接新建一个loader.js 

可以使用'loader-utils'的getOptions来提取出参数。

可以传入一个文件path,来指定传入文件。

(2)在webpack.config.js中配置

entry中配置入口文件。

modules - rules - [ test, use(loader, options) ]

98.编写一个webpack插件

(1)定义一个class类

(2)原型函数中定义一个apply方法,里面传入compiler。

(3)调用compiler.hook的钩子,后面可以用tap/tapAsync(第二个入参可以是个callback)/tapPromise(返回一个Promise)

(4)事件钩子 - https://v4.webpack.docschina.org/api/compiler-hooks/

(5)compilation的结构,

compilation - chunk - module - fileDependency

compilation - chunk - files

99.angular和vue的区别

(1)体积上,vue+vuex+vue-router,gzip后只有30kb,angular-cli为65kb。

(2)开发效率,angular使用typescript(代码可读性,可维护性),vue使用js。

(3)灵活性,vue可以用CDN引入,作为一个前端的模板引擎使用。

(4)angular的静态检查,依赖注入,面向对象编程,对java程序员来说更容易上手。

100.webpack惰性加载,优化,AOT编译模式,tree shaking优化

webpack惰性优化:

AOT 预先/静态编译模式              JIT 即时编译

Angular使用的就是AOT编译模式,

使用Typescript编写,编译后不含HTML片段,全部为Typescript,再编译为Javascript。

101.单例

102.浏览器地址栏url到看到页面的全过程

 * 1.主进程接管。浏览器开一个下载线程

 * 2.HTTP请求,下载资源(DNS查询,IP寻址),三次握手,下载相应报文。

 * 3.渲染进程接管,渲染cssom tree和dom tree

 * 4.如果遇到script或者link标签,会优先进行script和link的加载,如果有缓存,则直接使用缓存资源。

 * 5.当cssom tree 和 dom tree都完成后,开始渲染render tree,通过render tree,浏览器会计算

 * 每个元素显示的位置,在浏览器上绘制成图像。

 * 6.关闭连接,四次挥手

ipv4:4字节,长度32位; ipv6:16字节,长度128位。

103.V8引擎 - https://www.cnblogs.com/wxmdevelop/p/10315622.html

使用c++编写,帮助把JS脚本转化为机器码,可以在所有的主流操作系统中运行,也可以嵌入浏览器,NodeJs。

他会负责编译/执行JS脚本,内存管理,垃圾回收,与宿主语言交互等功能。

二、算法

1.计算一个二叉树的高度

2.大数字加减法

3.数字添加千分位符

4.promise all 限制并发数

https://zhuanlan.zhihu.com/p/163287555

5.排序

https://zhuanlan.zhihu.com/p/101522204

 V8 引擎 sort 函数只给出了两种排序 InsertionSort 和 QuickSort,数量小于10的数组使用 InsertionSort,比10大的数组则使用 QuickSort。


6.二分查找

https://www.cnblogs.com/zuojiayi/p/6229902.html

三、小程序

1.小程序登录机制

(1)wx.login()获取code,传给服务器。

(2)服务器端把appId, appSecret, code传给微信接口code2session,换取openId和sessionKey。

(3)服务器端返回自定义登录态给小程序端,小程序保存到storage中,每次发起业务请求,携带自定义登录态,后台查询对应的openId和sessionKey,返回业务数据。

(4)sessionKey是会话密钥,当通过wx.getUserInfo()获取用户信息,其中请求了加密信息时,会返回加密数据encryptedData和加密算法的初始向量iv,需要传给后台通过sessionKey和iv解密出用户的加密信息,如openId和unionId。

2.滚动视图

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容