快手海外部门面试

229 阅读35分钟

整个面试过程比较顺利吧,三面面试官说了一句,如果hr给你发offer,希望你能来(没记错的话,是说过这一句话的)。但最后问结果的时候,hr说面试官觉得和职位不是很匹配(没过),问具体原因,说不方便透露。
关于简历也是奇奇怪怪,开始约我面试的时候,我以为是朋友内推的,到3面前,hr问我能不能发个最新的简历给她,她没有我最新的简历,说我的简历是她们从人才库里面捞出来的。

以下内容,主要是面试官问我的;标记为扩展的是我总结的扩展,并不是面试官追问的内容;

正文大概有1w字,如果觉得太多,可以看看题目。

一面

自我介绍

最有挑战的项目

小程序怎么性能优化

这个是我简历中有写,所以面试的时候被问。

前端角度怎么做优化

babel是怎么运作的, 以及的配置

Babel 是一个广泛用于 JavaScript 代码转译(transpilation)的工具。它的主要功能是将高版本的 JavaScript 代码(如 ES6/ES2015+)转译为向后兼容的低版本 JavaScript 代码,以便在现有的环境中运行。

babel作用

  1. 将高版本 JavaScript 转译为低版本 JavaScript;Babel 可以将新的 JavaScript 语法和特性(如箭头函数、解构赋值、模板字符串等)转译为旧版本的 JavaScript 代码,使得它们能在不支持这些特性的环境中运行。
  2. 转译 JSX :Babel 也可以将 JSX 语法转译为普通的 JavaScript 代码,以便在浏览器环境中运行。
  3. 插件系统 Babel 支持使用插件来扩展其功能,可以通过添加不同的插件来支持特定的语法、功能或者自定义转译规则。
  4. 支持多种环境: Babel 可以在不同的环境中使用,包括浏览器、Node.js、React Native 等。 4.提升开发效率:Babel 可以帮助开发者在编写代码时使用最新的语言特性,而不用担心它们在旧版浏览器或环境中的兼容性问题。

如何配置 Babel

  1. 创建 .babelrc 文件:在项目的根目录下创建一个名为 .babelrc 的文件。
  2. 配置文件内容:如果你的项目是基于 JSON 文件的,.babelrc 文件的内容如下:
{ "presets": ["@babel/preset-env"], "plugins": ["@babel/plugin-transform-runtime"] }

如果你的项目使用 JavaScript 文件作为配置,可以创建一个名为 babel.config.js 的文件,内容如下:

module.exports = {
    presets: ['@babel/preset-env'],
    plugins: ['@babel/plugin-transform-runtime']
};

在这个示例中,我们配置了两个 Babel 的预设(presets)和一个插件(plugin):

  • @babel/preset-env
  • @babel/plugin-transform-runtime

安装相应的 Babel 插件:在配置文件中使用了 @babel/preset-env 和 @babel/plugin-transform-runtime,所以需要确保这些插件已经安装在项目中:

npm install @babel/preset-env @babel/plugin-transform-runtime --save-dev

运行 Babel:在项目中运行 Babel,可以使用命令行工具或者配置构建工具(如 Webpack)来自动进行转译。

如果使用命令行工具,可以安装全局的 Babel CLI:

npm install -g @babel/cli

然后可以使用以下命令运行 Babel:

babel src -d lib

扩展:Babel 的运行步骤:

  1. 解析(Parsing):

Babel 首先会将源代码解析成抽象语法树(Abstract Syntax Tree,AST)。AST 是一个描述代码结构的树状数据结构,它将代码中的每个元素(如变量、函数、操作符等)表示为一个节点,节点之间通过父子关系连接。

  1. 转译(Transformation)

Babel 会对 AST 进行遍历,对其中的节点进行修改、添加或删除,从而实现对源代码的转译。这个阶段包括了将新的语法特性转译为旧版本的 JavaScript 代码,以及应用一些插件的转译规则。

  1. 生成(Code Generation)

经过转译后的 AST 会被重新转换为代码字符串,形成一个新的 JavaScript 源代码。

  1. 输出(Output)

生成的新代码会被输出到指定的位置,可以是文件系统中的一个文件,也可以是内存中的一个字符串。

Babel如何将源代码解析为AST

Babel 使用了一个名为 @babel/parser 的独立解析器,它是 Babel 的解析器模块,负责将源代码解析成抽象语法树(AST)。

以下是 Babel 将源代码解析成 AST 的基本步骤:

  1. 词法分析(Lexical Analysis):

首先,Babel 的解析器会将源代码分割成一个个的词法单元(Tokens)。词法单元是代码中的一个个小片段,比如变量名、关键字、运算符等。这个过程称为词法分析。

  1. 语法分析(Syntax Analysis):

