1. 好未来
- 大数相加
let a = "9007199254740991";
let b = "1234567899999999999";
function add(a, b) {
if (a.length < b.length) [a, b] = [b, a];
a = a.split('').reverse();
b = b.split('').reverse();
let carry = 0;
let result = [];
for (let i = 0; i < a.length; i++) {
let digitA = parseInt(a[i], 10);
let digitB = i < b.length ? parseInt(b[i], 10) : 0;
let sum = digitA + digitB + carry;
result.push(sum % 10);
carry = Math.floor(sum / 10);
}
if (carry) result.push(carry);
return result.reverse().join('');
}
let a = "9007199254740991";
let b = "1234567899999999999";
console.log(add(a, b));
- 优化上面的代码
- 有技术难度的业务、技术挑战
- 讲一下当前业务
- ab测解耦:职责链模式
- class转hook
- 打包优化
- 业务sop
- 组件渲染方面优化
- 浏览器的缓存策略
- 强缓存
- no-cache:强制客户端在使用缓存资源前进行重新验证。
- no-store:禁止任何缓存,不存储响应数据。
- public:表示响应可以被任何缓存存储(客户端和代理服务器)。
- private:表示响应仅能被客户端缓存,不能被共享缓存存储。
- must-revalidate:要求缓存必须重新验证过期资源。
- Cache-Control 头部指令。
- max-age=seconds 指定资源可以缓存的最长时间(以秒为单位。
- 协商缓存
- ETag:是资源的唯一标识符,通常是由服务器生成的哈希值或其他唯一标识。每次资源修改时,
ETag 的值会变化。
- Last-Modified:
Last-Modified 表示资源的最后修改时间。每次资源修改时,Last-Modified 的值会更新。
- 浏览器的本地存储方式
- cookie
- localStorage
- sessionStorage
- IndexedDB
IndexedDB 提供了一个低级API,用于在用户浏览器中存储大量结构化数据。
let request = indexedDB.open("MyTestDatabase", 1);
request.onupgradeneeded = function(event) {
let db = event.target.result;
let objectStore = db.createObjectStore("customers", { keyPath: "id" });
objectStore.createIndex("name", "name", { unique: false });
};
request.onsuccess = function(event) {
let db = event.target.result;
let transaction = db.transaction(["customers"], "readwrite");
let objectStore = transaction.objectStore("customers");
objectStore.add({ id: 1, name: "John Doe" });
objectStore.get(1).onsuccess = function(event) {
console.log(event.target.result);
};
};
request.onerror = function(event) {
console.log("Database error: " + event.target.errorCode);
};
- File System Access API
File System Access API 允许Web应用直接与用户的文件系统交互。注意:此API目前在某些浏览器中需要实验性标志。
async function getFile() {
const [fileHandle] = await window.showOpenFilePicker();
const file = await fileHandle.getFile();
const contents = await file.text();
console.log(contents);
}
async function saveFile() {
const options = {
types: [
{
description: 'Text Files',
accept: { 'text/plain': ['.txt'] },
},
],
};
const handle = await window.showSaveFilePicker(options);
const writable = await handle.createWritable();
await writable.write('Hello World');
await writable.close();
}
getFile();
saveFile();
- 提高cookie的安全性
- 使用HttpOnly标志:使Cookie只能通过HTTP(S)请求发送,防止JavaScript在客户端访问Cookie,减小XSS攻击的风险。
- 设置合适的过期时间和Max-Age:根据需要设置合理的过期时间或最大存活时间,避免长期存储不必要的敏感信息
- 使用Secure标志:仅允许在HTTPS连接上传输Cookie,防止Cookie在不安全的网络中被拦截
- 避免存储敏感信息
- 加密Cookie的值
- 定期清理和更新Cookie
- 提高编译速度、提高开发效率
- 跨域
- 移动端适配兼容性问题
- 事件循环机制
- JavaScript 的事件循环机制(Event Loop)是处理异步操作的核心。它允许 JavaScript 在处理 I/O 操作(如用户输入、网络请求、定时器等)时不阻塞主线程,保持高性能和响应性
- 概念
- 调用栈(Call Stack):
- 调用栈是一个 LIFO(后进先出)结构,用于跟踪正在执行的函数调用。当一个函数被调用时,它会被推入调用栈,当函数执行完成后,它会从调用栈中弹出。
- 任务队列(Task Queue 或 Message Queue):
- 任务队列是一个 FIFO(先进先出)结构,用于存储异步任务的回调函数。这些回调函数将在调用栈为空时被执行。
- 微任务队列(Microtask Queue) :
- 微任务队列也是一个 FIFO 结构,存储微任务(microtasks),如
Promise 的回调函数。微任务会在当前事件循环的任务完成后立即执行,优先级高于任务队列中的任务。
- 事件循环(Event Loop) :
- 事件循环是一个不断检查调用栈和任务队列的循环机制。它负责从任务队列中取出任务并将其放入调用栈中执行。
- 原理
- 同步任务:
- 当 JavaScript 引擎开始执行脚本时,所有的同步任务会按照顺序被推入调用栈,并依次执行。同步任务执行完成后,调用栈会被清空。
- 异步任务:
- 异步任务(如
setTimeout、setInterval、I/O 操作、Promise 等)的回调函数会被放入相应的任务队列(任务队列或微任务队列)中。
- 事件循环流程:
- 事件循环不断地检查调用栈是否为空。
- 如果调用栈为空,事件循环会首先检查微任务队列,依次执行所有的微任务。
- 微任务执行完毕后,事件循环会检查任务队列,从中取出一个任务,将其推入调用栈中执行。
- 这个过程会不断重复,以确保所有的任务都被执行。
2. 白龙马
- 所做的工作
- ab测新增、迭代、下线、解耦,提升业务的灵活性和效果
- 解决手机兼容性问题:安卓、ios
- 根据日志、可回溯、埋点、数据大盘寻找并解决线上问题
- 新人讲解业务逻辑,制定团队开发、业务需求评审流程sop,组织CR
- 根据业务代码痛点,推动组内工具开发
- ab测、背景是什么、目的:
AB测试是一种在实验设计和统计学中常用的方法,用于比较两个或多个版本的产品或服务,以确定哪个版本在用户中表现更好。这种方法常用于Web设计、产品开发、营销策略等领域
- 怎么处理线上问题
- 上线完成即遇到问题
- 回滚
- 确认问题是否是问题
- 如果能解决则解决,再次发版
- 如果定位不到问题,则根据报错模拟出问题,并解决再发版
- 可回溯定位的问题
- 这种问题一般是根据可回溯、大盘数据、埋点异常发现的问题
- 解决这一类的问题首先根据异常的大盘数据、埋点寻找到时间、页面、用户
- 根据上述查看可回溯录屏,查看用户可能出现的操作
- 根据操作前后的日志查看后端数据、前端代码是否有问题
- 怎么判断ab测的结论
- 最有成就的事
- 负责项目重构,从需求评审、人员调配、任务分发、开发设计、测试CR、平滑上线
- 共计50多人天
- 怎么看待加班
- 一个场景做两个页面、都需要开发
- 怎么判断哪个页面需要增加ab测
- hook和class组件的区别
- hook性能提升点
- react的key的作用
- 什么是高阶组件、应用场景
- es6新增的语法
- 实现一个promise
- 控制并发的请求数量,一起进来6个请求,限制一次最多可以发送两个请求,请求完成后进来一个新的请求,直到所有请求完成之后把结果返回出来。
const requests = [1, 2, 3, 4, 5, 6];
async function controlConcurrentRequests(requests, limit) {
const inProgress = [];
const results = [];
const handleRequest = async (request) => {
try {
console.log(`Sending request ${request}`);
await new Promise(resolve => setTimeout(resolve, 1000));
results.push(`Request ${request} completed`);
console.log(`Request ${request} completed`);
} catch (error) {
console.error(`Request ${request} failed:`, error);
results.push(`Request ${request} failed`);
}
};
for (let i = 0; i < requests.length; i++) {
const requestPromise = handleRequest(requests[i]);
inProgress.push(requestPromise);
if (inProgress.length >= limit) {
await Promise.race(inProgress);
}
}
await Promise.all(inProgress);
return results;
}
controlConcurrentRequests(requests, 2)
.then(results => {
console.log("All requests completed:");
console.log(results);
})
.catch(error => {
console.error("Error handling requests:", error);
});
3. IM30
- rem、vw原理,响应式
- vw:基于视口宽度的相对单位,1vw等于视口宽度的1%,例如宽1000px,1vw=10px
- rem:是相对于根元素字体大小的单位(html)
- 区别:
- vw适用于响应式设计,因为它根据视口宽度进行缩放,无论视口变得多窄
- rem适用于一致排版的场景,可以通过调整根元素的字体大小,调整使用rem元素的大小
- useRef
- 访问DOM:通过useRef获取一个引用
- 存储持久值:用来存储渲染周期不变的任意值,而不会触发重新渲染。
- 避免闭包陷阱:通过将变量存储在ref中,可以确保在事件函数中始终访问到最新的值,而不是事件绑定时的值。
- 存储定时器引用
- 与forwardRef一起使用:useRef可以与React.forwardRef一起使用,将ref转发到子组件中。
- webPack4和5的区别
- 性能和优化
- 更快的构建速度
- webpack5引入了持久缓存,通过将缓存写入磁盘,webpack5能够在后续的构建中重用缓存,加快构建速度
- webpack4依赖内存缓存
- 更好的Tree Shaking
- webpack5改进了Tree Shaking算法,能更好的识别、删除未使用的代码
- 模块联邦
- webpack5引入了模块联邦,允许应用动态加载来自不同远程服务器的模块。4没有
- 打包输出改进:更小的包体积
- webpack5在打包输出上进行了改进,生成的包体积通常更小。得益于更好的代码分割和优化技术。
- webpack的打包流程
- juejin.cn/post/735974…
- 初始化阶段
- 读取配置
- 初始化创建compiler对象,管理整个编译过程
- 读取入口
- 模块递归处理
- 解析文件
- 使用loader
- 解析依赖:处理模块时,webpack会解析模块的依赖关系,并将依赖模块添加到依赖图中,递归处理,直到所有依赖都被解析。
- 输出资源
- 模块打包:将所有模块按照依赖关系打包成一个或者多个文件
- 使用plugin:在输出过程中,webpack会调用plugin,优化代码、注入环境变量、生成html文件
- 生成输出文件
- 什么时候挂载自定义plugin
- beforeRun: 在编译开始之前触发
- compile: 在创建新的编译开始时触发
- compilation: 在每个新的编译中触发(子编译和增量编译)
- emit: 在生成资源到输出目录之前触发
- afterEmit: 在生成资源到输出目录之后触发
- done: 在编译完成后触发
- 一个自定义plugin是具有apply方法的js类,接受一个compiler对象,通过该对象可以访问webpack的钩子
- 插件的挂载时机与他们绑定的钩子有关’
- ts项目引入js第三方库导致报错,如何解决
- 创建自定义类型声明:在src文件下创建一个.d.ts文件,然后在tsconfig.json文件中确保包含自定义类型声明文件的路径
- 使用ts-ignore注释
- type、interface的区别
- interface接口
- ts中用来命名一个特定的结构化类型的方式,用于定义对象的形状,包括属性、方法、其他。
- 可以扩展、合并,ts会自动合并同名接口的成员
- Type类型别名
- 允许为现有类型提供一个更具意义的名称。不仅限于对象类型,还可以为任何类型创建别名,包括基本类型、联合类型、元祖等。
- 可以使用联合类型、交叉类型等高级类型,类型别名可以使用TS中所有类型系统功能。
- 可以给现有类型起一个更具描述性的名字
- 可以在联合类型、交叉类型中进行复杂类型定义。
- 接口更适合定义对象的结构和方法,对类进行抽象
- 类型别名更适用给现有类型起一个新名字,或者服用联合类型、交叉类型等复杂类型定义。
- 捕获react内部错误
- try-catch
- compnentDidCatch
- Error Boundary
- js中的this
- flex:1