前言
找工作,面试官非常看重个人的技术沉淀,如果说你有自己的博客(记录自己日常的一些技术分析等),开源(针对公司业务开发的组件,插件等,或者个人为了学习新技术而搭建的一套完整的技术产品,如电商系统等),那么这会让面试官眼前一亮,最起码会给人一种你是热爱技术的感觉,第一印象会加很多分,拿本人的开源项目来说:
- 基于Taro3的虚拟列表:github.com/tingyuxuan2…
- 基于cesium的热力图组件:github.com/cesium-plug…
star虽说没有成千上万,但至少证明你在沉淀,对技术是有追求的!
攻重浩: 攻城师不浪(优秀技术解决方案、前端架构、3D可视化、基础建设等);
绿泡泡:brown_7778(请尊重个人时间);
基建方向
一、如何监控资源加载时长?
获取所有资源:performance.getEntries()
获取静态资源:performance.getEntriesByType("resource")
获取动态资源载入:PerformanceObserver
参考: cloud.tencent.com/developer/a…
二、如何监听白屏、首屏渲染时长?
- 白屏
利用performance.timing的API(监控白屏这块网络上始终没有比较全面的介绍,如果有人做过实践,欢迎留言 )
document.addEventListener("DOMContentLoaded", () => {
console.log('---------333-------', performance.timing.domInteractive - performance.timing.fetchStart)
})
2. 首屏
MutationObserver:监听页面元素抖动频率最大的那一时刻
三、js加载执行:async, defer, preload, prefetch的区别?
- async:立即下载(异步,不会阻碍文档解析),异步执行(执行的时候会阻碍文档解析)
- defer:立即下载(异步,不会阻碍文档解析),延迟执行,在整个页面都解析完毕后执行
- preload:提前下载,需要的时候立即执行,无需再下载
- prefetch:提前下载,在未来的某个页面可能会执行,节省下载时间
四、浏览器从输入url到渲染的过程?
五、浏览器的进程与线程
进程
浏览器进程、GPU进程、网络进程、插件进程、渲染进程
渲染进程中的线程
GUI渲染线程、JS引擎线程、计时器线程、异步http请求线程、事件触发线程 参考:juejin.cn/post/699184…
六、错误捕获
- document.addEventListener("unhandledrejection")
- document.addEventListener("error")
七、webpack优化手段
- exclude、include配置来转译更少的文件
- cache-loader缓存编译结果
- happypack多核构建,把任务分给多个子进程并发执行
- thread-loader把loader放置在单独的worker池中进行
- HardSourceWebpackPlugin提供中间缓存,节省二次编译构建时间
- DllPlugin和DLLReferencePlugin实现拆分bundles,将不会频繁更新的第三方库(如:react、react-dom等)单独打包
- optimization.splitChunks抽离公共代码
- webpack-bundle-analyzer分析包体积
八、如何监听到某个资源加载失败以及要怎么处理?
九、页面长时间停留可能会卡死,从什么角度去排查问题
从内存溢出等方向,看是否有倒计时未清除、是否dom节点在无限递增、打印了(console)大量的size大的对象,大量闭包等方向
十、jsBridge的原理
十一、浏览器合成层
十二、css加载会阻塞dom渲染吗?会阻塞js执行吗?
十三、h5优化手段
十四、强缓存、协商缓存与cdn缓存的区别
参考:(www.upyun.com/tech/articl… CDN 缓存与浏览器缓存.html)
JS基础
一、变量提升
var a = 2;
// 问题1
(function(){
console.log(a)
const a = 1
})()
// 问题2
(function(){
console.log(a)
var a = 1
})()
二、原型、原型链
参考:github.com/mqyqingfeng…
注意:
Function._proto_ === Function.prototype
Function.prototype._proto_ === Object.prototype
三、箭头函数、普通函数的区别
- this指向
- 箭头不能new(原因)
四、构造函数如果是箭头函数能不能用new(不能)
五、实现一个功能让构造函数只能new操作,否则报错
if (!this instanceof Constructor) {
throw new Error()
}
六、class类与es5的构造函数有什么区别
七、mutationObserver、requestAnimationFrame
八、闭包的缺点
TS
一、泛型、infer
- 泛型:一种可重用的表示,可用类型变量,表示变量而不是值,可约束某些值的类型
- infer:表示在
extends
条件语句中待推断的类型变量
网络
一、http缓存
二、https原理
三、解决跨域请求头都需要设置什么
四、cookie、session、localStorage分别是什么?有什么作用?
五、什么情况下会发送预检请求?如何优化?
React
一、新版生命周期
- 创建:constructor -> getDerivedStateFromProps -> render -> componentDidMount
- 更新:getDerivedStateFromProps -> shouldComponentDidUpdate -> render -> getSnapShotBeforeUpdate -> componentDidUpdate
- 卸载:componentWillUnMount
二、hooks如何模拟didupdate生命周期
const isDidMount = useRef(true)
useEffect(() => {
if (isDidMount.current) {
// 只有第一次执行
isDidMount.current = false
return
}
//didupdate...
})
三、useEffect和useLayoutEffect区别
- useEffect:回调在组件渲染完成之后的一个延迟函数中执行,不会阻塞视图渲染
- useLayoutEffect:在render之后执行,执行时机相当于componentDidMount和componentDidUpdate,会同步触发组件重新render,会阻塞视图渲染
四、hooks原理
五、diff原理、fiber原理
六、hooks和class的区别(hooks解偶)
七、react如何实现的中断可恢复更新
手写题(编码)
- 实现flat
const myFlat = (arr) => {
return arr.reduce((prev, cur) => {
return prev.concat(Array.isArray(cur) ? myFlat(cur) : cur)
}, [])
}
2. 实现promise.all
const promiseAll = (promises) => {
let res = []
let count = 0
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then((data) => {
count++
// 重点,向对应下标塞数据,保证顺序
res[i] = data
if (count === promises.length) {
resolve(res)
}
}).catch(err => {
reject(err)
})
}
})
}
3. 实现new
function myNew() {
const obj = new Object()
const Constructor = [].shift.call(arguments)
obj.__proto__ = Constructor.prototype
const res = Constructor.apply(obj, arguments)
return typeof res === "object" ? res : obj
}
4. 订阅发布
class Event {
constructor() {
// 所有 eventType 监听器回调函数(数组)
this.listeners = {};
}
/**
* 订阅事件
* @param {String} eventType 事件类型
* @param {Function} listener 订阅后发布动作触发的回调函数,参数为发布的数据
*/
on(eventType, listener) {
if (!this.listeners[eventType]) {
this.listeners[eventType] = [];
}
this.listeners[eventType].push(listener);
}
/**
* 发布事件
* @param {String} eventType 事件类型
* @param {Any} data 发布的内容
*/
emit(eventType, data) {
const callbacks = this.listeners[eventType];
if (callbacks) {
callbacks.forEach((c) => {
c(data);
});
}
}
}
5. 实现一个缓存函数
const memorize = (fn) => {
const obj = {}
return (...args) => {
const key = JSON.stringify(args)
if (obj[key]) {
return obj[key]
} else {
return (obj[key] = fn.apply(this, args))
}
}
}
6. 数组去重
const unique = (arr) => {
const obj = {}
return arr.filter((item) => {
const key = typeof item + item
return obj.hasOwnProperty(key) ? false : (obj[key] = true)
})
}
7. arrayToTree 将
var arr = [
{ id: 1, name: "1111", pid: 0 },
{ id: 2, name: "2222", pid: 1 },
{ id: 3, name: "3333", pid: 1 },
{ id: 4, name: "4444", pid: 2 },
{ id: 5, name: "5555", pid: 4 },
{ id: 6, name: "5555", pid: 0 },
];
转化为
[
{
id: 1,
name: "1111",
pid: 0,
children: [
{
id: 2,
name: "2222",
pid: 1,
children: [
{
id: 4,
name: "4444",
pid: 2,
children: [
{
id: 5,
name: "5555",
pid: 4,
},
],
},
],
},
{
id: 3,
name: "3333",
pid: 1,
},
],
},
{
id: 6,
name: "5555",
pid: 0,
},
];
const arrayToTree = (arr, id, pid, rootVal) => {
const res = []
for (let i = 0; i < arr.length; i++) {
const item = arr[i]
if (item[pid] === rootVal) {
res.push(item)
} else {
const parent = arr.find(el => el[id] === item[pid])
if (parent) {
if (parent.children) {
parent.children.push(item)
} else {
parent.children = [item]
}
}
}
}
return res
}
8. 实现接口最大并发
// arr -> 接口数组
// max -> 最大并发数
const poll = (arr, max) => {
const run = () => {
if (!arr.length) return
const min = Math.min(arr.length, max)
for (let i = 0; i < min; i++) {
max--
const item = arr.shift()
Promise.resolve(item).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
}).finally(() => {
max++
run()
})
}
}
run()
}
9. 防抖
const debounce = (fn, delay) => {
let timer = null
return (...args) => {
timer && clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
10. 截流
const throttle = (fn, delay) => {
let timer = null
let startTime = 0
return (...args) => {
timer && clearTimeout(timer)
const now = Date.now()
if (now - startTime > delay) {
fn.apply(this, args)
startTime = now
} else {
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
}
11. reduce
Array.prototype.myReduce = function(callback, initVal) {
const arr = this
let res = initVal === undefined ? arr[0] : initVal
const index = initVal === undefined ? 1 : 0
for (let i = index; i < arr.length; i++) {
res = callback(res, arr[i], i, arr)
}
return res
};
12. 深拷贝
- promise
- 柯里化
const curry = (fn) => {
return curried = (...args) => {
if (args.length >= fn.length) {
return fn.apply(this, args)
} else {
return (...innerArgs) => {
return curried.apply(this, [...args, ...innerArgs])
}
}
}
}
15. 千分位分隔符
const myLocalStr = (num) => {
const arr = num.toString().split("").reverse()
let res = []
for (let i = 0; i < arr.length; i++) {
if (i % 3 === 0 && i !== 0) {
res.push(",")
}
res.push(arr[i])
}
return res.reverse().join("")
}
16. promisify
const promisify = (fn) => (...args) => {
return new Promise((resolve, reject) => {
fn.call(this, ...args, (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
CSS
一、 什么是BFC(一块独立的渲染区域)
如何触发BFC布局:
- float的值不为none
- overflow的值不为visible
- display的值为inline-block、table-cell、table-caption
- position的值为absolute或fixed
二、三角形,以及给加个边框
加边框:两个三角形重叠
三、margin重叠问题
将父元素添加overflow:hidden,变成BFC模块
四、css module原理
五、盒模型
算法、数据结构
1. 判定有效括号
2. 最长回文子串
3. 判断数组中是否有重复元素
4. 链表反转
前端安全
1. 什么是xss攻击,如何防御
项目
一、小程序底层实现原理
- 双线程原因:管控性和安全性,阻止开发者使用一些页面跳转、dom操作、动态执行脚本的开放性操作,因此小程序提供了一个沙箱,只能进行纯js操作,没有任何浏览器相关接口
- 双线程通信:通过native(微信客户端)中转