1,简单讲解下http2的多路复用
在http1中,每次请求都会建立TCP连接,也就是3次握手四次挥手,这在请求过程中占用了很长的时间,即使开启了keep-alive,解决了多次连接的问题,但依然还有效率上的问题。
- 串行的文件输出。
- 连接数过多。
http2采用了二进制格式传输,取代了http1的文本格式,效率更高。多路复用代替了HTTP1的序列和阻塞机制,所有的相同域名请求都通过同一个TCP连接并发完成。消除了因多个TCP连接而带来的延时和内存消耗。 单个连接上可以并行交错的请求和响应,互不影响。
2,谈谈你对TCP三次握手和四次挥手的理解。
3次握手: 客户端发送一个带SYN标志的数据包给服务器。 服务端收到后 返回一个带有SYN/ACK标志的数据包表示传达确认信息。 客户端再回传一个带ACK标志的数据包代表握手结束。
4次挥手: 客户端进程发出连续释放报文,并停止发送数据。 服务器收到连续释放报文,发出确认报文。 服务器将最后的数据发送完毕,向客户端发送连续释放报文。 客户端收到服务器的连续释放报文,发出确认。服务器收到客户端的确认,进入closed状态。
3,有以下3个判断数组的方法,请分别介绍之间的区别和优劣
Object.prototype.toString.call()、 instanceof、 Array.isArray
Object.prototype.toString.call会返回[Object type],其中的type为当前参数的类型。 这种方法对于所有的类型都能进行判断。
instanceof是通过判断当前对象的原型链上是否有对应的prototype。 找到了就是true,找不到返回false。 所以instanceof只能判断对象类型,并且所有的对象类型instanceof Object 都为true
Array.isArray用来判断对象是否为数组。
4,介绍下重绘和回流,以及如何进行优化
1,浏览器渲染机制
-
- 浏览器采用流式布局模型
- 浏览器会把html解析为dom, 把css解析为cssom,dom和cssom合并就成了render tree
- 有了rendertree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后绘制也页面上。
- 由于浏览器使用流式布局,对render tree的计算通常只需要一次遍历。但table及其内部元素除外,他们可能要多次计算,通常可能会花3倍的时间,这就是为什么要避免table布局的原因。
2,重绘
由于节点的几何属性发生改变或者由于样式发生改变而不会影响布局的,称为重绘。 例如outline,visibility,color和background-color。
3,回流
页面的布局或者几何属性需要改变就称为回流。 回流是影响浏览器性能的关键因素,因为其变化涉及到了部分或整个页面的布局更新,一个元素的回流可能会导致其之后所有节点的回流。
回流必然会发生重绘,但重绘不一定引发回流。
4, 减少重绘与回流
-
-
- 设定元素的样式,尽量通过改变元素的class名。
- 避免设置多项内联样式
- 应用元素的动画应使用position属性的fixed值或absolute
- 避免使用table布局
-
5,用迭代的方式实现flatten函数
let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]; function flatten(arr) { while(arr.some(item => Array.isArray(item))) { arr = [].concat(...arr); } return arr; }
// 递归方法
function flatten(arr) { return arr.reduce((pre, next) => { return Array.isArray(next) ? [...pre, ...flatten(next)] : [...pre, next]; }, []) }
6,去除字符串前后的空格
// 模仿jquery中的trim函数
function fn(str) { const atrim = /^[suFEFFxA0]+|[suFEFFxA0]+$/g; // uFEFF代表 (字节次序标记字符) xA0 代表自动换行空白,也就是html里面nbsp
return String.prototype.trim ? (str+'').trim() : (str+'').replace(atrim, '');
}
7, 有一个指定的url https://www.baidu.com/s?id=111&name=xiaoming&age=20,写一个函数获取query的参数存放在对象里。
function getQuery() { var obj = {}, reg = /([^=&?]*)=([^=&?]*)/g, result = []; while (result = reg.exec(url)) { obj[result[1]] = result[2]; } return obj; }
8,从输入网址到网页渲染完成经历了哪些过程
- 输入网址
- 发送到dns服务器,获取域名对应的ip地址
- 与web服务器简历tcp连接
- 浏览器向web服务器发送http请求
- web服务器响应请求,并返回指定url的数据
- 浏览器下载web服务器返回的数据以及解析html源文件
- 生成dom树,解析css和js,渲染页面。
9,对一串数字进行科学计数法
function scienceCount(n) { return n.toString().replace(/B(?=(d{3})+(?!d))/g, ','); }
scienceCount(100000001111.234); //100,000,001,111.234
10,深拷贝
1 function isObject(obj) { 2 return typeof obj === 'object' && obj != null; 3 } 4 5 function deepCopy(source, hash = new WeakMap()) { // 这里使用weakMap存储, 是为了防止循环引用, 每次都要和weakMap里面已经存的对象进行比较看是否有相同的。 6 if (!isObject(source)) return source; 7 if (hash.has(source)) return hash.get(source); 8 9 var target = Array.isArray(source) ? [] : {}; 10 hash.set(source, target); 11 12 for (var key in source) { 13 if (Object.prototype.hasOwnProperty.call(source, key)) { 14 if (isObject(source[key])) { 15 target[key] = deepCopy(source[key], hash); 16 } else { 17 target[key] = source[key]; 18 } 19 } 20 } 21 return target; 22 }
11,节流和防抖
// 节流 function throttle(fn, wait){ var timeout, previous = 0; return (...args) => { var now = new Date().getTime(); if (!previous) previous = now; var remaining = wait - (now - previous); if (remaining <= 0) { clearTimeout(timeout); timeout = null; previous = now; fn(args); } else if (!timeout) { timeout = setTimeout(() => { timeout = null; previous = new Date().getTime(); fn(args); }, wait) } } }
// 防抖 function debounce (fn, wait) { var timeout; return (...args) => { clearTimeout(timeout);
timeout = (() => {
fn(args);
}, wait) } }
12,new的实现
- 创建一个新对象
- 将构造函数的作用域赋给新对象
- 执行构造函数中的代码
- 返回新对象
function _new(fn, ...args) { var obj = Object.create(fn.prototype); var result = fn.apply(obj, args); return typeof result === 'object' ? result : obj; }
13,跨域的几种方式
只要协议、域名和端口有任何一个不同,都被当做是不同的域。
1,jsonp
通过script标签引入的js是不受同源策略限制的。所以可以通过script标签引入一个js,此文件返回一个js函数的调用。
首先在页面中定义一个函数,然后在页面动态加载一个script标签,通过script标签的url将本地的函数名传过去,服务器返回的js文件中是这个函数的调用。
2,通过h5的postMessage方法
这个功能主要包括接收信息的message事件和发送信息的postMessage方法。
3,通过CORS跨域
CORS分为简单请求和非简单请求。
简单请求会在头信息中额外增加一个Origin字段,如果Origin在服务器的许可范围内,服务器返回的响应会多出几个头信息。
非简单请求会在正式通信之前增加一次http请求。会先用options方法发送一个请求看能否通信。
14,函数柯里化
function curry(fn, ...args) { var self = this; return function (...newArg) { return fn.apply(self, [...args, ...newArg]); } }
15, 实现bind方法
Function.prototype.bind = function (context, ...args) { var self = this; return function () { return self.apply(context, args); } }
16,比较两个对象相等
function isEqualObj(obj1, obj2) { if (obj1 === obj2) return true; const key1 = Object.getOwnPropertyNames(obj1); const key2 = Object.getOwnPropertyNames(obj2); if (key1.length !== key2.length) return false; for (let key of key1) { if (obj1[key] instanceof Object && obj2[key] instanceof Object) { return isEqualObj(obj1[key], obj2[key]) } else if (obj1[key] !== obj2[key]) { return false; } } return true; }