如何设计一个图像识别的接口?
对于一个图片,后端接收前端传递的图片信息,比如图片宽高和需要识别的位置的位置信息,在第一次识别之后,将识别结果缓存到数据库中,后续再次查看识别结果就可以直接从数据库中取出数据。否则后续每次都需要重新识别,这样可以提高效率。接口将相似度最高的前100张图片返回给前端。
webpack原理?为了解决什么问题?webpack性能优化?如何设计webpack ddlplugin?
webpack原理:[万字总结] 一文吃透 Webpack 核心原理 - 知乎 (zhihu.com)
webpack是用来解决什么问题的?
- 效率问题:更多的模块带来了更多的js文件,更多的js文件带来了更多的网络请求,降低了页面的访问效率。webpack将众多文件生成几个bundles文件,减少了网络请求。
- 兼容问题:浏览器目前仅支持ES6的模块化标准,并且还存在兼容性问题。
- 工具问题:浏览器不支持npm下载的第三方包。
- 打包压缩:删除空格换行注释等无用信息。
- 添加文件指纹:文件内容发生变化,重新生成文件指纹,就可以让浏览器区分是否用缓存文件还是获取新的文件
- 开发时启动开发服务器:文件发生变动时,webpack重新打包,并通知浏览器从开发服务器获取新的打包文件,从而刷新页面
webpack性能优化:
- 加快webpack构建速度
- 缩小文件的搜索范围(配置include/exclude/resolve.modules/resolve.mainFields/alias/noParse/resolve.extensions)
- 使用cache-loader,将结果缓存在磁盘中
- 使用happypack开启多进程打包
- thread-loader。将其放置在其他loader之前,那么放置在这个loader之后的loader就会在一个单独的worker池中进行。但是在worker池中运行的loader是受到限制的。例如:这些loader不能产生新的文件;这些loader不能使用定制的loader api;这些loader无法获取webpack的选项设置
- 使用hard-source-webpack-plugin为模块提供中间缓存
- 使用ignorePlugin忽略第三方包指定目录
- 使用webpack-parallel-uglify-plugin增强代码压缩
- 减少打包文件体积
- 使用externals配置,然后将js包、css文件存储在cdn
- 使用DLLPlugin(动态链接库)将bundles拆分,避免第三方包重复编译
- 使用optimization.splitChunks配置抽离公共代码
- 使用ignorePlugin忽略第三方包指定目录
- 使用url-loader和image-webpack-loader对图片进行转化和压缩处理
- 优化source-map
- 按需加载
hooks原理?
函数式编程和闭包状态管理
用户认证基于jwt与seesion的优劣
- jwt: 优点:
- 可扩展性好,应用程序分布式部署的情况下,session需要做多机数据共享,通常需要存在数据库或者redis里面。而jwt不需要。
- 无状态。jwt不在服务器端存储任何状态。restful api的原则之一是无状态,发出请求时,总会返回带有参数的响应,不会产生附加影响。用户的认证状态引入这种附加影响,这破坏了这一原则。另外jwt的载荷中可以存储一些常用信息,用户交换信息,有效的使用jwt,可以降低服务器查询数据库的次数。 缺点:
- 安全性:由于jwt的payload是使用base64编码,并没有加密,因此jwt中不能存储敏感数据。而session的信息是存在服务端的,相对来说更安全。
- 性能:jwt太长。由于是无状态使用jwt,所有的数据都被放在jwt里,如果还要进行一些数据交换,那载荷会更大,经过编码之后导致jwt非常长,cookie限制的大小一般是4k,cookie很可能放不下,所以jwt的token一般放在localStorage中。并且用户在系统中的每次http请求都会把jwt携带在header里面,http请求的header可能比body还要大。而session id只是很短的一个字符串,因此使用jwt的http请求比使用session的开销大得多。
- 一次性:无状态是jwt的特点,但也导致了jwt是一次性的。想修改里面的内容,就必须签发一个新的jwt。1)无法废弃:通过上面jwt的验证机制可以看出,一旦签发一个jwt,在到期之前就会始终有效,无法中途废弃。例如你在payload中存储了一些信息,当信息需要更新时,则重新签发一个jwt,但是由于旧的jwt还没过期,拿着这个旧的jwt依旧可以登录,那登陆后服务端从jwt中拿到的信息就是过时的。为了解决这个问题,我们就需要在服务端部署额外的逻辑,例如设置一个黑名单,一旦签发了新的jwt,那么旧的就加入黑名单(比如存到redis里面),避免被再次使用;2)续签:如果使用jwt做会话管理,传统的cookie续签方案一般都是框架自带的,session有效期30分钟,30分钟内如果有访问,有效期被刷新至30分钟。一样的道理,要改变jwt的有效时间,就要签发新的jwt。最简单的一种方式时每次请求刷新jwt,即每个http请求都返回一个新的jwt。这个方法不仅暴力不优雅,而且每次请求都要做jwt的加密解密,会带来性能问题。另一个方法是在redis中单独为每个jwt设置过期时间,每次访问时刷新jwt的过期时间;
可以看出想要破解jwt一次性的特性,就需要在服务端存储jwt的状态。但是引入redis之后,就把无状态的jwt硬生生变成有状态了,违背了jwt的初衷。而且这个方案和session都差不多了。
适合使用jwt的场景:
- 有效期短
- 只希望被使用一次
比如,用户注册后发一封邮件让其激活账户,通常邮件中需要有一个链接,这个链接需要具备以下的特性:能够标识用户,该链接具有时效性(通常只允许几小时内激活),不能被篡改以激活其他的账户,一次性的。这种场景就适合使用jwt。
而由于jwt具有一次性的特性。单点登录和会话管理非常不适合用jwt,如果在服务端部署额外的逻辑存储jwt的状态,那还不如使用session。基于session有很多成熟的框架可以开箱即用,但是用jwt还要自己实现逻辑。
- session: 基于sessin的认证流程为:
- 用户输入其登录信息
- 服务器验证信息是否正确,并创建一个session,然后将其存储在数据库中
- 服务器为用户生成一个sessin id,将具有session id 的cookie放置在用户浏览器中
- 在后续请求中,客户端请求会携带seesion id,服务器会根据数据库验证session id,如果有效,则接受请求
- 一旦用户注销应用程序,会话将在客户端和服务端都被销毁
优点:
- session中的信息存储在服务端,相比cookie就在一定程度上加大了数据的安全性
- session数据存储在服务端,相比jwt方便进行管理,也就是说当用户登录和主动注销,只需要添加删除对应的session就可以,这样管理起来很方便
缺点: - session存储在服务端,这就增加了服务器的开销,当用户多的情况下,服务器性能会大大降低
- 因为是基于cookie来进行用户识别的,cookie如果被截获,用户就很容易受到跨站请求伪造的攻击。
- 用户认证之后,服务端做认证记录,如果认证的记录被保存子啊内存的话,这意味着用户下次请求还必须请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,响应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。
DOM渲染会影响js的执行吗
DOM渲染与js执行都执行在渲染主线程,所以会互相阻塞。
js单线程的好处和坏处?
优点:
- 切换开销小
- js作为浏览器脚本语言,如果设置为多进程的话,会带来复杂的同步问题,操作DOM必然会涉及资源的竞争。而设计成单线程,并辅以完善的异步队列来实现,那么运行成本就会比多线程的设计要小很多了。比如,假设js同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?所以,为了避免复杂性,js从一开始就是单线程,这已经成了这门语言的核心特征,将来也不会改变。为了利用多核CPU的计算能力,html5提出web worker标准,允许js脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变js单线程的本质。
缺点:
- 阻塞:js在执行某个任务时会阻塞整个线程,因此如果某个任务需要大量计算或者网络请求等耗时操作,就会导致页面的响应时间变慢甚至出现卡顿现象。
- 难以利用多核CPU:由于js是单线程的,因此无法利用多核CPU的优势,这使得在处理大量数据或者进行复杂计算时效率低下。
- 不适合CPU密集型任务:由于js是单线程的,因此对于CPU密集型任务(例如视频编码、图像处理等),js的执行效率低下。
- 难以处理大量并发请求:由于js的单线程特性,无法同时处理多个请求,这使得在处理大量并发请求时,js的执行效率较低。
- 容易出现死锁:由于js的单线程特性,当某个任务长时间占用线程时,其他任务就会被阻塞,这可能会导致死锁的发生。
- 无法实现真正的并行:由于js是单线程的,无法真正的实现并行,而只能通过异步编程方式模拟并行。这种模拟方式需要使用回调、Promise、async/await等技术,代码复杂度较高,也容易出现回调地狱等问题。
canvas和svg的区别
canvas和svg都允许你在浏览器中创建图形,但是它们在根本上是不同的。
svg可以用来定义XML格式的矢量图形,本质上是一种使用XML描述2D图形的语言。
svg创建的每个元素都是一个独立的DOM元素,既然是独立的DOM元素,那么我们就可以通过css和js来操作dom,可以对每一个dom元素进行监听。
并且因为每个元素都是一个DOM元素,所以修改svg中的dom元素,系统会自动进行dom重绘。
canvas通过js来绘制2d图形,canvas只是一个html元素,其中的图形不会单独创建dom元素。因此我们不能通过js操控canvas内单独的图形,不能对其中的具体图形进行监控。
在canvas中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。
实际上canvas是基于像素的即时模式图形系统,绘制完对象不保存对象到内存中,当再次需要这个对象时,需要重新绘制;svg是基于形状的保留模式图形系统,绘制完对象会被其保存在内存中,当需要修改这个对象信息时,直接修改就可以了。
| canvas | svg |
|---|---|
| 依赖分辨率(位图) | 不依赖分辨率(矢量图) |
| 单个HTML元素 | 每个图形都是一个DOM元素 |
| 只能通过脚本语言绘制图形 | 可以通过css也可以通过脚本语言绘制 |
| 不支持事件处理程序 | 支持事件处理程序 |
| 弱的文本渲染能力 | 最适合带有大型渲染区域的应用程序 |
| 图面较小,对象数量较大(>10k)时性能最佳 | 对象数量较小(<10k)、图面更大时性能更佳 |
市面上各个微前端框架的区别与优劣
qiankun:
优点:
- 降低了应用改造的成本,通过html entry的方式引入子应用
- 提供了完备的沙盒方案,包括js沙盒和css沙盒
- 支持静态资源预加载能力
缺点:
- 适配成本高,包括工程化、生命周期、静态资源路径、路由等方面的适配
- css沙盒的严格隔离可能引发问题,js沙盒在某些场景下性能下降
- 无法同时激活多个子应用,不支持子应用保活
- 不支持vite等esmodule脚本运行
micrp-app:
优点:
- 使用webcomponent加载子应用,更优雅
- 复用经过大量项目验证过的qiankun沙盒机制,提高了框架的可靠性
- 支持子应用保活
- 降低了子应用改造的成本,提供了静态资源预加载能力
缺点:
- 接入成本虽然降低,但路由依然存在依赖
- 多应用激活后无法保持各子应用的路由状态,刷新后全部丢失
- css沙盒无法完全隔离,js沙盒做全局变量查找缓存,性能有所优化
- 支持vite运行,但必须使用plugin改造子应用,且js代码没办法沙盒隔离
- 对于不支持webcomponent的浏览器没有做降级处理
EMP方案:
优点:
- webpack联邦编译可以保证所有子应用依赖解耦
- 支持应用间去中心化的调用、共享模块
- 支持模块远程ts支持
缺点:
- 对webpack强依赖,对于老旧项目不友好
- 没有有效的css沙盒和js沙盒,需要靠用户自觉
- 子应用保活、多应用激活无法实现
- 主、子应用的路由可能发生冲突
无界方案:
优点:
- 基于webcomponent容器和iframe沙盒、充分解决了适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite框架支持、应用共享等问题
缺点:
- 在继承了iframe优点的同时,缺点也继承了
script标签的async和defer
defer属性告诉浏览器不要等待脚本,浏览器继续处理html,构建dom。该脚本在后台加载,然后在dom构建完成后再运行。defer脚本保持相对顺序来执行,就像常规脚本一样,按照script标签从上至下的顺序执行,不会根据下载完成顺序执行
async属性意味着该脚本是完全独立的,浏览器的渲染不会阻塞该脚本的下载与执行,该脚本也不会阻塞其他脚本的执行。async脚本在下载完成后立即执行
link标签的prefetch和preload
preload告诉浏览器立即加载资源prefetch告诉浏览器在空闲时才开始加载资源preload和prefetch仅仅是加载资源,并不会执行preload和prefetch均能设置、命中缓存- 正确使用
preload和prefetch不会导致重复请求
react中非list结构为何不需要添加key值
对于非list结构很难出现dom经常变动的情况,逐层对比就已经满足新旧节点对比的需求。而且非list结构都需要开发者添加唯一的key值的话,开发成本、心智负担过大。而对于list结构,数据会经常变动,当头部或中部插入新数据时,逐层对比对因为对比错位而失效,所以需要key来缓存旧节点,从而借用map修正逐层对比。