接下来,解析器会根据词法单元的组合规则,将它们转化为一个个的语法节点,这些节点之间形成了一颗树状的结构,即抽象语法树(AST)。这个过程称为语法分析。例如,对于代码 const x = 10;,解析器会生成一个 AST,其中包含一个变量声明节点,节点中包含一个变量名节点 x 和一个字面量节点 10。

  1. AST 的生成和遍历:
  • 生成的 AST 是一个嵌套的对象结构,每个节点代表了代码中的一个语法元素,比如变量声明、函数定义、表达式等。
  • Babel 可以对生成的 AST 进行遍历,从而实现对源代码的转译、修改等操作

有没有用过jsbridge

JSBridge(JavaScript Bridge)是指在原生应用(如iOS或Android应用)的WebView组件中,通过JavaScript代码调用原生代码的一种技术。它允许前端开发者在Web页面中通过JavaScript调用设备的原生功能,如获取设备信息、调用相机、发送短信等。

具体来说,JSBridge 实际上是一个桥接器,它提供了一组接口,使得JavaScript可以与原生代码进行通信。

在iOS和Android平台上,通常会分别使用不同的JSBridge实现:

  • iOS:iOS平台上常用的JSBridge包括WebViewJavascriptBridge、WKWebViewJavascriptBridge等。
  • Android:Android平台上常用的JSBridge包括WebViewJavascriptBridge、JSBridge等。

使用JSBridge可以实现以下功能:

  1. 调用原生功能:前端可以通过JSBridge调用设备的原生功能,如相机、地理位置、通讯录等。
  2. 获取设备信息:前端可以通过JSBridge获取设备的信息,如设备型号、操作系统版本等。
  3. 进行页面跳转:前端可以通过JSBridge请求原生应用进行页面跳转。
  4. 与原生进行数据交互:前端可以通过JSBridge与原生应用进行数据交互,实现前后端的数据传递。

总的来说,JSBridge是一种强大的技术工具,它使得前端开发者可以在WebView中与原生应用进行无缝交互,从而实现更丰富、更灵活的应用功能。

https2了解多少

http2

HTTP/2(又称为HTTP2)是HTTP协议的一个重大更新版本,旨在提升网站性能和用户体验。它是HTTP/1.1的后续版本,于2015年发布,通过引入新的特性和优化,以加速页面加载速度、提升性能。

以下是HTTP/2的一些重要特性:

  1. 多路复用(Multiplexing):支持在单个连接上同时发送多个请求和响应,解决了HTTP/1.1中的队头堵塞问题。这样,可以更高效地利用网络连接,提升页面加载速度。
  2. 二进制传输(Binary Format):使用二进制格式传输数据,而不是HTTP/1.1的文本格式。这使得数据的解析更高效,减少了解析的复杂性。
  3. 头部压缩(Header Compression):使用HPACK算法对头部信息进行压缩,减少了传输的数据量。这对于那些有大量小文件或者频繁请求的网站来说特别有用。
  4. 优先级(Prioritization):允许客户端指定请求的优先级,使得浏览器可以更加智能地处理哪些请求先发送。
  5. 流(Stream):在单个连接上可以同时存在多个流,每个流代表一个虚拟的通道。多个流可以并行地发送和接收数据。
  6. 服务器端推送(Server Push): 允许服务器在客户端请求之前,主动推送相应的资源,从而减少了额外的请求时间。
  7. 安全性:对于安全连接(使用TLS/SSL加密)的支持是强制的,这也增强了网络安全。

扩展:HTTP/3

HTTP/3 是互联网工程任务组(IETF)制定的下一代超文本传输协议,旨在提升网络性能和安全性。相对于之前的HTTP/2,HTTP/3 带来了一些重要的改进,其中最显著的是采用了基于UDP的传输层协议——QUIC(Quick UDP Internet Connections)。

以下是关于HTTP/3的一些关键特点和改进:

  1. 基于QUIC:HTTP/3 使用 QUIC 作为其传输层协议,而不是传统的TCP。QUIC 结合了传输层和网络层的功能,可以更快地建立新连接,也可以在网络切换时更快地恢复连接。。
  2. 0-RTT 握手:在建立连接时发送数据(称为0-RTT数据),这使得客户端可以在连接建立时发送请求,从而进一步降低了响应时间。
  3. 拥塞控制和流量控制: 内置了拥塞控制和流量控制机制,以确保在网络拥塞的情况下保持稳定的传输。
  4. 减少头部压缩成本: 采用了 QPACK 头部压缩方案,相对于 HTTP/2 中的 HPACK,它减少了头部压缩的计算成本。
  5. 更好的性能:由于QUIC协议的特性以及一些其他优化,HTTP/3 可以提供比 HTTP/2 更低的延迟和更高的性能。
  6. 安全性: 使用了现代加密算法,并且基于 QUIC 的传输层协议提供了更高级别的安全保障。

