web前端常见面试题

Http

http和http的基本概念

http是一个客户端和服务器请求和应答标准(TCP),用于www服务器传输超文本到本地浏览器的超文本传输协议。
https是以安全为目标的HTTP通道,即http下加入了SSL层进行加密。主要作用是建立了一个信息安全通道,来确保数据的传输有一定的安全性,确保网站的真实性

http和https的区别以及优缺点

  1. http是超文本传输协议,信息是明文传输的,而https协议要比http协议更安全,https是具有安全性的ssl加密传输协议,可以防止数据在传输过程中不被窃取、改变,确保了数据的安全性以及完整性
  2. http协议的默认端口是80,https的默认端口则是443
  3. http链接很简单,是无状态的,https握手阶段比较费时,会导致页面加载时间延长50%,增加10%~20%的耗电
  4. https的缓存不如http的高效,会增加数据开销
  5. https协议需要ca证书,费用较高,功能越强大的证书费会越贵
  6. SSL协议需要绑定ip,不能在同一个ip上绑定多个域名,IPV4资源支持不了这种消耗

https协议的工作原理

客户端在使用https方式与web服务器通信的时候有以下几个步骤

  1. 客户端在使用https url访问服务器,要求web服务器建立ssl链接
  2. web服务器接收到客户端发出的请求后,会将网站的证书(证书中包含了公钥),传输给客户端。
  3. 客户端和web服务器端开始协商SSL链接的安全等级,也就是加密等级。
  4. 客户端浏览器通过双方协商一致的安全等级,会建立一个会话密钥,然后通过网站的公钥来加密会话密钥,并传输给网站
  5. web服务器通过自己的私钥解密出会话密钥
  6. web服务器通过会话密钥加密与客户端的通信

http请求跨域问题

跨域的原理

跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的
同源策略,是浏览器对JavaScript实施的安全限制,只要协议、域名、端口有任何一个不同、都被当做是不同的域
跨域原理,即是通过各种方式,避开浏览器的安全限制

解决方案
jsonp

ajax请求受同源策略影响,允许进行跨域请求,而script标签src属性中链接却可以访问跨域的js脚本,利用这个特性,服务端不再返回json格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样就实现了跨域功能,
jsonp缺点:jsonp只支持get,因为script标签只能使用get请求,jsonp需要后端配合返回指定格式的数据
步骤:

  1. 去创建一个script标签
  2. script的src属性设置接口地址
  3. 接口参数,必须要带一个自定义函数名,要不然后台无法返回数据
  4. 通过自定义函数名去接受返回的数据
//动态创建script
var script = document.createElement('script');
// 设置回调函数
function getData(data){
	console.log(data)
}
//设置script的src属性,并设置请求地址
script.src = 'http://localhost:80/?callback=getData'
//让script生效
document.body.appendChild(script)
CORS资源共享

浏览器会自动进行CORS通信,实现CORS通信的关键是后端。服务器设置Access-Contorl-Allow-Origin就可以开启CORS。该属性表示那些域名可以跨域访问资源
主要设置以下几个属性

  1. Access-Control-Allow-Origin //允许跨域的域名
  2. Access-Control-Allow-Headers //允许的header的类型
  3. Access-Control-Allow-Methods //跨域允许的请求方式
Nginx反向代理

通过nginx配置有个代理服务器将客户机请求转发给内部网络上的目标服务器,并将服务器上返回的结果返回给客户端

webpack (在Vue.config.js文件中) 配置webpack-dev-server
devServer: {
  proxy: {
    '/api': {
      target: "http://39.98.123.211",
      changeOrigin: true,  //是否跨域
    },
  },
},

TCP

TCP三次握手

  1. 第一次握手:建立链接时,客户端发送syn包到服务器,并进入SYN_SENT状态,等待服务器确认;同步序列编号
  2. 第二次握手:服务器收到syn包并确认客户的syn,同时也发送一个自己的syn包,即syn+ack包,此时服务器进入SYN_RECV状态;
  3. 第三次握手:客户端收到服务器的SYN+ACK包,想服务器发送确认包ACK,此包发送完毕,客户端和服务器进入ESTABLISHED(TCO链接成功)状态,完成三次握手

TCP四次挥手

  1. 客户端进程发出链接释放报文,并且停止发送数据,释放数据报文首部,FIN = 1,其序列号为seq = u(等于前面已经传送过来的数据的最后一个字节的序号加一),此时,客户端进入FIN-WAIT-1(终止等待)状态。TCP规定,FIN报文段即使不懈怠数据,也要消耗一个序号。
  2. 服务器收到链接释放报文,发出确认报文,ACK=1,ack = u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭的状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受,这个状态还要持续一段时间,也就是close-wait状态持续的时间
  3. 客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最 后的数据)。
  4. 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
  5. 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
  6. 服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

TCP/IP如何保证数据包传输的有序可靠?

对字节流分段并进行编号然后通过ACK回复和超时重发这两个机制来保证。

  1. 为了保证数据包的可靠传递,发送方必须把已发送的数据包保留在缓冲区;
  2. 并为每个已发送的数据包启动一个超时定时器
  3. 如在定时器超时之前收到了对方发送的应答信息,则释放该数据包占用的缓冲区
  4. 否则,重传该数据包,直到收到应答或者重传次数超过规定的最大次数为止。
  5. 接收方收到数据包后,先进行CRC校验,如果正确则把数据交给上层协议,然后给发送方发送一个累计应答包,表名数据已经收到,如果接收方正好也有数据要发给发送方,应答包也可在数据包中捎带过去

Cookie、sessionStorage、localStorage的区别

相同点

存储在客户端

