vue复习
vue2和vue3的diff算法的区别?
vue2和vue3的区别?
webpack
为什么要有webpack?
热更新的原理
待补充
js运行机制
- 什么是同步什么是异步
2. js是单线程的
3. 事件循环
- 宏任务、微任务
await后面的代码相当于.then。
性能优化
性能指标:
检测网站性能:灯塔
前端安全
重构
预渲染
eslint规范
- 安装 ESLint:npm install eslint --save-dev
- 初始化配置文件:在项目根目录下执行
eslint --init命令,按照提示选择相应的配置选项。这将生成一个.eslintrc或.eslintrc.js配置文件。 - 配置规则:打开生成的
.eslintrc或.eslintrc.js文件,可以根据项目需求和团队约定修改或添加规则。可以在配置文件中的rules属性中设置具体的规则,也可以使用extends属性引入其他规则配置,例如"extends": "eslint:recommended"。 - 配置忽略文件:在配置文件中可以使用
ignorePatterns属性指定需要忽略的文件或目录,例如"ignorePatterns": ["dist/", "node_modules/"]。 - 添加命令脚本:在
package.json文件的scripts属性中添加一个脚本,用于运行 ESLint 检查代码。例如:
"scripts": {
"lint": "eslint . --ext .js"
}
这里的脚本命令是运行 eslint 命令来检查当前目录下所有后缀为 .js 的文件。
- 运行 ESLint:使用命令
npm run lint或yarn lint来运行 ESLint 检查代码。如果有不符合规则的地方,会在终端中显示错误或警告信息,并指导如何修复问题。
commit规范
利用husky+commitlint来做提交前的校验
封装组件
数据灵活 结构灵活 事件灵活
图片压缩
白屏问题
产生的原因:
网络问题:网络延迟或者网络不稳定可能导致资源加载缓慢或失败,从而引起白屏。
资源加载问题:如果页面引入的css或js文件、图片等资源存在404或者其他加载问题,也会导致白屏问题。
js错误:如果页面的js代码出现了错误,可能会导致页面无法正常渲染。
DOM结构错误:如果页面中的HTML代码存在语法错误,可能会导致浏览器无法正确解析DOM结构。 渲染性能问题:如果页面中存在大量复杂的DOM结构或者渲染性能问题,也可能导致白屏问题。
解决
规范
大文件上传
- 先获取文件:打印出来是个文件对象
- 对file文件进行切片:file中有slice方法,打印出来piece是blob类型,blob类型可以直接发送给服务器
3. 写一个切片函数,传递文件,传递切片大小,就可以帮助完成切片。(将切片结果放在result数组中进行保存)
4. 特殊场景:假设传到某个切片的时候断网了,下次还需要接着上传,还怎么继续传。
通过一次ajax请求就知道要传递哪些范围的分片
那客户端怎么告诉服务端这个文件呢???(我们需要找到唯一的东西代表这个文件,就是文件hash)
hash算法有很多,我们用的是md5. 接下来我们如何计算这个文件的hash值是什么???所以我们需要使用第三方库spark-md5算出文件的hash值。
- 计算文件hash值(分块去算hash值,叫增量算法)
垃圾回收机制
引用计数法:
问题: 循环引用,引用次数不可能为0,无法回收,内存无法释放。
标记清除法:
从根对象开始遍历,将存活的对象标记为1,如下图:
最后将所有标记为1的对象,标记为0,方便下一次垃圾回收机制回收,如下图:
问题: 位置是不连续的
V8对垃圾回收机制的优化
新生代:
form空间是使用空间,to是闲置空间,当form空间中的对象要满的时候,我们就开始标记,将存活的对象标记好,标记好后,将他们复制到闲置空间中,然后把form空间清空,再交换to、form名称。
老生代:
首先将所有对象标记为0,将存活对象标记为1,将标记为0的对象清空,将标记为1的对象标记为0,最后再用标记压缩算法,使他们的位置整理好。
问题:js是单线程的,所以垃圾回收机制会阻塞js执行,V8机制对这种情况做了优化,垃圾回收机制支持多线程并行回收。但是这样依旧会阻塞js的执行,所以诞生了增量标记,增量标记最大的特点是:垃圾回收可以分段执行。
那如何记录上一次回收的位置呢?
将上次标记的位置标记为灰色,当下次执行的时候,从灰色开始重新标记,V8还支持并行回收。
内存泄漏
下划线转成驼峰
function toHump(name) {
return name.replace(/_(\w)/g, function(all, letter){
return letter.toUpperCase();
});
}
toHump('hello_js_go') //helloJsGo
驼峰转成下划线
function toLine(name) {
return name.replace(/([A-Z])/g,"_$1").toLowerCase();
}
toLine('aBcdEfg') //a_bcd_efg
实现Event-bus
class EventBus {
constructor() {
this.events = {};
}
// 订阅事件
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
// 发布事件
emit(eventName, data) {
const eventCallbacks = this.events[eventName];
if (eventCallbacks) {
eventCallbacks.forEach((callback) => {
callback(data);
});
}
}
// 取消订阅事件
off(eventName, callback) {
const eventCallbacks = this.events[eventName];
if (eventCallbacks) {
this.events[eventName] = eventCallbacks.filter((cb) => cb !== callback);
}
}
}
// 创建一个全局的 Event-bus 实例
const eventBus = new EventBus();
// 示例用法
// 订阅事件
eventBus.on('event1', (data) => {
console.log('Event 1:', data);
});
// 发布事件
eventBus.emit('event1', 'Hello, World!');
// 取消订阅事件
const callback = (data) => {
console.log('Event 2:', data);
};
eventBus.on('event2', callback);
eventBus.emit('event2', 'Goodbye!');
eventBus.off('event2', callback);
在上述示例中,EventBus 类表示一个 Event-bus 对象,它具有 on、emit 和 off 方法。
on(eventName, callback):用于订阅事件。将事件名称eventName和回调函数callback添加到事件列表中。emit(eventName, data):用于发布事件。触发事件名称为eventName的事件,并将数据data传递给订阅该事件的回调函数。off(eventName, callback):用于取消订阅事件。从事件列表中移除事件名称为eventName,且回调函数为callback的订阅。
通过创建一个全局的 Event-bus 实例,不同组件可以订阅、发布和取消订阅事件,实现它们之间的通信。当某个组件调用 emit 方法发布事件时,所有订阅该事件的回调函数都会被触发执行,并且可以传递数据作为参数。
需要注意的是,上述示例的 Event-bus 实现比较简单,没有考虑多个实例、异步操作、错误处理等情况。在实际应用中,可能需要根据具体需求进行功能扩展和优化。
Event-bus 如何改造成 Promise 的接口
Event-bus 是一种常见的前端开发模式,用于实现组件间通信,但是通过 Promise 更加符合现代 JavaScript 开发思路。下面简单介绍一下如何将 Event-bus 改造为 Promise 的接口。
- 创建一个 Promise 对象:在 Event-bus 中发送事件时,我们可以将其封装为一个 Promise 对象。例如,我们可以定义一个函数
emitPromise,它接收相应的参数,返回一个 Promise 对象。
function emitPromise(event, ...params) {
return new Promise((resovle, reject) => {
eventBus.$emit(event, ...params);
resolve();
})
}
其中,event 参数表示要发送的事件名称,params 参数表示要传递给事件监听器的参数。我们通过调用 $emit 方法来触发事件,并在 Promise 的 resolve 方法中返回结果。
- 监听 Promise 对象:在 Event-bus 中监听事件时,我们可以根据事件名称注册一个回调函数。对于 Promise 对象,我们可以使用
.then()方法来监听事件完成的状态。
function onPromise(event) {
return new Promise((resolve, reject) => {
eventBus.$on(event, (result) => {
resolve(result);
});
});
}
其中,event 参数表示要监听的事件名称。我们先创建了一个 Promise 对象,并在 $on 方法中注册了一个回调函数,当事件触发时,回调函数会将结果传递给 Promise 的 resolve 方法。
- 使用 Promise 接口:在 Event-bus 中,我们可以使用
$emit方法来发送事件,使用$on方法来监听事件。在使用 Promise 接口时,我们可以将其改为使用emitPromise函数来发送事件,使用onPromise函数来监听事件。
// 发送事件
emitPromise('event-name', 'param1', 'param2')
.then(() => {
console.log('事件触发成功!');
});
// 监听事件
onPromise('event-name')
.then((result) => {
console.log(`事件接收到了结果:${result}`);
});
上述代码中,我们使用 emitPromise 函数发送了一个名为 event-name 的事件,并传递了两个参数。在 .then() 方法中,我们定义了事件触发成功后的回调函数。
同时,我们使用 onPromise 函数监听了同样的事件名称。在 .then() 方法中,我们定义了接收完成后的回调函数,它会接收到事件传递的结果。
通过这种方式,我们可以使用 Promise 更加优雅地实现组件间通信,并且能够使用 Promise 接口提供的丰富功能,例如链式调用、错误处理等。
npm版本号比较大小
版本号比较的原则如下:
- 首先比较主版本号(MAJOR),如果有差异,则选择较大的版本。
- 如果主版本号相同,再比较次版本号(MINOR),如果有差异,则选择较大的版本。
- 如果主版本号和次版本号都相同,再比较修订版本号(PATCH),如果有差异,则选择较大的版本。
在比较版本号时,可以使用 npm semver 模块提供的 gt、lt、gte、lte 等函数。这些函数用于比较两个版本号的大小。
以下是使用 npm semver 模块进行版本号比较的示例代码:
javascriptCopy Code
const semver = require('semver');
const version1 = '1.2.3';
const version2 = '1.3.0';
if (semver.gt(version1, version2)) {
console.log(`${version1} is greater than ${version2}`);
} else if (semver.lt(version1, version2)) {
console.log(`${version1} is less than ${version2}`);
} else {
console.log(`${version1} is equal to ${version2}`);
}
在上述示例中,我们通过 semver.gt 函数比较了 version1 和 version2 的大小。如果 version1 大于 version2,则打印出 ${version1} is greater than ${version2};如果 version1 小于 version2,则打印出 ${version1} is less than ${version2};如果两个版本号相等,则打印出 ${version1} is equal to ${version2}。
通过使用 npm semver 模块,可以方便地进行版本号的比较和判断。
如果一个用户在北京的特定机型上出现了白屏问题,而周围的同事使用相同的机型没有复现该问题,那么可能是由于一些特定的环境或配置导致的。以下是一些排查思路:
- 浏览器版本:首先确认用户使用的是哪个浏览器版本,是否与其他同事使用的浏览器版本有差异。如果有差异,可以尝试升级或降级浏览器版本,看是否能够复现问题。
- 缓存问题:如果用户之前访问过该页面,可能存在缓存导致页面无法正常加载。可以尝试清除浏览器缓存,或者在代码中添加版本号来强制刷新页面。
- 网络问题:确认用户的网络状况是否正常,尝试使用相同的网络环境测试页面是否能正常加载。如果网络不稳定,可能会导致页面加载失败或延迟。
- 设备配置:检查用户的设备配置,例如屏幕分辨率、操作系统版本等,是否与其他同事有差异。这些差异可能影响页面的布局和渲染。
- 兼容性问题:确保所使用的前端框架、库和特性支持用户的设备和浏览器。在某些情况下,特定的前端特性可能在某些浏览器或设备上不被支持,需要进行相应的兼容性处理。
- 错误日志:检查是否有错误日志记录。在前端代码中添加错误捕获和日志记录的功能,可以帮助快速定位问题所在。
- 与用户沟通:与用户详细沟通,了解具体操作步骤、输入内容等。可能用户在特定的操作步骤下才会出现白屏问题,从而帮助定位到问题所在。
综上所述,针对该白屏问题,可以从浏览器版本、缓存、网络、设备配置、兼容性、错误日志和与用户的沟通等多个角度来排查问题,并根据具体情况逐步缩小问题范围,最终找到导致白屏问题的原因并进行修复。
localstorage 大家都去写, 很容易就写满了. 如何处理呢?
以下是一些处理 LocalStorage 容量限制的方法:
-
使用 SessionStorage:与 LocalStorage 类似,SessionStorage 也是一种本地存储机制,但是它存储的数据只在当前会话期间有效,即当用户关闭浏览器标签页或窗口后,SessionStorage 中的数据将被删除。因此,如果你只需要在会话期间保存少量的数据,可以考虑使用 SessionStorage。
-
压缩数据:如果你需要存储较大的数据,可以尝试对数据进行压缩,以减小存储空间的占用。可以使用一些 JavaScript 库,如 pako.js、lz-string.js 等来处理压缩和解压缩操作。
-
删除过期数据:如果你的应用需要定期清理 LocalStorage 中的过期数据,可以在存储每个值的同时存储一个时间戳,以便在需要时检查该值是否过期,并定期清理已过期的数据。
-
拆分数据:如果你需要存储大量的数据,可以考虑将数据拆分为更小的部分,然后在需要时合并成一个完整的数据。这样可以降低每个键值对所占用的存储空间,同时也方便了数据的管理。
-
使用 IndexedDB:IndexedDB 是一种比 LocalStorage 更强大的浏览器内存储机制,它使用类似数据库的方式来存储数据,并支持事务操作、复杂查询等功能。如果你需要存储海量数据并进行高效的读写操作,可以考虑使用 IndexedDB。
-
使用 try-catch 捕获异常:当写入 LocalStorage 的时候,可以使用 try-catch 块来捕获写入过程中可能出现的异常,在捕获到异常后进行相应的处理,例如清空 LocalStorage,或者向用户提示存储空间已满的消息。
javascriptCopy Code
try {
localStorage.setItem(key, value);
} catch (e) {
// 处理异常,例如清空 LocalStorage
localStorage.clear();
// 或者提示用户存储空间已满
alert('LocalStorage已满,请清理存储空间');
}
- 使用存储队列:将需要存储的数据放入一个队列中,然后通过定时器或者其他方式依次从队列中取出数据,写入 LocalStorage。这样可以保证每次写入的数据量不会过大,从而避免 LocalStorage 容量满的问题。
javascriptCopy Code
let storageQueue = []; // 存储队列
function addToStorageQueue(data) {
storageQueue.push(data);
}
function writeToLocalStorage() {
if (storageQueue.length > 0) {
const data = storageQueue.shift();
try {
localStorage.setItem(data.key, data.value);
} catch (e) {
// 处理异常,例如清空 LocalStorage
localStorage.clear();
// 或者提示用户存储空间已满
alert('LocalStorage已满,请清理存储空间');
}
}
}
// 定时器每隔一段时间写入一次 LocalStorage
setInterval(writeToLocalStorage, 1000);
原型
对象获取原型:
构造函数获取原型:
原型对象类与继承
继承:
原型对象的继承:
原型链上的最终指向为object
instanceof原理
箭头函数和普通函数的区别
深度克隆
为什么需要虚拟DOM
1. 框架设计
数据驱动:数据一变化,在render函数中就要全量生成,由于他是这样子设计的,就导致了如果这里面有真实DOM存在,就要操作真实的DOM,真实DOM很昂贵,就会严重的影响效率。没办法使用了虚拟DOM,比较虚拟DOM哪个变了,再去操作真实的DOM
跨平台:浏览器环境才认识真实DOM,一旦脱离了浏览器环境,就不行了。因此搞了有个所有环境都认识的虚拟DOM。根据不同的环境,使用虚拟DOM渲染出界面,就可以实现一套代码多端使用了。