总的来说,HTTP/3 旨在改善网络性能和安全性,使得网页加载速度更快,特别是在高延迟和丢包的网络环境下。然而,需要注意的是,目前(截至我所知,截至 2021 年 9 月)HTTP/3 还在逐步推广和实施中,并未完全普及,因此支持程度可能会因浏览器、服务器和网络环境而异。

扩展:HPACK

HPACK(HTTP/2的头部压缩算法)是一种用于在HTTP/2通信中减少传输开销的压缩算法。它允许客户端和服务器在头部信息中使用索引和字面值的组合来减小数据传输的大小。

以下是HPACK算法的主要原则:

  1. 动态表和静态表:HPACK 使用了两个表格来存储头部信息。一个是静态表,包含了一些常见的头部字段和值,另一个是动态表,用于存储最近的头部信息。
  2. 索引引用: 使用索引来引用静态表和动态表中的头部信息。静态表的索引从1开始,动态表的索引从静态表之后的第一个位置开始。
  3. 字面值和索引组合:每个头部字段都可以用索引引用或字面值表示。索引引用会指向静态表或动态表中相应位置的头部信息,而字面值直接表示头部字段名和值。
  4. 头部信息的更新和清理:动态表的大小是有限制的,当需要添加新的头部信息时,可能会需要清理旧的信息以腾出空间。
  5. 动态表的动态调整:动态表的大小可以在连接过程中动态调整,以适应不同的网络环境和需求。
  6. 处理顺序:在解码的时候,头部信息的顺序保持与编码时相同,确保了头部的原始顺序性。

http加密知道多少

HTTP加密是指通过对HTTP通信进行加密,以保护数据在传输过程中不被窃听或篡改的一种安全措施。这种加密方式通常采用TLS/SSL协议来实现。

以下是HTTP加密的基本原理:

  1. TLS/SSL协议: HTTP加密主要依赖于传输层安全协议(Transport Layer Security / Secure Sockets Layer,TLS/SSL)。TLS/SSL协议提供了一种在通信过程中对数据进行加密和验证的机制。
  2. 握手阶段:在建立连接之初,客户端和服务器之间会进行一个握手阶段,这个过程中会协商加密算法、密钥等信息。
  3. 证书验证:服务器通常会向客户端提供一个数字证书,证明了服务器的身份。客户端会验证证书的有效性,以确保正在连接到正确的服务器。
  4. 数据加密传输:一旦握手完成并且密钥被协商,之后的通信将使用这个密钥进行加密和解密,从而保护数据的安全性。

浏览器输入url后发生什么

当你在浏览器中输入一个URL并按下回车后,会触发以下一系列步骤:

  1. URL解析:浏览器首先会对输入的URL进行解析,判断其协议(如http、https)、域名、路径等信息。
  2. DNS解析:如果输入的URL包含了域名(如www.example.com),浏览器会向DNS服务器发起一个请求,以获取对应的IP地址。如果之前已经缓存了该域名的IP地址,浏览器会直接使用缓存的值。
  3. 建立TCP连接:浏览器会通过域名解析得到服务器的IP地址后,会尝试与服务器建立TCP连接。这个过程包括三次握手,确保双方都能够正常通信。
  4. 发起HTTP请求:一旦TCP连接建立,浏览器就会使用HTTP协议向服务器发送请求。这个请求包括了请求方法(GET、POST等)、请求头、请求体等信息。
  5. 服务器处理请求:服务器接收到浏览器发送的请求后,会根据请求的内容进行相应的处理,可能是查找并返回对应的网页文件,或者执行相应的后台操作。
  6. 服务器返回响应:服务器将处理结果封装成HTTP响应,包括状态码、响应头和响应体。响应体通常包括了请求的内容,如HTML页面、图片等。
  7. 浏览器接收响应:浏览器接收到来自服务器的HTTP响应后,会根据响应头的信息进行相应的处理,包括解析HTML、渲染页面、下载并显示资源等。
  8. 渲染页面:浏览器会根据HTML文档中的结构和样式信息,渲染出页面的样式和内容,显示在用户界面上。
  9. 关闭TCP连接:一旦页面渲染完成,浏览器会关闭与服务器之间的TCP连接,释放资源

详细说下render树的构建

渲染树(Render Tree)是浏览器用于渲染网页的一种内部数据结构,它包含了网页中需要被渲染的可见元素,通常是文档对象模型(DOM)的一部分。渲染树的构建过程是浏览器渲染引擎的核心部分,以下是构建渲染树的基本步骤:

  1. DOM树构建:首先,浏览器会解析HTML文档并构建DOM树。DOM树表示了HTML文档的层次结构,包括HTML元素、属性、文本内容等。
  2. 样式计算:一旦DOM树构建完成,浏览器开始计算每个元素的样式信息,这包括了CSS解析和样式计算。浏览器会确定每个元素最终应用的样式,包括颜色、字体、大小、位置等。
  3. 生成渲染树:
  • 接下来,浏览器将DOM树和样式信息结合起来,生成渲染树。渲染树只包含需要被渲染的可见元素,通常是指那些具有视觉效果的元素,如文本、图像、表单元素等。
  • 渲染树不包括那些不可见的元素,如<head><meata>,display:nonde
  • 渲染树的节点结构与DOM树类似,但是它包含了每个节点的计算样式信息,以及布局信息(如位置、大小等)。\

