Node.js
1.请介绍一下Node事件循环的流程
在进程启动时,Node便会创建一个类似于while(true)的循环,每执行一次循环体的过程我们称为Tick。每个Tick的过程就是查看是否有事件待处理。如果有就取出事件及其相关的回调函数。然后进入下一个循环,如果不再有事件处理,就退出进程。
2.如何在node中操作MongoDB数据库
node端常见用来操作MongoDB数据库的两个驱动程序(插件)是mongodb
和mongoose
。
mongodb插件使用时需要写终端中使用的增删改查语句,使用起来相对繁琐
mongoose插件则在终端命令的基础上进行了封装,通过定义一个model模型的方式,在模型的基础上调用封装好的增删改查API对数据库进行操作,从而代码更加简洁,可读性更好。
使用mongoose时需要注意的是,对于查询到的mongoose对象,若想往该对象中新增属性,必须提前在model中定义好指定的字段,否则属性会添加失败。或者可以将查询到的mongoose对象克隆成新的对象,再进行处理。
3.node的优缺点以及适用场景
优点:
- 因为 Node 是基于事件驱动和无阻塞I/O的,所以非常适合处理并发请求,因此构建在Node 上的代理服务器相比其他技术实现(如Ruby)的服务器表现要好得多
- 与 Node 代理服务器交互的客户端代码是由 javascript语言编写的,因此客户端和服务器端技术统一
缺点:
- Node 是一个相对新的开源项目,所以不太稳定,更新比较快,向下不兼容
- Node适合于I/O密集型,不适合CPU密集型
解决方案:分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起 - 只支持单核CPU,不能充分利用CPU
- 可靠性比较低,一旦代码某个环节崩溃,整个系统都会崩溃
解决方案:使用Nginx进行反向代理,负载均衡,开多个进程,绑定多个端口 - debug不太方便
使用场景:
实时应用:如在线聊天,实时通知推送等等(如 socket.io)
分布式应用:通过高效的并行 I/O 使用已有的数据
工具类应用:海量的工具,小到前端压缩部署(如 grunt),大到桌面图形界面应用程序
游戏类应用:游戏领域对实时和并发有很高的要求(如网易的 pomelo 框架)
总而言之,Node适合运用在高并发、I/O密集、少量业务逻辑的场景。
Git
1.git怎么删除远程和本地分支
- 删除本地分支:git branch -D 分支名
- 删除远程分支:git branch origin -D 分支名
Webpack
1.从启动webpack构建到输出结果经历了一系列过程,它们是什么
- 解析webpack配置参数,合并从shell传入和webpack.config.js文件里配置的参数,生产最后的配置结果。
- 注册所有配置的插件,好让插件监听webpack构建生命周期的事件节点,以做出对应的反应。
- 从配置的entry入口文件开始解析文件构建AST语法树,找出每个文件所依赖的文件,递归下去。
- 在解析文件递归的过程中根据文件类型和loader配置找出合适的loader用来对文件进行转换。
- 递归完后得到每个文件的最终结果,根据entry配置生成代码块chunk。
- 输出所有chunk到文件系统。
2.webpack 优化有哪些
- 减少 Webpack 打包时间
- 优化 Loader 的文件搜索范围(原因:Babel 会将代码转为字符串生成 AST,然后对 AST 继续进行转变最后再生成新的代码,项目越大,转换代码越多,效率就越低。)
module.exports = {
module: {
rules: [
{
// js 文件才使用 babel
test: /\.js$/,
//将 Babel 编译过的文件缓存起来,下次只需要编译更改过的代码文件即可,
//这样可以大幅度加快打包时间
loader: 'babel-loader?cacheDirectory=true',
// 只在 src 文件夹下查找
include: [resolve('src')],
// 不会去查找的路径
exclude: /node_modules/
}
]
}
}
-
HappyPack (Node是单线程,webpack打包也是单线程)
HappyPack 可以将 Loader 的同步执行转换为并行的,这样就能充分利用系统资源来加快打包效率了
-
代码压缩
webpack3 :webpack-parallel-uglify-plugin 来并行运行 UglifyJS
webpack4 :mode 设置为 production 就可以默认开启以上功能 -
DllPlugin
DllPlugin 可以将特定的类库提前打包然后引入。减少打包类库的次数,只有当类库更新版本才有需要重新打包,并且也实现了将公共代码抽离成单独文件的优化方案。 -
resolve.alias:通过别名来映射路径,能让 Webpack 更快找到路径
-
module.noParse:当确定一个文件下没有其他依赖,就可以使用该属性让 Webpack 不扫描该文件,这种方式对于大型的类库很有帮助
-
externals
想引用一个库,但是不想让webpack打包,且不影响我们在程序中以CMD、AMD或者window/global全局等方式进行使用,那就可以通过配置externals。 -
resolve.extensions
import 时最好写扩展名,如果你导入的文件没有添加后缀就会按照这个顺序查找文件。我们应该尽可能减少后缀列表长度,然后将出现频率高的后缀排在前面。
- 减少 Webpack 打包后的文件体积
- 懒加载、按需加载,使用按需加载,将每个路由页面单独打包为一个文件;也可以对大型类库使用按需加载
- Scope Hoisting 会分析出模块之间的依赖关系,尽可能的把打包出来的模块合并到一个函数中去。
- Tree Shaking
移除 JavaScript 上下文中的未引用代码(dead-code)
Webpack 4 :mode 设置为 production 会自动启动这个优化功能。
3.webpack 中 loader 和 plugin 的区别
- loader: loader是文件加载器,能够加载资源文件,直接对文件进行操作,最后进行打包, 处理一个文件可以使用多个loader,loader的执行顺序是和本身的顺序是相反的,即最后一个loader最先执行,第一个loader最后执行。 第一个执行的loader接收源文件内容作为参数,其他loader接收前一个执行的loader的返回值作为参数。最后执行的loader会返回此模块的JavaScript源码
- plugin: webpack启动后,在读取配置的过程中会执行new MyPlugin(options)初始化一个MyPlugin获取其实例 · 在初始化compiler对象后,就会通过compiler.plugin(事件名称,回调函数)监听到webpack广播出来的事件 · 并且可以通过compiler对象去操作webpack 虽然俩者都可以对webpack进行一定的拓展,但是loader更像是一个转换器,直接操作文件进行转换 。plugin是一个扩展器,它丰富了wepack本身,针对于loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,
4.webpack 和 gulp 的区别?
- webpack是一个模块打包器,强调的是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源都看成是模块,通过loader和plugin对资源进行处理。
- gulp是一个前端自动化构建工具,强调的是前端开发的工作流程,可以通过配置一系列的task,第一task处理的事情(如代码压缩,合并,编译以及浏览器实时更新等)。然后定义这些执行顺序,来让glup执行这些task,从而构建项目的整个开发流程。自动化构建工具并不能把所有的模块打包到一起,也不能构建不同模块之间的依赖关系。
5.webpack的环境拆分
环境拆分:主要有两种方式
第一种方式是将开发环境配置和生成环境配置分离,并配置一个公共配置,在对应的环境下调用 merge方法将公共配置的内容merge到当前环境的配置中,实现环境分离;
第二种方式是开发环境和生成环境配置写在同一个文件中,通过在script脚本中设置NODE_ENV区分当前环境,在配置文件中通过 process.env.NODE_ENV 获取当前环境,调用对应的配置。需要注意window在使用NODE_ENV时可能会出现问题,可以安装cross-env 并配置在script脚本中解决该问题。
webpack-dev-server的作用
webpack-dev-server是webpack官方提供的一个小型Express服务器。使用它可以为webpack打包生成的资源文件提供web服务。
webpack-dev-server 主要提供两个功能:
1.为静态文件提供web服务
2.自动刷新和热替换(HMR)
自动刷新指当修改代码时webpack会进行自动编译,更新网页内容
热替换指运行时更新各种模块,即局部刷新
微信小程序
1.微信小程序的原理
小程序是基于WEB规范,采用HTML,CSS和JS等搭建的一套框架,微信官方给它们取了一个很牛逼的名字:WXML,WXSS,但本质上还是在整个WEB体系之下构建的。
微信小程序的框架包含两部分View视图层、App Service逻辑层,View层用来渲染页面结构,AppService层用来逻辑处理、数据请求、接口调用,它们在两个进程(两个Webview)里运行。
视图层和逻辑层通过系统层的JSBridage进行通信,逻辑层把数据变化通知到视图层,触发视图层页面更新,视图层把触发的事件通知到逻辑层进行业务处理。
小程序启动时会从CDN下载小程序的完整包,一般是数字命名的,如:_-2082693788_4.wxapkg
小程序架构图
小程序技术实现
小程序的UI视图和逻辑处理是用多个webview实现的,逻辑处理的JS代码全部加载到一个Webview里面,称之为AppService,整个小程序只有一个,并且整个生命周期常驻内存,而所有的视图(wxml和wxss)都是单独的Webview来承载,称之为AppView。所以一个小程序打开至少就会有2个webview进程,正式因为每个视图都是一个独立的webview进程,考虑到性能消耗,小程序不允许打开超过5个层级的页面,当然同时也是为了体验更好。
AppService
可以理解AppService即一个简单的页面,主要功能是负责逻辑处理部分的执行,底层提供一个WAService.js的文件来提供各种api接口,主要是以下几个部分:
消息通信封装为WeixinJSBridge(开发环境为window.postMessage, IOS下为WKWebview的window.webkit.messageHandlers.invokeHandler.postMessage,android下用WeixinJSCore.invokeHandler)
1、日志组件Reporter封装
2、wx对象下面的api方法
3、全局的App,Page,getApp,getCurrentPages等全局方法
4、还有就是对AMD模块规范的实现
然后整个页面就是加载一堆JS文件,包括小程序配置config,上面的WAService.js(调试模式下有asdebug.js),剩下就是我们自己写的全部的js文件,一次性都加载。
总结
小程序底层还是基于Webview来实现的,并没有发明创造新技术,整个框架体系,比较清晰和简单,基于Web规范,保证现有技能价值的最大化,只需了解框架规范即可使用已有Web技术进行开发。易于理解和开发。
2. 说一下小程序的优化(不完全,仅供参考,可自行补充)
其实小程序的view 部分是运行在 webview上的,所以前端领域的优化大部分都能运用在小程序上
(1) 首屏加载方面,可以使用骨架屏 和基础内容的展示 避免白屏;或者是利用 storage 对异步数据进行缓存,二次进入小程序就可以先使用缓存渲染,再去进行后台更新
(2) 小程序的项目会根据功能进行分包,主包可以放默认启动页 和 用到的公共资源,其余的分包在用户打开页面时或者 加载完主包后再进行加载。
(3) setData 会 触发视图页面的更新,会阻塞用户操作,要合理使用setData,避免通信开销过大
(4) 其他的 类似 对pageScroll、input 事件 的监听 或者 执行操作 ,要用到 节流或 防抖进行性能优化。
项目实战
1.简述微信支付的业务流程 微信支付
2020.05.26 微信支付升级为V3版本
(1)商户后台系统根据用户选购的商品生成订单。
(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;
(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
(4)商户后台系统根据返回的code_url生成二维码。
(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
(8)微信支付系统根据用户授权完成支付交易。
(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。
(12)商户确认订单已支付后给用户发货。