11. 说出你对 Electron 的理解?
- 减少 HTTP 请求数最最重要的一点, electron 实际上是一个套了 Chrome 的 nodeJS 序。
- Chrome 无各种兼容性问题
- NodeJS
12. WebSocket 的理解?
- 历史来源:序由于 http 存在一个明显的弊端(消息只能有客户端推送到服务器端,而服务器端不能主动推送到客户端),导致如果服务器如果有连续的变化,这时只能使用轮询,而轮询效率过低,并不适合。于是 WebSocket 被发明出来。
- 支持双向通信,实时性更强;
- 可以发送文本,也可以二进制文件
- 协议标识符是 ws ,加密后是 wss
- 较少的控制开销。连接创建后, ws 客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有 2~10 字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的 4 字节的掩码。而 HTTP 协议每次通信都需要携带完整的头部;
- 支持扩展。ws 协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)
- 无跨域问题
13. 什么是单线程,和异步的关系?
- 单线程 - 只有一个线程,只能做一件事
- 原因 - 避免 DOM 渲染的冲突:
- 浏览器需要渲染 DOM
- JS 可以修改 DOM 结构
- JS 执行的时候,浏览器 DOM 渲染会暂停
- 两段 JS 也不能同时执行(都修改 DOM 就冲突了)
- webworker 支持多线程,但是不能访问 DOM
- 解决方案 - 异步
14. 说说负载均衡 ?
- 单台服务器共同协作,不让其中某一台或几台超额工作,发挥服务器的最大作用。
- http 重定向负载均衡:调度者根据策略选择服务器以 302 响应请求,缺点只有第一次有效果,后续操作维持在该服务器 dns 负载均衡:解析域名时,访问多个 ip 服务器中的一个(可监控性较弱)原因 - 避免 DOM 渲染的冲突。
- 反向代理负载均衡:访问统一的服务器,由服务器进行调度访问实际的某个服务器,对统一的服务器要求大,性能受到 服务器群的数量。
15. webpack 的一些 plugin ,怎么使用 webpack 对项目进行优化 ?
- 构建优化:
- 减少编译体积 ContextReplacementPugin 、 IgnorePlugin 、 babel-plugin-import 、babelplugin-transform-runtime
- 并行编译 happypack 、 thread-loader 、 uglifyjsWebpackPlugin 开启并行
- 缓存 cache-loader 、 hard-source-webpack-plugin 、 uglifyjsWebpackPlugin 开启缓存。
- babel-loader 开启缓存:
- 预编译 dllWebpackPlugin && DllReferencePlugin 、 auto-dll-webapck-plugin。
- 原因 - 避免 DOM 渲染的冲突:
- 减少编译体积 Tree-shaking 、 Scope Hositing
- hash 缓存 webpack-md5-plugin
- 拆包 splitChunksPlugin 、 import() 、 require.ensure。
16. 编写一个 loader?
- loader 就是一个 node 模块,它输出了一个函数。当某种资源需要用这个
- loader 转换时,这个函数会被调用。并且,这个函数可以通过提供给它的
- this 上下文访问 Loader API 。 reverse-txt-loader
module.exports = {
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' }
]
}
};
17. webpack 打包体积优化思路
- 提取第三方库或通过引用外部文件的方式引入第三方库
- 代码压缩插件 UglifyJsPlugin
- 服务器启用 gzip 压缩
- 按需加载资源文件 require.ensure
- 优化 devtool 中的 source-map
- 剥离 css 文件,单独打包
- 去除不必要插件,通常就是开发环境与生产环境用同一套配置文件导致。
18. webpack 打包效率 ?
- 开发环境采用增量构建,启用热更新
- 开发环境不做无意义的工作如提取 css 计算文件 hash 等
- 配置 devtool
- 选择合适的 loader
- 个别 loader 开启 cache 如 babel-loader
- 第三方库采用引入方式
- 提取公共代码
- 优化构建时的搜索路径 指明需要构建目录及不需要构建目录
- 模块化引入需要的部分
19. 原型 / 构造函数 / 实例 ?
- 原型( prototype ): 一个简单的对象,用于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个 JavaScript 对象中都包含一个 proto (非标准)的属性指向它爹(该对象的原型),可 obj.proto 进行访问。
- 构造函数: 可以通过 new 来 新建一个对象 的函数。
- 实例: 通过构造函数和 new 创建出来的对象,便是实例。 实例通过 proto 指向原型,通过 constructor 指向构造函数。
- 以 Object 为例,我们常用的 Object 便是一个构造函数,因此我们可以通过它构建实例:
// 实例
const instance = new Object()
- 则此时, 实例为 instance , 构造函数为 Object ,我们知道,构造函数拥有一个 prototype的属性指向原型,因此原型为:
// 实例
const prototype = Object.prototype
- 原型 / 构造函数 / 实例三者的关系
- 实例.proto === 原型
- 原型.constructor === 构造函数
- 构造函数.prototype === 原型
// 这条线其实是是基于原型进行获取的,可以理解成一条基于原型的映射线
// 例如:
// const o = new Object()
// o.constructor === Object --> true
// o.__proto__ = null;
// o.constructor === Object --> false
实例.constructor === 构造函数
20. 原型链?
- 原原型链是由原型对象组成,每个对象都有 proto 属性,指向了创建该对象的构造函数的原型, proto 将对象连接起来组成了原型链。是一个用来实现继承和共享属性的有限的对象链。
- 属性查找机制: 当查找对象的属性时,如果实例对象自身不存在该属性,则沿着原型链往上一级查找,找到时则输出,不存在时,则继续沿着原型链往上一级查找,直至最顶级的原型对象 Object.prototype ,如还是没找到,则输出 undefined 。
- 属性修改机制: 只会修改实例对象本身的属性,如果不存在,则进行添加该属性,如果需要修改原型的属性时,则可以用: b.prototype.x = 2 ;但是这样会造成所有继承于该对象的实例的属性发生改变。