扩展:DOM树是如何构建的

构建DOM树(Document Object Model Tree)是浏览器渲染引擎的核心任务之一,它表示网页的结构和层次关系,包括HTML文档中的元素、属性和文本内容。构建DOM树的过程通常分为以下步骤:

  1. 解析HTML: 当浏览器加载一个网页时,首先需要将HTML文档解析为一系列标记(tokens)和节点(nodes)。

  2. 词法分析(Lexical Analysis):解析器会将HTML文档划分为一系列词法单元,这些词法单元包括标签、属性名、属性值、文本内容等。

  3. 语法分析(Syntax Analysis):解析器会根据HTML的语法规则,将词法单元组合成DOM节点。这个过程包括了建立元素之间的父子关系,形成DOM树的结构。

  4. 构建DOM树:

  • 解析器会从解析得到的标记和节点开始构建DOM树。根节点通常是HTML元素(标签),然后是和等子节点。
  • 根据HTML的结构,解析器会不断构建DOM树,包括创建元素节点、属性节点、文本节点等。
  • 解析器会根据元素的嵌套关系将节点连接成树状结构,形成完整的DOM树。

宏任务和微任务的区别

两个盒子的间距是多少

距离

<div class="box1">
</div> <div class="box2"></div> 
.box1 { margin-bottom: 10px }
.box1 { margin-top: 20px }

如何解决margin塌陷

  1. 使用Padding: 将外边距应用到元素的内边距(padding)而不是外边距,这样可以避免 Margin 塌陷。但请注意,这不适用于所有情况,因为内边距和外边距的作用是不同的。
  2. 使用Border或Outline: 给一个元素添加边框(border)或轮廓(outline)也可以阻止 Margin 塌陷,因为这些属性会创建一个视觉分隔线,防止外边距重叠。
  3. 使用浮动或定位: 使用浮动(float)或绝对定位(position: absolute)可以阻止 Margin 塌陷,但这通常需要更多的CSS来实现所需的布局。
  4. 使用overflow: hidden 将容器元素的 overflow 属性设置为 hidden 也可以阻止 Margin 塌陷,但要小心,因为这可能会隐藏内容溢出容器的部分。
  5. 使用display: inline-block 将元素的 display 属性设置为 inline-block 可以改变元素的布局上下文,通常也会影响 Margin 塌陷。
  6. 使用Flexbox或Grid布局: 使用Flexbox或Grid布局可以更精确地控制元素的布局,通常不容易发生Margin 塌陷。
  7. 设置父容器的border或padding: 为包含有 Margin 塌陷的元素的父容器添加边框或内边距可以分隔外边距,从而防止 Margin 塌陷。

什么是BFC

BFC

BFC 指的是 "块级格式化上下文"(Block Formatting Context)。

它是 CSS 布局的一个重要概念,用于决定块级盒子如何放置在页面上以及相互之间的关系和影响。BFC 是一个独立的渲染区域,其中的元素布局是相互隔离的,这意味着在一个 BFC 中的盒子不会影响到外部的布局。

BFC 的主要特性包括:

  1. 内部的盒子会在垂直方向上一个接一个地放置。
  2. 内部的盒子会在水平方向上尽可能地填满容器。
  3. BFC 区域的边缘与外部的容器元素相隔。
  4. 计算 BFC 的高度时,浮动元素也会参与计算。
  5. 可以通过设置元素的

overflow 属性为 auto 或 hidden 触发 BFC。

BFC 在实际中有许多应用,比如用于清除浮动、防止外边距合并等。

举个例子,当你给一个元素设置 float: left;,它会生成一个 BFC,这样可以防止它对其他元素的布局产生影响。

总的来说,BFC 是一个非常有用的概念,可以帮助开发者更精确地控制布局,解决一些常见的布局问题。

扩展:IFC

IFC(Inline Formatting Context)是CSS中的一种布局模型,用于定义块级元素内部的内联元素的布局规则。

在IFC中,内联元素会根据一定的规则依次排列,形成一个水平的线框,类似于一行文字。IFC中的元素会在主轴(水平方向)上依次排列,当元素超过一行的宽度时会自动换行。

IFC 的特点包括:

  1. 水平排列:IFC中的元素在主轴方向上水平排列,从左往右。
  2. 垂直对齐:可以通过垂直对齐的方式将元素在交叉轴(垂直方向)上进行对齐。
  3. 自动换行:当一行的宽度不足以容纳所有元素时,元素会自动换行到下一行。