不同点

  1. cookie数据大小不能超过4k,sessionStorage和localStorage的存储比cookie大的多,可以达到5M+
  2. cookie设置的过期时间之前一直有效;localStorage永久存储,浏览器关闭后数据不丢失除非主动删除数据,sessionStorage数据在当前浏览器窗口关闭时会自动删除
  3. cookie的数据会自动的传递到服务器;sessionStorage和localStorage数据保存在本地

val&&let && const

ES6之前创建变量用的是val,之后创建变量用的是let/const

三者区别

  1. var定义的变量,没有块的概念,可以跨块访问,不能跨函数访问
    let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问
    const 用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,并且不能修改。
  2. var 可以先使用,后声明,因为存在变量提升;let必须先声明后使用
  3. var 是允许在相同作用域内重复声明同一个变量的,而let和const不允许这一现象。
  4. 在全局上下文中,基于let声明的全局变量和全局对象GO(window)没有任何关系,var声明的变量会和GO又映射关系
  5. 会产生暂时性死区:
    暂时性死区是浏览器的bug:检测一个未被声明的变量类型时,不会报错,会返回undefined
    如:console.log(typeof a) //undefined
    而:console.log(typeof a)//未声明之前不能使用
    let a
  6. let/const/function会把当前所在的大括号(除函数之外)作为一个全新的块级上下文,应用这个机制,在开发项目的时候,遇到循环事件绑定等类似的需求,无需自己构建闭包来存储,只要基于let的块作用特征即可解决

JS垃圾回收机制

在项目中,如果存在大量不被释放的内存(堆/栈/上下文),页面性能会变得很慢,当某些代码操作不能被合理释放,会造成内存泄露,我们尽可能减少使用闭包,因为它会消耗内存
浏览器垃圾回收机制/内存回收机制:
浏览器的javascript具有自动垃圾回收机制,垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。

  1. 标记清除:在js中,最常用的垃圾回收机制是标记清除,当变量进入执行环境时,被标记为进入环境,当变量离开执行环境时,会标记为离开环境。垃圾回收器就会销毁那些带标记的值并回收他们所占用的内存空间
    谷歌浏览器:查找引用,浏览器不定时去查找当前内存的引用,如果没有被占用了,浏览器会回收他,如果被占用,就不能回收
    IE浏览器:引用计数法,当前内存被占用一次,计数累加1次,移除占用就减1,减到0时,浏览器就会回收它

优化手段

内存优化;手动释放:取消内存的占用即可
1. 堆内存:fn=null (null:空指针对象)
2. 栈内存:把上下文中,被外部占用的堆的占用取消即可。

内存泄漏

在js中,常见的内存泄露主要有4种:全局变量、闭包、DOM元素的引用、定时器

JS中this的五种清空

  1. 作为普通函数执行时,this指向window
  2. 当函数作为对象的方法被调用时,this就会指向该对象。
  3. 构造器调用,this指向返回的这个对象。
  4. 箭头函数 箭头函数的this绑定看的是this所在函数定义在那个对象下,就绑定哪个对象,如果有嵌套的情况,则this绑定最近的一层对象上。
  5. 基于function.prototype上的apply、call、和bind调用模式,这三个方法都可以显示的指定调用函数this指向。apply接收参数的是数组,call接收参数列表,bind方法通过传入一个对象,返回一个this绑定了传入对象的新函数。这个函数的this指向除了使用new时会被改变,其他情况都不会改变,若为空默认是指向全局对象的window。

介绍节流防抖原理、区别以及应用

节流

事件触发后,规定事件内,事件处理函数不能再次被调用。也就是说在规定时间内,函数只能被调用一次,且是最先被触发调用的那次

防抖

多次触发事件,事件处理函数只能执行一次,并且是在触发操作结束时去执行。也就是说,当一个事件被触发准备执行事件函数前,会等待一定的事件(这事件是码农自己去定义的,比如1秒),如果没有再次被触发,那么就执行,如果触发了,那就本次作废,重新从新触发的事件开始计算,并再次等待1秒,直到能最终执行!

使用场景

节流:滚动加载更多、搜索框的搜索联想功能、高频点击、表单重复提交…
防抖:搜索框搜索输入,并在输入完以后自动搜索、手机号、邮箱验证输入检测、窗口大小resize变化后,再重新渲染

/**
 *节流函数 一个函数执行一次后,只有大于设定的执行周期才会执行第二次。有个需要频繁触发的函数,出于优化性能的角度,在规定时间内,只让函数触发的第一次生效,后面的不生效。 
 * @param fn要被节流的函数
 * @param delay规定的时间
 */
function throttle(fn,delay){
	//记录上一次函数触发的事件
	var lastTime = 0;
	return function(){
		//记录当前函数触发的事件
		var nowTime = Date.now();
		if(nowTime - lastTime > delay){
			//修正this指向问题
			fn.call(this);
			//同步执行结束时间
			lastTime = nowTime;
		}
	}
}
document.onscroll = throttle(function(){
	console.log('scllor事件被触发了'+Data.now());
},200)


 
/**
 * 防抖函数  一个需要频繁触发的函数,在规定时间内,只让最后一次生效,前面的不生效
 * @param fn要被节流的函数
 * @param delay规定的时间
 */
function debounce(fn,delay){
	//记录上一次的延时器
	var timer = null;
	return function(){
		//清除上一次的延时器
		clearTimeout(timer);
		//重新设置新的延时器
		timer = setTimeout(function(){
			//修正this指向问题
			fn.apply(this);
		},delay)
	}
}

document.getElementById('btn').onclick = debounce(function(){
	console.log('按钮被点击了'+Data.now());
},1000)

  • 28
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值