介绍一下Connection:keep-alive什么是keep-alive我们知道HTTP协议采用的是“请求-响应”模式。当使用普通模式,即非KeepAlive模式时,每次请求/回复客户端和服务端都必须建立新的连接,完成后立即断开连接(HTTP协议是无连接协议);当使用Keep-Alive模式(也称为持久连接,连接复用)时,Keep-Alive功能使客户端在连接到服务器端的连接保持有效。当有后续请求到服务器时,Keep-Alive功能避免建立或重新建立连接。为什么使用keep-alivekeep-alive技术的创建目的是在多个HTTP之前重用同一个TCP连接,从而减少创建/关闭多个TCP连接的开销(包括响应时间、CPU资源、减少拥塞等),参考下图显示了如何启用客户端。在HTTP/1.0协议中,默认是禁用的。需要在http头中添加“Connection:Keep-Alive”来启用Keep-Alive;Connection:keep-alive在HTTP1.1中默认启用。如果您添加“连接:关闭”,它将被关闭。Connection:close目前大部分浏览器使用的是http1.1协议,也就是说默认会发起一个Keep-Alive连接请求,所以能否完成一个完整的Keep-Alive连接取决于服务器的设置。Promise.any说明:只要promise中有一个fulfilled,就返回第一个fulfilled的Promise实例的返回值。现实Promise.any=function(promises){returnnewPromise((resolve,reject)=>{if(Array.isArray(promises)){if(promises.length===0)returnreject(newAggregateError("All承诺被拒绝了”));letcount=0;promises.forEach((item,index)=>{Promise.resolve(item).then(value=>resolve(value),reason=>{count++;if(count===promises.length){reject(newAggregateError("Allpromiseswererejected"));};});})}elsereturnreject(newTypeError("Argumentisnotiterable"));});}代码输出结果asyncfunctionasync1(){console.log("async1start");等待async2();console.log("async1end");}asyncfunctionasync2(){console.log("async2");}async1();console.log('start')输出结果如下:async1startasync2startasync1end代码的执行过程如下:首先执行函数中的同步代码async1start,然后然后遇到await,会阻塞async1后面代码的执行会先执行async2中的同步代码async2,然后跳出async1;跳出async1函数后,执行同步代码start;经过一轮宏tasks执行完毕,然后执行awaitasync1end之后的内容这里可以理解,await之后的语句相当于放在newPromise中,下一行和后面的语句相当于放在Promise.then中,本质闭包生成的引用代码输出指向当前环境中的父作用域vara=3;functionc(){alert(a);}(function(){vara=4;c();})();js中变量的作用域链与定义时的环境,与执行时间无关。执行环境只会改变this,传参,全局变量等代码输出结果Promise.resolve('1').then(res=>{console.log(res)}).finally(()=>{console.log('finally')})Promise.resolve('2').finally(()=>{console.log('finally2')return'我是finally2返回的值'}).then(res=>{console.log('thenfunctionafterfinally2',res)})输出结果如下:1finally2finallyThenfunctionafterfinally22.finally()一般很少用到,只要记住以下几点:.finally()方法会无论Promise对象的最终状态如何,它都会被执行。finally()方法的回调函数是不接受任何参数的,也就是说在.finally()函数中你无法知道Promise的最终状态是resolved还是rejected。它最终会返回默认将是最后一个Promise对象值,但如果抛出异常,将返回异常Promise对象。finally本质上是then方法的一个特例。Finally()错误捕获:Promise.resolve('1').finally(()=>{console.log('finally1')thrownewError('IwasthrowninfinallyException')}).then(res=>{console.log('thenfunctionafterfinally',res)}).catch(err=>{console.log('catcherror',err)})输出结果为:'finally1''caughterror'Error:我是最后抛出的异常。详见前端进阶面试题的详细解答。Promise.resolvePromise.resolve=function(value){//1.如果value参数是Promise对象,则返回对象不变if(valueinstanceofPromise)returnvalue;//2.如果value参数是一个有then方法的对象,将这个对象转为Promise对象,并立即执行其then方法if(typeofvalue==="object"&&'then'invalue){returnnewPromise((resolve,reject)=>{value.then(resolve,reject);});}//3.否则返回一个新的Promise状态为fulfilled的Promise对象returnnewPromise(resolve=>resolve(value));}JS整数是怎么表示的?用Number类型表示,遵循IEEE754标准,一个数用64位表示,(1+11+52),最大安全数为Math.pow(2,53)-1,16位十进制。(符号位+指数位+小数有效位)vuexvuex是专门为vue.js应用开发的状态管理器,它采用集中存储的方式管理应用所有组件的状态,并保证状态在可预测的范围内以相应的规则变化方式。state:vuex使用单个状态树,其中包含所有应用程序级别的状态和一个对象。mutation:在vuex中改变state状态的唯一方法就是提交mutationaction:action提交mutation,而不是直接改变state。Action可以包含任何异步操作getter:相当于vue中计算属性代码的输出结果vara,b(function(){console.log(a);console.log(b);vara=(b=3);console.log(a);console.log(b);})()console.log(a);console.log(b);输出结果:undefinedundefined33undefined3本题与上题考察的知识点类似,b赋值3,此时b为全局变量,将3赋值给a,a为局部变量,所以当它最终被打印出来时,a仍然是未定义的。JS隐式转换,显示转换一般在转换非基本类型时,会先调用valueOf。如果valueOf无法返回基本类型值,则将调用toString字符串和数字“+”运算符。如果一个是字符串,那么既转换为字符串再进行字符串拼接“-”运算符,转换为数字,减(-a,a*1a/1)可以进行隐式强制转换[]+{}和{}+[]布尔值到数字1+true=21+false=1在第二个whileif三元表达式中转换为布尔值||(logicalor)&&(logicaland)operandsymbolsontheleftcannotbeconvertedtonumbersconvertedtoaboolean(bothtrue)canbeconvertedtoastring"Symbol(cool)"松散相等和严格相等松散相等允许强制转换,而严格相等不允许字符串和数字先转为数字再进行比较其他Type和Boolean先把Boolean类型转为数字,然后继续比较对象和非对象ExecuteToPrimitive(object)ofobjects然后继续比较false值列表undefinednullfalse+0,-0,NaN""setInterval模拟setTimeout说明:使用setInterval模拟实现setTimeout的功能。思路:setTimeout的特点是在指定时间内只执行一次。我们只需要在执行完setInterval里面的回调之后,关闭定时器即可。实现:constmySetTimeout=(fn,time)=>{lettimer=null;timer=setInterval(()=>{//关闭定时器,保证fn只执行一次,达到setTimeout的效果clearInterval(timer);fn();},time);//返回用于关闭定时器的方法return()=>clearInterval(timer);}//testconstcancel=mySetTimeout(()=>{console.log(1);},1000);//一秒后打印1js脚本加载问题,async,defer问题如果依赖其他脚本和DOM结果,使用defer如果不强依赖DOM和其他脚本,使用async的范围是什么?ES5中只有两种作用域:全局作用域和函数作用域。在JavaScript中,我们将作用域定义为一组规则,用于管理引擎如何根据标识符名称在当前作用域和嵌套子作用域中搜索变量(变量名或函数名)。在原型JavaScript中,所有对象都有一个特殊的原型内置属性,它实际上是对其他对象的引用。几乎所有对象都是使用非空值的原型属性创建的。我们可以将这个属性作为一个备份仓库,在尝试引用对象的属性时会触发get操作。第一步是检查对象本身是否具有此属性。如果它有这个属性,它就会被使用。如果没有,它将在原型中进行搜索。一层一层直到最顶层Object.prototype是基于原型扩展来描述原型链,什么是原型链,原型继承,ES5和ES6的继承和区别。说说slicesplicesplit的区别?//slice(start,[end])//slice(start,[end])方法:该方法是对数组进行部分截取,该方法返回一个新数组//参数start是该数组的起始索引截取,end参数等于要提取的最后一个字符的位置值加1(可选)。//包含源函数指定的从头到尾的元素,但不包括结束元素,如a.slice(0,3);//如果有负数,把负数加到长度上再除。//如果切片中负数的绝对值大于数组长度,则显示所有数组//如果只有一个参数,且参数大于长度,则为空。//如果结束位置小于开始位置,则返回一个空数组//返回的数为结束-开始的个数//原数组不变vararr=[1,2,3,4,5,6]/*console.log(arr.slice(3))//[4,5,6]从下标0到3,截取3之后的数console.log(arr.slice(0,3))//[1,2,3]截取下标0到下标3之前的数console.log(arr.slice(0,-2))//[1,2,3,4]console.log(arr.slice(-4,4))//[3,4]console.log(arr.slice(-7))//[1,2,3,4,5,6]console.log(arr.slice(-3,-3))//[]console.log(arr.slice(8))//[]*///个人总结:如果slice的参数是正数,从左往右数,如果是负数,从右往左数。//截取的数组与数字方向一致。如果有两个参数,截取的就是数字的交集。如果没有交集,将返回一个空数组。//ps:slice也可以切String,用法同array,但注意空格也算字符//splice(start,deletecount,item)//start:起始位置//deletecount:位数todelete//item:replaceditem//返回值为被删除的字符串//如果有额外的参数,item将被插入到被删除元素的位置。//splice:remove,splice方法从数组中移除一个或多个数组,并用新项替换它们。//举个简单的例子vara=['a','b','c'];varb=a.splice(1,1,'e','f');console.log(a)//['a','e','f','c']console.log(b)//['b']vara=[1,2,3,4,5,6];//console.log("删除:",a.splice(1,1,8,9));//删除:2//console.log("数组元素:",a);//1,8,9,3,4,5,6//console.log("删除:",a.splice(0,2));//Deleted:1,2//console.log("数组元素:",a)//3,4,5,6console.log("Deleted:",a.splice(1,0,2,2))//插入第二个数字为0,即删除0console.log("数组元素:",a)//1,2,2,2,3,4,5,6//split(string)//string.split(separator,limit):split方法将字符串分割成段,创建一个字符串数组。//可选参数limit可以限制分割的段数。//分隔符参数可以是字符串或正则表达式。//如果separator为空字符,则返回单字符数组,不改变原数组。vara="0123456";varb=a.split("",3);console.log(b);//b=["0","1","2"]//注:字符串。split()的作用与Array.join的作用相反。代码输出结果console.log('1');setTimeout(function(){console.log('2');process.nextTick(function(){console.log('3');})newPromise(function(resolve){console.log('4');resolve();}).then(function(){console.log('5')})})process.nextTick(function(){console.log('6');})newPromise(function(resolve){console.log('7');resolve();}).then(function(){console.log('8')})setTimeout(function(){console.log('9');process.nextTick(function(){console.log('10');})newPromise(function(resolve){console.log('11');resolve();}).then(function(){console.log('12')})})输出结果如下:176824359111012(1)第一轮事件循环流程分析如下:整体脚本进入mainThread,遇到console.log,输出1。遇到setTimeout,将其回调函数分发到宏任务EventQueue。暂且记录为setTimeout1。当遇到process.nextTick()时,它的回调函数被分发到microtaskEventQueue。将其表示为process1。遇到Promise,直接执行newPromise,输出7。然后分发到microtaskEventQueue。记录为then1。又遇到了setTimeout,它的回调函数被分发到宏任务EventQueue中,记录为setTimeout2。MacrotaskEventQueueMicrotaskEventQueuesetTimeout1process1setTimeout2then1上表是第一轮事件循环宏任务结束时各个EventQueue的情况,此时已经输出了1和7。找到process1和then1两个微任务:执行process1,输出6。执行then1,输出8。第一轮事件循环正式结束,本轮结果输出1,7,6,8。(2)第二轮时间循环从**setTimeout1**宏任务开始:先输出2,接下来遇到process.nextTick(),同样分发到microtaskEventQueue,记录为process2.新的Promise立即执行输出4,然后也分发到microtaskEventQueue,记录为then2。macrotaskEventQueuemicrotaskEventQueuesetTimeout2process2then2第二轮事件循环macrotask结束,发现有process2和then2两个微任务可以执行:output3.output5.第二轮事件循环结束,并且第二轮输出2,4,3,5。(3)第三轮事件循环开始,此时只剩下setTimeout2,执行。直接输出9。分发process.nextTick()到微任务事件队列。将其表示为process3。直接执行newPromise,输出11,将then分发到microtaskEventQueue中,记为then3。macrotaskEventQueuemicrotaskEventQueueprocess3then3第三轮事件循环macrotask执行完毕,执行两个microtasksprocess3和then3:输出10。输出12。第三轮事件循环结束,第三轮输出9,11,10,12.整个代码,一共三个事件循环,完整的输出是1,7,6,8,2,4,3,5,9,11,10,12。代码输出结果functionFoo(){Foo.a=function(){console.log(1);}this.a=function(){console.log(2)}}Foo.prototype.a=function(){console.log(3);}Foo.a=function(){console.log(4);}Foo.a();letobj=newFoo();obj.a();Foo.a();输出结果:421解析:Foo.a()这是调用Foo函数的静态方法a。Foo中虽然有一个优先级更高的属性方法a,但是此时并没有调用Foo,所以此时输出的是Foo的静态方法a的结果:4letobj=newFoo();new方法用于调用函数,返回函数实例对象。这时候Foo函数内部的属性和方法就被初始化了,原型链就建立起来了。obj.a();调用obj实例上的方法a,目前有两个a方法:一个是内部属性方法,一个是原型上的方法。当两者都存在时,先查找ownProperty,如果不存在,则去原型链中查找,于是在实例上调用a,输出:2Foo.a();按照步骤2,已经初始化并覆盖了Foo函数内部的property方法,使用了同名的静态方法,所以输出:1说说HTTP和HTTPS协议的区别?1、HTTPS协议需要CA证书,成本高;而HTTP协议不需要它。2、HTTP协议是一种超文本传输??协议,信息是以明文传输的,HTTPS是一种安全的SSL加密传输协议;3、使用的连接方式不同,端口也不同。HTTP协议端口为80,HTTPS协议端口为443;4、HTTP协议连接非常简单,无状态;HTTPS协议是用SSL和HTTP协议构建的网络协议,可以进行加密传输和身份认证。它比HTTP更安全。script标签中defer和async的区别如果没有defer或者async属性,浏览器会立即加载并执行相应的脚本。它不会等待后续加载的文档元素,读取到就开始加载执行,从而阻塞后续文档的加载。defer和async属性用于异步加载外部JS脚本文件,不会阻塞页面的解析。区别如下:执行顺序:多个带有async属性的标签不能保证加载顺序;多个具有defer属性的标签,标签按照加载顺序执行;脚本是否并行执行:async属性表示后续文档的加载和执行与js脚本的加载和执行是并行的,即异步执行;defer属性表示加载后续文档和js脚本的过程加载(此时只加载不执行)是并行(异步)进行的。js脚本需要等到document的所有元素都解析完后才执行,DOMContentLoaded事件触发执行前。