IFC的一些常见应用场景包括:

  • 文字排版:在段落中,文字会形成一个IFC,依次排列在一行中,当宽度不足时会自动换行。
  • 行内块元素:一些内联块元素(例如、<span> <a>等)会在IFC中排列,可以通过CSS属性来控制它们的排列方式.
  • 表单元素:表单元素中的内联元素(例如输入框、按钮等)也会在IFC中排列。

下面代码的输出

我简历上面是没有说会node的,这个题中的process是node中的api,面试官让我根据自己理解做。

setTimeout(() => {
    console.log('setTimeout')
}, 0);
new Promise((resolve) => {
    console.log('init Promise');
    process.nextTick(resolve)
}).then(() => {
    console.log('then');
});
process.nextTick(() => {
    console.log('nexttick');
});
setImmediate(() => {
    console.log('setImmediate')
})
// init Promise
// nexttick
// then
// setTimeout
// setImmediate

把数组转换为tree结构

function transformArrToTree(arr) {
    // 便于查找
    const map = arr.reduce((pre, cur) => {
        pre.add(cur.id, cur); return pre;
    }, new Map()); const res = [];
    arr.forEach((item) => {
        onst pid = item.pid;
        const parentInfo = map.get(pid);
        if(parentInfo) {
            parentInfo.children = (parent.children || []).concat(item);
        } else {
            res.push(item);
        }
    });
    return res;
}

实现一个EventEmit

class EventEmit{
    constructor() {
        this.eventMap = new Map();
    }
    on(key, callback) {
        const callbacks = (this.eventMap.get(key) || new Set()).concat(callback); 
        this.eventMap.set(key, callbacks);
    }
    off(key, callback) {
        if(callback) {
            const callbacks = this.eventMap.get(key) || new Set(); 
            callbacks.delete(callback); this.eventMap.set(key, callbacks);
        } else { this.eventMap.delete(key);
        }
    }
    emit(key) {
        const callbacks = this.eventMap.get(key) || new Set(); 
        callbacks.forEach(callback => { callback(); })
    }
    once(key, callback) {
        const fn = () => { callback(); this.off(key, fn); }
        this.on(key, fn);
    }
}

用过哪些hook,简单说下内部实现原理

面试的时候,回答的useMemo的原理(源码时怎么实现的)

createContext的原理

  1. 创建上下文对象:
  • 调用 createContext 函数会返回一个具有 Provider 和 Consumer 属性的对象。
  • Provider组件用于提供上下文数据,Consumer 组件用于订阅上下文数据。
  1. Provider 的工作原理:
  • 当使用 Provider 组件将上下文数据提供给整个组件树时,它实际上会创建了一个新的 React 元素,并在元素的 props 中包含了提供的数据。
  • 这个 React 元素会被插入到组件树中,从而使得整个子树都能够访问到上下文数据。
  • Provider 组件会在渲染过程中通过 React 的上下文机制将数据传递给子组件。
  1. Consumer的工作原理:
  • Consumer组件可以在其子组件中使用,用于订阅上下文数据。
  • 当 Consumer 组件被渲染时,它会调用一个函数作为子组件,并将当前上下文的值作为参数传递给该函数。
  • 这样,你可以在函数中使用上下文的值来进行相应的操作。
  1. 默认值(Optional):
  • 可以在创建上下文时传递一个默认值作为参数,当在组件树中没有找到匹配的 Provider 时,会使用这个默认值。
  • 这个默认值可以在 Consumer 组件中作为参数传递给渲染函数。

用过哪些单位

基本单位

px、vw、vh、rem、em

计算下html上应该设置的字体大小为多少vw

手机屏幕宽1920px,若要1rem = 100px,则html上font-size=?? vw 答案:100/19.2

二面

自我介绍

怎么做小程序性能优化的

怎么做稳定性保障

代码质量保障: eslint,ts检查,人工CR 单元测试: 前置开发问题

前端稳定性保障是保证Web应用在各种环境下正常运行和用户体验良好的重要工作。以下是一些前端稳定性保障的方法和策略:

  1. 代码质量保证:
  • 编写清晰、可维护的代码,遵循编码规范和最佳实践,提高代码的可读性和稳定性。
  • 使用静态代码分析工具(如ESLint)进行代码质量检查,及时发现和修复潜在问题。
  1. 单元测试和集成测试:
  • 使用单元测试框架(如Jest、Mocha等)编写针对组件和功能的单元测试,保证各个单元模块的功能正确性。
  • 进行集成测试,确保各个组件之间的协作和整体功能的稳定性。
  1. 自动化测试:
  • 使用自动化测试工具(如Selenium、Cypress等)进行端到端的功能测试,模拟用户行为,确保应用在各种浏览器和设备上正常运行。
  1. 异常监控:
  • 集成异常监控工具(如Sentry、Bugsnag等),实时收集并分析前端错误,及时发现并修复bug。
  1. 日志监控:
  • 记录用户行为、关键操作和异常信息,通过日志分析工具(如ELK Stack、Splunk等)进行实时监控和分析,及时发现潜在问题。
  1. 版本控制和发布流程:
  • 使用版本控制工具(如Git)进行代码管理,实施代码分支管理策略,确保稳定版本的发布。
  • 使用自动化部署工具(如CI/CD流水线)进行持续集成和持续部署,确保每次发布的代码都经过了测试。
  1. 容灾和备份:
  • 设计容灾方案,确保在服务器故障或网络故障时能够快速恢复。
  • 定期进行数据备份,以防止数据丢失或损坏。
  1. 安全防护:
  • 防止常见的安全问题,如XSS攻击、CSRF攻击等,采取合适的安全措施保护用户数据和系统安全。
  1. 持续优化和监控:
  • 定期评估和优化应用性能,更新技术栈,保持前端代码的健康和稳定。
  • 持续监控用户反馈和应用的运行情况,及时做出调整和优化。

