笔试题
写出执行结果
for (let i = (setTimeout(() => { console.log(i) }, 50), 0); i < 5; i += 1) {
console.log(i)
}
// 执行结果: 0, 1, 2, 3, 4, 0 👈🏻这个是setTimeout中的log
// setTimeout中的log执行的时候先被压入消息队列, 待调用栈执行结束后从消息队列取出后再执行
// 考察解析: 闭包
// let i = (xx,x,xxx); 逗号操作符用于分隔多个表达式,并且返回最后一个表达式的值
// 主要用于重写运算符的优先级,会按照从左到右的顺序执行,并将最后一个值赋值给等式左边的变量
// 举例: const a = (1,2,3) // a = 3
写出执行结果
setTimeout(() => {
console.log(1)
})
const p = new Promise(resolve => {
resolve()
console.log(2)
})
p.then(() => {
console.log(3)
})
console.log(4)
// 执行结果: 2,4,3,1
// 考察解析: EventLoop
// 解析: 👇
// 4. 压入消息队列, 待执行栈为空且微任务队列也为空的时候被压入调用栈所出执行
setTimeout(() => {
console.log(1)
}) //此处省略了第二个参数, 默认为 0
// 1. 压入调用栈立即执行, 遇resolve被调用,意味着Promise对象已经成功完成. 继续执行console.log(2)
const p = new Promise(resolve => {
resolve()
console.log(2)
})
// 3. 遇到p的then回调函数, 被压入微任务队列, 待调用栈为空的时候被压入调用栈所执行
p.then(() => {
console.log(3)
})
// 2. 压入调用栈立即执行
console.log(4)
实现一种数组乱序算法, 例如 [1,2,3,4,5] => [6,3,1,2,5,4]
// 写的是最简单和常见的一种
const randomSort = (arr: number[]) => arr.sort(() => 0.5 - Math.random())
面试
vue2和vue3的区别
- 速度更快
- 重写虚拟DOM实现
- 编译模板优化
- 更高效的组件初始化
undate
性能提高SSR
速度提高
- 体积更小
- 结合
webpack
的tree-shaking
功能仅打包需要的代码tree-shaking:
- 对开发者,不必担心整体体积过大
- 对使用者,打包的体积变小
- 结合
- 更易维护
- 新增
composition API
- 灵活的逻辑组合与复用
- 可与现有的
Options API
一起使用 vue3
模块可以搭配其他框架使用
- 新增
- 更好的Typescript支持
vue3
基于typescript编写
- 编译器重写
- 更接近原生
- 自定义渲染API
import { createRender } from '@vue/runtime-core'
- 自定义渲染API
- 更易使用
- 响应式
API
的暴露import { observable } from 'vue'
- 响应式
- 新特性
Framents
- vue3版本中, 页面或者组件支持多个根节点
<template> <header /> <main /> <footer /> </template>
- vue3版本中, 页面或者组件支持多个根节点
Teleport
- 利用
Teleprot
能够将DOM移动到其他位置的技术<button @click="showToast" class="btn">打开 toast</button> <!-- to 属性就是目标位置 --> <teleport to="#teleport-target"> <div v-if="visible" class="toast-wrap"> <div class="toast-msg">我是一个 Toast 文案</div> </div> </teleport>
- 利用
CreateRender
- 通过
CreateRender
构建自定义渲染器import { createRenderer } from '@vue/runtime-core' const { render, createApp } = createRenderer({ patchProp, insert, remove, createElement, // ... }) export { render, createApp }
- 通过
CompositionAPI
- ...
GET和POST的区别
- 协议解释
GET
和POST
都是HTTP
协议的请求方法, 二者都是TCP
链接GET
方法用于请求一个地址的资源, 使用GET
的请求应该只用于数据的获取POST
方法用于将数据提交到指定的资源地址, 通常会使服务器上产生一些变化或者副作用
- 区别
GET
请求在浏览器后退的时候无害,POST
会再次提交表单GET
产生的URL地址可以被添加为Bookmark(书签)
,POST
不可以GET
请求会被浏览器主动cache
,POST
在非手动设置下不会GET
请求只能进行URL编码,POST
支持多种编码方式GET
请求的参数会被完整保存在浏览器历史记录中,POST
的参数不会被保留GET
请求在URL中传输的参数长度有限,POST
没有GET
比POST
更加不安全, 因为参数直接暴露在URL中, 不适宜传递敏感信息POST
请求可能会自动变成OPTIONS
请求, 可能原因如下- 遇 跨域资源共享
(CORS)
,服务端未配置CORS
情况下Ajax
请求被拒绝,变成了OPTIONS
请求进行预检请求
预检请求
: 在发送实际请求前, 发送OPTIONS
请求获取服务器支持的HTTP
请求方法或者检查服务器性能.- 如果服务器返回的响应头中包含了
ALLOW
, 那么就标识了服务器所支持的HTTP
请求方法
- 如果服务器返回的响应头中包含了
- 遇 跨域资源共享
GET
参数通过URL
传递,POST
放在Request Body
中- 参数数据类型不一致,
GET
请求只接受ASCII
字符,POST
没有限制
vue和react的区别
- 核心思想不同
- diff算法不同
- 响应式原理不同
vue
使用Object.defineProperty
和Proxy
react
使用setState
- ...
- 学习曲线不同
- ...
const和readonly的区别
const
用于声明一个常量对象,const
必须在声明时候立即初始化, 该对象一旦赋值后就不能再被赋值, 如果对象是一个具有属性的对象, 其属性是可以修改的.readonly
用于声明或者修饰一个对象设置为只读, 包含其属性也不能进行修改, 可以理解为Object.freeze()
什么是跨域、如何解决跨域
- 跨域(Cross-Origin-Resource-Sharing,
CORS
) 是浏览器出于安全策略限制了,一个域(协议、域名、端口)下的网页无法直接访问另一个域下的资源. - 解决跨域
JSONP(仅限GET请求)
:JSONP利用<script>标签可以跨域加载资源的特性,通过在服务器端返回一个包含回调函数的JSON字符串,客户端通过这个回调函数处理数据CORS(Cross-Origin Resource Sharing)
:服务器需要设置Access-Control-Allow-Origin
、Access-Control-Allow-Methods
等响应头,允许特定的源进行跨域请求代理服务器
:在服务器端设置一个代理,将请求转发到目标服务器,然后返回结果。这样,浏览器认为请求和响应都是来自同一源,从而绕过同源策略。PostMessage
:HTML5引入的window.postMessage
方法允许不同源的页面之间安全地传递消息。通过这个API,页面可以发送消息给另一个窗口或iframe,只要它们在同一文档下Document.domain
:当两个页面属于同一个主域(主域相同,子域不同)时,可以通过设置document.domain
为相同的主域来实现跨域通信WebSocket
:WebSocket
协议允许在浏览器和服务器之间建立全双工通信,它不受同源策略的限制,可以用于实现跨域通信使用第三方服务
:如CORS Anywhere、Apigee等,这些服务可以作为中间代理,帮助处理跨域请求Nginx反向代理
:在Nginx服务器配置中设置反向代理,可以将请求转发到目标服务器,并在响应头中添加Access-Control-Allow-Origin
等CORS相关的头信息
什么是cookie?如何设置cookie (客户端)
cookie
是一种存储在用户浏览器本地的小型文本文件。当用户访问网站时候,服务端可以创建一个cookie
将其发送到用户的浏览器。浏览器随后会将这个cookie
保存到本地,并在后续访每次向服务器发送请求的时候自动携带这个cookie
cookie
的大小通常有限制(例如单个cookie
大小通常不超过4KB),而且每次HTTP
请求都会携带cookie
从而影响性能。- 由于
cookie
是存储在客户端,所以它可能存在安全风险,因为用户可以查看和修改cookie
内容。
- 示例
nest.js
// 使用 cookie-parser 插件 npm i cookie-parser npm i -D @types/cookie-parser // 注册插件 省略其他引入 import * as cookieParser from 'cookie-parser'; async function bootstrap () { const app = await NestFactory.create(AppModule, { cors: true, }); app.use(cookieParser()); } bootstrap() // 使用 import { Controller, Get, Req, Res } from '@nestjs/common'; import { Response, Request } from 'express'; @Controller() export class AppController { @Get('set/cookie') setCookie(@Res() res: Response) { res.cookie('cookieName', 'cookieValue', { maxAge: 1000 * 60 * 10, // 10分钟 httpOnly: true, // 只有服务器可以访问Cookie signed: true, // 签名Cookie,提高安全性 }) res.send('cookie set success') } @Get('get/cookie') getCookie (@Req() req: Request) { const cookie = req.cookies['cookieName'] } }
什么是 session(服务端)
session
是一种服务端机制,用于存储和管理用户的会话信息。每个用户都拥有一个唯一的session ID
session
比cookie
存储更多数据且没有明确大小限制。常用于存储用户的身份验证信息、购物车、用户设置等session
比cookie
更安全,因为session
数据存储在服务端,用户无法直接修改或者访问- 示例
nest.js
// 安装依赖 npm install express-session @types/express-session --save // 配置Session中间件 import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import * as session from 'express-session'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 配置Session中间件 app.use( session({ secret: 'your-secret-key', // 用于加密Session ID resave: false, saveUninitialized: true, cookie: { secure: true }, // 如果你使用HTTPS }), ); await app.listen(3000); } bootstrap(); // 使用 import { Controller, Get, Post, UseGuards, Request, Session } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { Session } from 'express-session'; @Controller() export class AppController { constructor() {} @Get('session') async getSession(@Session() session: Session) { console.log(session); // 获取Session数据 return 'Session data'; } @Post('login') @UseGuards(AuthGuard('local')) async login(@Request() req) { // 在用户登录后,你可以将用户信息存储到Session中 req.session.user = { id: 1, username: 'johndoe', }; return 'User logged in'; } }
浏览器事件循环和node.js的事件循环的区别
执行环境的区别
- 浏览器事件循环运行在浏览器中的JavaScript引擎中, 主要处理DOM操作, 用户交互, 网络请求等
- node.js运行在node.js环境中, 处理文件系统操作, 网络通信, 进程控制等
事件循环的阶段
- 浏览器事件循环通常包括宏任务(如script执行、setTimeOut、setInterval、requestAnimationFrame、UI事件处理等), 微任务(如Promise.then、MutationObserver), 调用栈执行
- node.js事件循环由
libuv
库实现, 包括多个阶段, 如 timer、I/O、callbacks、idle、prepare、poll、check、close callbacks等
宏任务与微任务的处理
:- 浏览器在每个宏任务执行完毕后,会立即执行当前微任务队列中的所有微任务
- _(:з」∠)_ 这里不是指宏任务的队列的优先级高于微任务队列优先执行
- 在某些版本中,微任务的处理可能与浏览器有所不同。例如,在Node.js v11及以上版本中,微任务的执行顺序与浏览器相似;而在Node.js v10及以下版本中,微任务的执行可能受到宏任务执行的影响。
- 浏览器在每个宏任务执行完毕后,会立即执行当前微任务队列中的所有微任务
I/O操作
- 浏览器的事件循环通常不会直接处理I/O操作, 而是通过委托给浏览器底层系统
- node.js的事件循环直接处理I/O操作, 如文件读写, 网络请求等
性能和优化
- 浏览器事件循环需要考虑渲染性能, 可能会在某些情况下限制事件循环执行, 以避免阻塞UI渲染
- node.js事件循环更注重I/O密集型任务性能, 通常I/O操作等待期间会进行其他任务处理
平台差异
- 浏览器的事件循环需要在不同的浏览器和操作系统上保持一致
- node.js的事件循环依赖底层的libuv库, 使得node.js在不同操作系统上实现类似异步I/O处理
在浏览器地址输入URL按下回车之后发生了什么
URL解析
- 浏览器首先会检查输入的URL是否有效, 如果URL格式正确, 浏览器会解析URL, 提取协议(http/https)、域名、端口(如果有)和路径
检查缓存
- 浏览器会检查本地缓存(http缓存、dns缓存)看是否有当前URL的缓存数据。如果有缓存同时缓存的数据比较新,浏览器会可能会直接使用缓存,跳过后续步骤
DNS解析
- 如果浏览器没有缓存或者缓存的数据比较老, 浏览器会进行DNS(Domain Name System)解析,将域名转换成服务器的IP地址。这个过程可能涉及多个DNS服务器,包括本地DNS缓存、根DNS域名服务器等
建立TCP连接
- 一旦有了服务器的IP地址, 浏览器会尝试与服务器通过TCP建立连接。这个过程通常涉及三次握手(SYN、SYN-ACK、ACK)
发送HTTP请求
- TCP连接建立后, 浏览器会构造一个HTTP请求(GET请求), 包括请求头和请求体(如果有), 并发送给服务器
服务器处理请求
- 服务器接收到请求后, 会根据请求的URL和参数处理请求。这可能会包括数据库的查询、执行服务器端的脚本等等
服务器响应
- 服务器处理完成后, 会返回一个HTTP响应给浏览器, 包括状态码、响应头和响应体(包含网页内容)
处理响应
- 浏览器接收到服务器的响应后, 会根据响应头中的信息(如Content-Type)处理响应体。如果是HTML文档, 浏览器则会开始解析HTML, 构建
DOM树
- 浏览器接收到服务器的响应后, 会根据响应头中的信息(如Content-Type)处理响应体。如果是HTML文档, 浏览器则会开始解析HTML, 构建
渲染页面
- 在解析HTML同时, 浏览器会下载并解析
CSS
和JavaScript
文件。JavaScript
可能会修改DOM树
, 执行动画等等。CSS
用于计算样式, 构建CSSOM
树。然后浏览器会将DOM树
和CSSOM树
合成并生成渲染树
, 进行布局(回流)
和绘制(重绘)
, 最终显示在屏幕上DOM树
构建完成会触发 -DOMContentLoadeds
事件
- 在解析HTML同时, 浏览器会下载并解析
资源加载
- 页面中的图片、视频资源也会被加载。如果资源需要, 浏览器可能会并行加载这些资源, 以提高加载速度.
Chrome
资源并行数量限制为6
个,why?
操作系统端口资源的考虑
: 在TCP/IP协议中, 每个TCP都需要占用一个端口线程切换开销
: 过多的并发请求会导致频繁的线程切换, 会产生额外的开销客户端良知机制
: 防止客户端无限制地发起请求, 从而导致服务端资源被过度占用避免服务端并发阈值
: 服务端通常也会设置并发请求的阈值, 以防止恶意攻击或者过度请求HTTP/1.1的Keep-Alive特性
: HTTP/1.1支持Keep-Alive, 允许一个TCP连接上发送多个HTTP请求, 这样可以减少建立连接和关闭连接的开销, 同时限制并发数量从而更有效的利用该特性来提高资源加载效率
- 页面中的图片、视频资源也会被加载。如果资源需要, 浏览器可能会并行加载这些资源, 以提高加载速度.
页面交互
- 用户开始与页面交互, 点击链接, 表单提交等等, 这些操作都会触发新的
HTTP
请求
- 用户开始与页面交互, 点击链接, 表单提交等等, 这些操作都会触发新的
断开连接
- 当页面被使用完成, 用户关闭页面时候, 浏览器会关闭也服务器的
TCP
连接
- 当页面被使用完成, 用户关闭页面时候, 浏览器会关闭也服务器的
尾巴
这仅仅作为个人面试记录与复盘, 对看见的人如果有所帮助, 那自然是更好的了, 如果有错误欢迎指正.
本篇内容均靠个人知识见解和互联网内容检索编写而成.
_(:з」∠)_