前端面试比较好的回答
介绍一下 Connection:keep-alive
什么是 keep-alive
我们知道 HTTP 协议采用“请求-应答”模式,当使用普通模式,即非 KeepAlive 模式时,每个请求/应答客户和服务器都要新建一个连接,完成 之后立即断开连接(HTTP 协议为无连接的协议);
当使用 Keep-Alive 模式(又称持久连接、连接重用)时,Keep-Alive 功能使客户端到服 务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。
为什么要使用 keep-alive
keep-alive 技术的创建目的,能在多次 HTTP 之前重用同一个 TCP 连接,从而减少创建/关闭多个 TCP 连接的开销(包括响应时间、CPU 资源、减少拥堵等),参考如下示意图
客户端如何开启
在 HTTP/1.0 协议中,默认是关闭的,需要在 http 头加入"Connection: Keep-Alive”,才能启用 Keep-Alive;
http 1.1 中默认启用 Keep-Alive,如果加入"Connection: close “,才关闭。
目前大部分浏览器都是用 http1.1 协议,也就是说默认都会发起 Keep-Alive 的连接请求了,所以是否能完成一个完整的 Keep- Alive 连接就看服务器设置情况。
Promise.any
描述:只要 promises
中有一个fulfilled
,就返回第一个fulfilled
的Promise
实例的返回值。
实现
代码输出结果
输出结果如下:
代码的执行过程如下:
首先执行函数中的同步代码
async1 start
,之后遇到了await
,它会阻塞async1
后面代码的执行,因此会先去执行async2
中的同步代码async2
,然后跳出async1
;跳出
async1
函数后,执行同步代码start
;在一轮宏任务全部执行完之后,再来执行
await
后面的内容async1 end
。
这里可以理解为 await 后面的语句相当于放到了 new Promise 中,下一行及之后的语句相当于放在 Promise.then 中。
闭包产生的本质
当前环境中存在指向父级作用域的引用
代码输出结果
js 中变量的作用域链与定义时的环境有关,与执行时无关。执行环境只会改变 this、传递的参数、全局变量等
代码输出结果
输出结果如下:
.finally()
一般用的很少,只要记住以下几点就可以了:
.finally()
方法不管 Promise 对象最后的状态如何都会执行.finally()
方法的回调函数不接受任何的参数,也就是说你在.finally()
函数中是无法知道 Promise 最终的状态是resolved
还是rejected
的它最终返回的默认会是一个上一次的 Promise 对象值,不过如果抛出的是一个异常则返回异常的 Promise 对象。
finally 本质上是 then 方法的特例
.finally()
的错误捕获:
输出结果为:
参考 前端进阶面试题详细解答
Promise.resolve
JS 整数是怎么表示的?
通过 Number 类型来表示,遵循 IEEE754 标准,通过 64 位来表示一个数字,(1 + 11 + 52),最大安全数字是 Math.pow(2, 53) - 1,对于 16 位十进制。(符号位 + 指数位 + 小数部分有效位)
vuex
代码输出结果
输出结果:
这个题目和上面题目考察的知识点类似,b 赋值为 3,b 此时是一个全局变量,而将 3 赋值给 a,a 是一个局部变量,所以最后打印的时候,a 仍旧是 undefined。
JS 隐式转换,显示转换
一般非基础类型进行转换时会先调用 valueOf,如果 valueOf 无法返回基本类型值,就会调用 toString
字符串和数字
"+" 操作符,如果有一个为字符串,那么都转化到字符串然后执行字符串拼接
"-" 操作符,转换为数字,相减 (-a, a * 1 a/1) 都能进行隐式强制类型转换
布尔值到数字
1 + true = 2
1 + false = 1
转换为布尔值
for 中第二个
while
if
三元表达式
|| (逻辑或) && (逻辑与)左边的操作数
符号
不能被转换为数字
能被转换为布尔值(都是 true)
可以被转换成字符串 "Symbol(cool)"
宽松相等和严格相等
宽松相等允许进行强制类型转换,而严格相等不允许
字符串与数字
转换为数字然后比较
其他类型与布尔类型
先把布尔类型转换为数字,然后继续进行比较
对象与非对象
执行对象的 ToPrimitive(对象)然后继续进行比较
假值列表
undefined
null
false
+0, -0, NaN
""
setInterval 模拟 setTimeout
描述:使用setInterval
模拟实现setTimeout
的功能。
思路:setTimeout
的特性是在指定的时间内只执行一次,我们只要在setInterval
内部执行 callback
之后,把定时器关掉即可。
实现:
js 脚本加载问题,async、defer 问题
如果依赖其他脚本和 DOM 结果,使用 defer
如果与 DOM 和其他脚本依赖不强时,使用 async
什么是作用域?
ES5 中只存在两种作用域:全局作用域和函数作用域。在 JavaScript 中,我们将作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套子作用域中根据标识符名称进行变量(变量名或者函数名)查找
原型
说一下 slice splice split 的区别?
代码输出结果
输出结果如下:
(1)第一轮事件循环流程分析如下:
整体 script 作为第一个宏任务进入主线程,遇到
console.log
,输出 1。遇到
setTimeout
,其回调函数被分发到宏任务 Event Queue 中。暂且记为setTimeout1
。遇到
process.nextTick()
,其回调函数被分发到微任务 Event Queue 中。记为process1
。遇到
Promise
,new Promise
直接执行,输出 7。then
被分发到微任务 Event Queue 中。记为then1
。又遇到了
setTimeout
,其回调函数被分发到宏任务 Event Queue 中,记为setTimeout2
。
上表是第一轮事件循环宏任务结束时各 Event Queue 的情况,此时已经输出了 1 和 7。发现了process1
和then1
两个微任务:
执行
process1
,输出 6。执行
then1
,输出 8。
第一轮事件循环正式结束,这一轮的结果是输出 1,7,6,8。
(2)第二轮时间循环从**setTimeout1**
宏任务开始:
首先输出 2。接下来遇到了
process.nextTick()
,同样将其分发到微任务 Event Queue 中,记为process2
。new Promise
立即执行输出 4,then
也分发到微任务 Event Queue 中,记为then2
。
第二轮事件循环宏任务结束,发现有process2
和then2
两个微任务可以执行:
输出 3。
输出 5。
第二轮事件循环结束,第二轮输出 2,4,3,5。
(3)第三轮事件循环开始,此时只剩 setTimeout2 了,执行。
直接输出 9。
将
process.nextTick()
分发到微任务 Event Queue 中。记为process3
。直接执行
new Promise
,输出 11。将
then
分发到微任务 Event Queue 中,记为then3
。
第三轮事件循环宏任务执行结束,执行两个微任务process3
和then3
:
输出 10。
输出 12。
第三轮事件循环结束,第三轮输出 9,11,10,12。
整段代码,共进行了三次事件循环,完整的输出为 1,7,6,8,2,4,3,5,9,11,10,12。
代码输出结果
输出结果:4 2 1
解析:
Foo.a() 这个是调用 Foo 函数的静态方法 a,虽然 Foo 中有优先级更高的属性方法 a,但 Foo 此时没有被调用,所以此时输出 Foo 的静态方法 a 的结果:4
let obj = new Foo(); 使用了 new 方法调用了函数,返回了函数实例对象,此时 Foo 函数内部的属性方法初始化,原型链建立。
obj.a() ; 调用 obj 实例上的方法 a,该实例上目前有两个 a 方法:一个是内部属性方法,另一个是原型上的方法。当这两者都存在时,首先查找 ownProperty ,如果没有才去原型链上找,所以调用实例上的 a 输出:2
Foo.a() ; 根据第 2 步可知 Foo 函数内部的属性方法已初始化,覆盖了同名的静态方法,所以输出:1
说一下 HTTP 和 HTTPS 协议的区别?
script 标签中 defer 和 async 的区别
如果没有 defer 或 async 属性,浏览器会立即加载并执行相应的脚本。它不会等待后续加载的文档元素,读取到就会开始加载和执行,这样就阻塞了后续文档的加载。
defer 和 async 属性都是去异步加载外部的 JS 脚本文件,它们都不会阻塞页面的解析,其区别如下:
执行顺序: 多个带 async 属性的标签,不能保证加载的顺序;多个带 defer 属性的标签,按照加载顺序执行;
脚本是否并行执行:async 属性,表示后续文档的加载和执行与 js 脚本的加载和执行是并行进行的,即异步执行;defer 属性,加载后续文档的过程和 js 脚本的加载(此时仅加载不执行)是并行进行的(异步),js 脚本需要等到文档所有元素解析完成之后才执行,DOMContentLoaded 事件触发执行之前。
评论