SVG和cavas适用场景

SVG(可缩放矢量图形)和 Canvas 是两种用于在Web上绘制图形的技术,它们各自有不同的适用场景和特点。

SVG:

  1. 矢量图形:SVG是基于矢量的图形格式,使用XML来描述图形。它可以无损地缩放,不会失真,适合绘制图标、图表等需要保持清晰度的图形。
  2. DOM元素:SVG元素是真实的DOM元素,可以像HTML元素一样使用CSS样式和JavaScript来控制。
  3. 事件处理:SVG可以通过事件监听器来实现交互,可以绑定点击、鼠标移动等事件。
  4. 图形编辑:SVG图形可以在浏览器中进行编辑,可以通过CSS或JavaScript实现动态效果。
  5. 复杂图形:适合绘制复杂、详细的图形,如地图、复杂的图表等。

Canvas:

  1. 位图绘制:Canvas提供了一个2D绘图上下文,可以通过JavaScript绘制位图图像,适合处理像素级别的绘制。
  2. 像素处理:可以通过Canvas对像素进行处理,包括图像的像素操作、滤镜、颜色调整等。
  3. 动画:Canvas适合用于实现复杂的动画,可以在每一帧中更新像素,实现高性能的动画效果。
  4. 游戏开发:Canvas在游戏开发中应用广泛,可以绘制游戏场景、精灵等。
  5. 实时绘制:适合需要实时绘制的场景,如实时图表、实时数据可视化等。
  • 使用SVG适合需要保持图形清晰度、交互性高、图形编辑性强的场景。
  • 使用Canvas适合需要绘制大量像素、实时绘制、动画效果丰富的场景,特别是游戏开发和实时数据可视化等应用。

webpack的plugin和loader的区别,常见的plugin和loader

我简历里面没有写webpack相关的,但是多场面试带来,发现面试官都喜欢问这个问题。

Webpack 是一个模块打包工具,它能够将项目中的各种资源(如JS、CSS、图片等)打包成一个或多个静态文件。

Loader:

Loader 用于对模块的源代码进行转换,可以将非 JavaScript 文件转换为 Webpack 可以处理的模块。每个 Loader 可以看作是一个转换器,负责把某种文件格式的内容转换成 Webpack 可以使用的模块。

常见的 Loader 有:

  1. babel-loader:用于将 ES6/ES7/ES8 等新版本的 JavaScript 代码转换成当前浏览器可以执行的代码。
  2. css-loader:用于加载和解析 CSS 文件,支持模块化、压缩等功能。
  3. style-loader:将 CSS 代码注入到 JavaScript 中,使得 CSS 生效。
  4. file-loader和 url-loader:用于处理图片、字体等文件,可以将小文件转换成 base64 编码,减少 HTTP 请求。
  5. sass-loader和 less-loader:用于将 SCSS 或 LESS 文件转换成 CSS。

Plugin:

Plugin 用于扩展 Webpack 的功能,在整个构建过程中,它可以监听事件,执行自定义任务,改变构建结果。

常见的 Plugin 有:

  1. HtmlWebpackPlugin:生成一个 HTML 文件,并将打包后的资源自动引入到 HTML 中。
  2. CleanWebpackPlugin:在每次构建前清理输出目录。
  3. MiniCssExtractPlugin:用于将 CSS 提取到单独的文件中,而不是将其嵌入到 JavaScript 文件中。
  4. DefinePlugin:用于在编译时创建全局变量。
  5. HotModuleReplacementPlugin:启用模块热替换(HMR)功能,允许在运行时更新各种模块,而无需完全刷新页面。
  6. CopyWebpackPlugin:用于复制静态资源文件到输出目录。

总结来说,Loader 主要用于对模块的源代码进行转换,而 Plugin 则可以用于执行更广泛的任务,如打包优化、资源管理、环境变量注入等。在配置文件中,Loader 通常在 module.rules 中配置,而 Plugin 在 plugins 中配置。

通过合理配置 Loader 和 Plugin,可以使 Webpack 更加灵活和强大,适应不同项目的需求。

optimization

在Webpack中,optimization 是一个配置项,它用于对打包结果进行优化和调整,以提升构建速度和输出质量。

optimization 可以包括以下几个常用的配置选项:

  1. minimize:默认为 truer,开启代码压缩。当设置为 ;false 时,将不会对代码进行压缩。
  2. minimizer:用于指定自定义的压缩器。可以配置一些第三方的压缩工具(如TerserWebpackPlugin等)来代替默认的压缩器。
  3. splitChunks:用于将公共代码拆分成独立的文件,以减少重复引用和提升缓存利用率。
  4. runtimeChunk:将webpack运行时代码提取到一个单独的文件,避免在每次构建时都重复打包。
  5. concatenateModules:尝试将模块合并到一个函数中,以减少函数调用的开销。
  6. removeAvailableModules:当它们是公共模块时,会从 chunk 和 assets 中移除模块
  7. removeEmptyChunks:从 chunk 中移除空的模块。
  8. mergeDuplicateChunks:尝试合并具有相同模块的块。
  9. flagIncludedChunks:标记块,以允许其他插件识别并跳过它们。
  10. occurrenceOrder:控制模块的分配,以使 ID 分配得尽可能紧凑,以便实现更好的长期缓存。
  11. sideEffects:标志哪些模块没有副作用,可以安全地进行更多的模块清理。

最有挑战的项目

从输入url到最后展现发生了啥

  1. url获取: 捕获并判断是否是有效url,【浏览器进程-ul线程】
  • 如果是启用网络进程进行DNS分析
  • 否则使用默认配置的搜索引擎来查询
  1. DNS分析:获取到IP地址后,(谷歌浏览器)会通过SafeBrowsing检查站点【浏览器进程-网络线程】
  • 若是恶意站点,则会提示一个警告页,阻止用户访问,当然也可以继续访问
  • 如果不是,则进行TCP三次握手
  1. TCP三次握手: 【浏览器进程-网络进程】

  2. 发送请求:【浏览器进程-网络进程】

  3. 客户端收到请求: 【浏览器进程-ul线程】

  4. 构建DOM树:分析html内容,解析喂多个标记,根据识别标记进行DOM树构建【渲染器进程-主线程】

  • 首先创建document对象,然后以document为根节点不断进行修改,向其中添加各个元素
  1. 构建css规则树

  2. 合并生成render树

  3. layout布局:根据render树,计算出元素大小和位置

  4. 绘制:比那里layout tree常见一个绘制记录表

  5. 分层:遍历layout tree 生成layer tree

  6. 栅格化:按照绘制的顺序,把信息转化成像素点显示在屏幕上【渲染器进程-栅格化线程】

  7. 合成:根据栅格化化后的土块生成一个合成器帧【渲染器进程-合成器线程】、

  8. 渲染:将合成帧发送给GPU进行绘制【浏览器进程-GPU】

算法-计算两个超大数字(字符串)的和

算法-斜线遍历二维数组

三面

自我介绍和个人经历

如何测试虚拟列表的性能

因为经历中说到了虚拟列表,所以被提问了,如何测试其性能

  1. 加载速度测试: 测试虚拟列表加载大量数据时的速度。记录加载时间并确保在大数据集情况下仍能快速加载。
  2. 滚动性能测试: 模拟用户滚动虚拟列表,观察滚动时的流畅度。检查是否有卡顿或延迟。
  3. 内存使用测试: 监测虚拟列表在加载不同数量的项时的内存使用情况。确保内存管理良好,避免内存泄漏。
  4. 搜索和过滤性能测试: 如果虚拟列表支持搜索和过滤功能,测试这些功能的性能。确保搜索和过滤操作快速响应。
  5. 并发性能测试: 测试多个用户同时使用虚拟列表时的性能。模拟多个并发请求并观察系统的响应时间。
  6. 性能优化: 根据性能测试结果,进行必要的性能优化。这可能包括优化渲染算法、使用虚拟化技术、减少不必要的重绘等。
  7. 跨浏览器和设备测试: 确保虚拟列表在不同浏览器和设备上的性能稳定性。
  8. 负载测试: 模拟大量用户或大量数据情况下的性能表现,以确定虚拟列表的极限容量。
  9. 监控和分析工具: 使用性能监控和分析工具来收集详细的性能数据,以便更好地理解性能瓶颈和优化机会。

http的发展

HTTP(Hypertext Transfer Protocol)是用于在互联网上传输超文本的协议。以下是HTTP的发展历史的主要里程碑:

  1. HTTP/0.9:在1991年,Tim Berners-Lee创建了第一个HTTP版本,它只支持GET方法,并且没有头部信息。这个版本是非常简单的,用于在浏览器和Web服务器之间传输HTML文件。
  2. HTTP/1.0:1996年发布,引入了更多的HTTP方法(如POST)和HTTP头部,允许传输不仅仅是HTML,还有多媒体文件等。这一版本还支持状态码,允许服务器和客户端进行更复杂的通信。
  3. HTTP/1.1:于1999年发布,是一个重要的版本,引入了一些性能优化,如持久连接(Keep-Alive)、管道化(Pipelining)和虚拟主机(Virtual Host)。这些改进提高了网站的加载速度和性能。
  4. HTTP/2:2015年发布,旨在进一步提高性能。它引入了多路复用(Multiplexing),允许多个请求和响应在同一连接上同时进行,减少了延迟。还引入了头部压缩(Header Compression)和服务器推送(Server Push)等功能。
  5. HTTP/3:于2020年发布,是最新的HTTP版本。它基于Google开发的QUIC协议,进一步提高了性能和安全性。HTTP/3的主要特点是使用UDP协议而不是TCP,以减少连接建立的延迟,并提供更好的流控制和错误处理。

HTTP3为啥比HTTP2快

  1. 采用QUIC协议:HTTP/3使用QUIC(Quick UDP Internet Connections)协议,而HTTP/2使用TCP协议。QUIC在传输层提供了更好的性能,因为它减少了连接建立的延迟。QUIC使用UDP而不是TCP,允许更快的连接建立,因为它不需要进行握手等复杂的过程。
  2. 多路复用改进:HTTP/3继承了HTTP/2的多路复用功能,但在QUIC的基础上进一步优化。多路复用允许多个请求和响应在同一连接上同时传输,减少了延迟。HTTP/3通过QUIC实现了更有效的多路复用,进一步提高了性能。
  3. 头部压缩改进:HTTP/3采用了更高效的头部压缩算法,以减少数据传输时的带宽占用。这有助于减少延迟和提高性能。
  4. 服务器推送:HTTP/3支持服务器推送功能,允许服务器在客户端请求之前主动将资源推送给客户端。这可以减少客户端等待所需资源的时间,从而提高加载速度。
  5. 连接迁移:QUIC允许连接从一个网络接口无缝迁移到另一个网络接口,而不会中断连接,这对于移动设备等场景非常有用,有助于提供更稳定的连接。

HTTPS是如何加密的

  1. 握手协商:在建立HTTPS连接之前,客户端和服务器会进行握手协商,以确定使用哪种加密算法和密钥。这个过程称为SSL/TLS握手。在握手期间,客户端向服务器发送一个“ClientHello”消息,其中包括所支持的加密算法和其他参数。服务器从中选择一个加密算法,并生成一个临时的加密密钥。
  2. 证书验证:服务器会向客户端发送一个数字证书,其中包含了服务器的公钥和证书颁发机构(CA)的签名。客户端会验证证书的有效性,包括检查签名是否有效、证书是否过期等。如果验证通过,客户端会提取服务器的公钥用于后续通信。
  3. 密钥交换:一旦证书验证成功,客户端会生成一个用于会话的随机密钥,并使用服务器的公钥对其进行加密。服务器使用其私钥解密客户端发送的随机密钥。现在,客户端和服务器都拥有相同的随机密钥,用于加密和解密通信数据。
  4. 数据加密:一旦密钥交换完成,通信数据将使用这个共享的密钥进行加密和解密。客户端和服务器之间的所有数据传输都将通过加密算法进行加密,从而保护数据的隐私和完整性。
  5. 安全通信:一旦握手和密钥交换完成,客户端和服务器之间的通信就是安全的。数据在传输过程中被加密,使得第三方无法轻易截取或窃听通信内容。

密钥存储

  1. 公钥:服务器的公钥通常包含在数字证书中,并在握手阶段发送给客户端。这个数字证书是由可信的证书颁发机构(CA)签发的,并被广泛分发和认可。因此,服务器的公钥可以被任何连接到服务器的客户端获取。
  2. 私钥:服务器的私钥是绝对不能公开的,因为它用于解密客户端发送的加密数据。服务器的私钥通常存储在服务器的安全硬件模块(HSM)中或者存储在受物理保护的服务器上。这些硬件和服务器通常具有严格的访问控制措施,以防止未经授权的访问。私钥的泄漏会对HTTPS连接的安全性造成严重威胁,因此它们需要受到高度的保护。

手写题:控制并发数量

// task 需要执行异步任务数组
// 最大同时执行的任务数量
function runTasks(tasks, max = 3) {
    let runingTaskNum = 0;
    const run = () => {
        if(runingTaskNum >= max || !tasks.length) {
            return;
        }
        const task = tasks.shift();
        runingTaskNum++;
        task().finnaly(() => {
            runingTaskNum--;
            run();
        })
    }
    while(runingTaskNum < max) {
        run();
    }
}

杂谈

部门信息,部门工作内容,工作是否非常的卷