多类型互联网前端开发技术的研究与应用.docx
- 文档编号:26679028
- 上传时间:2023-06-21
- 格式:DOCX
- 页数:32
- 大小:332.28KB
多类型互联网前端开发技术的研究与应用.docx
《多类型互联网前端开发技术的研究与应用.docx》由会员分享,可在线阅读,更多相关《多类型互联网前端开发技术的研究与应用.docx(32页珍藏版)》请在冰豆网上搜索。
多类型互联网前端开发技术的研究与应用
多类型互联网前端开发技术的
研究与应用
摘要
随着移动互联技术的快速发展,Web标准不断完善,用户对产品体验的要求日益攀升,导致Web应用交互日趋复杂。
课题采用当今服务端最热门的Node.js技术,在保持了与传统技术相互兼容的前提下,Node.js采用了基于事件驱动的异步式I/O模型,结合Node.js的模块管理工具—NPM,实现了在处理响应事件、多个并发请求上的突破,并保持了流动性的用户体验,对降低HTTP服务器的并发压力、提高吞吐量方面有着极其重要的作用。
【关键词】Node.js;异步式I/O;高并发;事件驱动;
DesignanddevelopmentofuniversalsalarymanagementsystemorientedtoAndroid
Abstract
WiththerapiddevelopmentofmobileInternettechnology,Webstandardscontinuetoimprove,theuser'sdemandforproductexperienceisincreasing,resultinginWebapplicationinteractionisbecomingincreasinglycomplex.Topicbytoday'sserverthemostpopularnode.jstechnology,whilemaintainingthepremiseofmutuallycompatiblewithtraditionaltechnology,node.jsadoptedbasedoneventdrivenasynchronousI/Omodel,combinedwithnode.jsmodulemanagementtool-NPM,therealizationoftheresponsetotheevent,multipleconcurrentrequestsonthebreakthroughinthetreatment,andtomaintaintheliquidityoftheuserexperience,toreducetheconcurrentpressureoftheHTTPserver,hasanextremelyimportantroletoimprovethethroughput.
[Keywords]Node.js;AsynchronousI/O;Highconcurrency;AsynchronousI/O;Eventdriven;
目录
1绪论1
1.1研究背景及意义1
1.2研究的思路与内容1
2Node.js技术2
2.1Node.js简介2
2.2Node.js工作原理3
2.2.1NPM包管理器4
2.2.2事件驱动编程4
2.2.3异步式I/O4
3异步式I/O与同步式I/O模型的研究4
3.1阻塞与线程6
3.1.1单线程非阻塞的事件编程模式6
3.1.2异步式I/O与同步式I/O的特点7
3.2单元测试8
3.2.1Node.js两种方式读取文件………………………………………….8
4传统I/O设计模型11
4.1传统I/O设计模型的异同11
4.2高性能I/O设计模式13
4.2.1Reactor模式—多路复用I/O13
5实时语音咨询单页面应用14
5.1语音咨询请求服务14
5.1.1语音咨询架构设计14
5.1.2API接口封装14
5.1.3异步式I/O请求服务16
5.1.4路由设计16
5.1.5核心功能模块17
6结论21
结束语23
参考文献24
1绪论
1.1研究背景及意义
随着移动互联的普及,通过互联网进行电子商务与信息获取已成为人们生活中不可或缺的一部分。
但由于互联网前端开发技术类型众多,在兼容性和扩展性上都无法适应需求,大大降低了应用平台的效率和用户体验,尤其在系统进行I/O操作(网络通信和磁盘读写)时更为严重。
如何在现有的基础上优化用户体验,开发人员不断做出努力和尝试。
在单核时代,PHP之类的语言大多采用多线程或者是多进程来解决并发请求,这样做增加了频繁的上下文切换,同时也加大了成本。
这时Node.js应运而生,采用单线程非阻塞的异步式的I/O请求方式,避免了频繁的上下文切换。
1.2研究的思路与内容
首先对Node.js技术出现的背景进行简单概括,对Node.js基于事件驱动的异步式I/O模型的原理进行详细分析并研究测试,总结该模型在处理高并发请求时的性能优势。
接着,研究了Node.js的组织架构,将Node.js的I/O模型与传统I/O模型进行对比,详述了传统多线程多进程模型的弊端。
最后,在基于Node.js平台下构建一个实时语音咨询应用,使用Node.js核心技术单线程异步式I/O的请求加上融云MQTT推送协议,在系统应用架构设计、API接口封装、路由设计以及核心功能模块上进行详细阐述,从而实现语音信息精准及时的推送。
2Node.js技术
2.1Node.js简介
Javascript作为服务端的脚本语言不是一门新技术,协程应用开发框架FibJS、RingoJS等等都在这方面做出过努力和尝试。
但它们在处理并发请求和I/O操作时始终无法完成突破,而Node.js则大胆的应用单线程异步式I/O请求,让前端开发工程师看到了从前端写到后端的希望。
传统的Web开发响应模式—客户端(C端)主动发起通信而服务端(S端)被动返回。
而Node.js在实时的Web应用上采用基于WebSocket的推送技术,在客户端和服务端均可发起网络通信,两者之间能够自由地交换数据。
图2-1传统Web响应模式
Node.js是一个基于 ChromeV8 引擎的JavaScript运行环境,采用事件驱动、非阻塞式I/O的模型,从而让自身变得轻量高效[1]。
此外,采用单线程的Node.js处理并发请求的流程如下:
第一步:
为监听套接口在反应堆中注册一个事件,该事件调用对应的回调,接受这个请求连接,然后为这个连接创建连接对象,统一管理;
第二步:
为此连接创建buffer对象,同时注册对应的读写错误事件的回调(上层对于buffer的读写事件回调都是业务层来控制的);
第三步:
每个请求在加入监听队列后是离散的,每一个事件的先后顺序跟它达到的顺序有关;
第四步:
如果有事件发生会调用回调来处理,理论上无阻塞情况减少了很多CPU的等待时间,这部分时间用于处理真正的业务。
所以异步模型能够带来很高的CPU处理能力,减少等待,单位时间处理的事件更多。
图2-1Node.js处理并发流程图
而传统的多线程在处理并发请求时,则是每增加一个请求,系统都会为该请求分配一条线程。
为了处理业务,采用多线程模型不得不消耗更多的内存而且增加了频繁的上下文切换所带来的切换开销。
图2-2多线程并发请求
2.2Node.js工作原理
Node.js的工作原理如下:
第一:
Node.js采用异步式I/O和事件驱动代替传统的多线程模型,由此带来HTTP服务器性能的提升;
第二:
Node.js使用V8作为Javascript的引擎,采用高效的Libev和Libeio库来支持事件驱动和异步式I/O;
第三:
在Libev和Libeio的基础上抽象出Libuv层,Libuv层使用了windows的IOCP机制,实现跨平台的高性能应用。
图2-3Node.js
架构图
2.2.1NPM包管理器
目前非常流行的NPM模块有如下几个:
表2-1常用的NPM模块
express
Node.jsWeb应用框架,应用普遍
connect
Connect是一个Node.js的HTTP服务拓展框架,提供一个高性能的“插件”集合,以中间件闻名
socket.io
目前服务端最流行的websocket组件
Jade
流行的模板引擎之一。
并且是Express.js的默认模板引擎
mongo
封装了MongoDB的的各种API
forever
可能是用来确保node脚本持续运行的最流行的工具
redis
Redis的客户端函数库
underscore
最流行的JavaScript工具库,用于Node.js的封装包
2.2.2事件驱动编程
传统的Web服务大多是采用线程模型,利用Apache或者其他的服务器,等待接受连接,该连接会一直等待所有的请求完成后再断开连接。
如果遇到I/O操作或者对数据库进行访问,Web服务器就会阻塞这个I/O请求,想要提高性能,只能启动更多的Server实例。
在开发Web应用时,当对某个DOM添加事件时,只需要在当前DOM元素上注册一个事件监听器即可[10]。
当用户触发该事件时,注册在该事件上的Javascript方法就会被执行。
这种方法是异步执行的,在高性能的并发网络领域应用十分普遍。
而Node.js使用的是事件驱动编程模型。
varhttp=require("http");//引入http模块
varurl=require("url");//引入url模块
http.createServer(function(req,res){//创建http服务器
varurlObj=url.parse(req.url,true);//获取被代理的URL
varurlToProxy=urlObj.query.url;//格式化代理的URL
if(!
urlToProxy){
res.statusCode=400;
res.end("URL地址。
");//返回信息
}
else{
console.log("处理代理请求:
"+urlToProxy);//打印调试信息
varparsedUrl=url.parse(urlToProxy);
http.get(opt,function(pres){//请求被代理URL的内容
res.statusCode=pres.statusCode;
varheaders=pres.headers;
for(varkeyinheaders){
res.setHeader(key,headers[key]);//设置头信息
}
pres.on("data",function(chunk){
res.write(chunk);//写回数据
});
});
}
}).listen(8080,"127.0.0.1");//监听端口
console.log("服务在8080端口启动。
");
上述实现过程主要分以下几步:
第一步:
通过http模块创建一个http服务器。
第二步:
通过 listen() 方法就可以让该HTTP服务器在特定端口监听。
第三步:
在 createServer() 方法中传入的参数是HTTP请求的响应方法。
2.2.3异步式I/O
对于异步式I/O请求与事件驱动的架构设计,Node.js采用单线程模型,对于所有的I/O操作,均采用异步式的请求方法,以此避免了频繁的上下文切换以及对内存的占用。
3异步式I/O与同步式I/O模型的研究
3.1阻塞与线程
3.1.1单线程非阻塞的事件编程模式
《node.js开发指南》对阻塞的定义为:
“线程在执行中如果遇到I/O 操作(如磁盘读写或网络通信),通常要耗费较长的时间,这时操作系统会剥夺这个线程的 CPU 控制权,使其暂停执行,同时将资源让给其他的工作线程,这种线程调度方式称为阻塞。
当 I/O 操作完毕时,操作系统将这个线程的阻塞状态解除,恢复其对CPU的控制权,令其继续执行[1]。
图3-1同步阻塞I/O请求
Node.js异步式的I/O采取的策略是:
当遇到I/O操作(包括字盘读写和网络通信,通常耗时较大)时,不会以阻塞的方式等待当前请求操作的完成或数据的返回,而只是将发送的请求告知操作系统,线程则继续执行下一条语句。
请求的结果是通过回调函数返回。
3.1.2异步式I/O与同步式I/O的特点
表3-1同步式I/O和异步式I/O的特点
同步式I/O和异步式I/O的特点
同步式I/O(阻塞式)
异步式I/O
利用多线程提供吞吐量单
通过功能划分利用多核CPU
通过事件片分割利用多核CPU
可以将单进程绑定到单核CPU
需要由操作系统调度使用多核CPU
可以充分利用CPU资源
难以充分利用CPU资源
内存轨迹小,数据局部性强
符合线性的编程思维
不符合传统编程思维
3.2单元测试
3.2.1Node.js两种方式读取文件
首先,Node.js同步读取文件的测试代码如下:
varfs=require("fs");//同步阻塞的文件读取
vardata=fs.readFileSync("../test.txt",'utf-8');//读取静态文本
console.log(data);//打印信息
console.log("end文件读取完毕");
执行命令,运行结果如下所示:
Test文件//首先打印的信息
end文件读取完毕//其次打印的信息
首先打印出读取到的data数据,然后打印结束语句。
其次,Node.js异步读取文件操作的测试代码如下:
fs.readFile('../test.psd','utf-8',function(err,data){//读取静态文本
if(err){
console.error(err);//抛出错误信息
}else{
console.log("异步非阻塞读取文件完毕1");//打印消息
}
});
console.log("测试文件读取");//打印调试信息
执行命令,运行结果如下所示:
测试文件读取//首先打印的信息
异步非阻塞读取文件完毕1//其次打印的信息
从测试执行结果的顺序来看,这和Javascript代码执行结果的顺序相反。
因为Node.js采用异步非阻塞的方式读取文件,当接受到异步I/O请求时,不会在当前等待结果的返回,而是继续执行以后的任务。
那么,异步请求的结果是什么时候返回给操作系统的呢?
是完成了以后立即返回还是等待后面的任务完成以后再将结果返回给操作系统?
因此,提出如下猜想:
猜想一:
异步请求的结果处理完成后立即返回给操作系统,并插入到一个正在进行并且等待这个任务结束之后。
猜想二:
异步请求的结果处理完成后要等待这个线程上所有任务完成后再来将异步请求的结果返回给操作系统。
为了验证猜想,构造如下的代码:
varfs=require("fs");//引入文件系统fs模块
fs.readFile('../test.psd','utf-8',function(err,data){//异步读取文件
if(err){
console.error(err);
}else{
console.log("异步非阻塞读取文件完毕1");
}
});
console.log("普通的任务");
vardata=fs.readFileSync("../test.psd",'utf-8');
console.log("同步阻塞文件读取完毕1");
如果“异步非阻塞读取文件完毕1”这句话可以被打印在中间,这就表明猜想成功,测试结果如下:
普通的任务//首先打印的信息
同步阻塞文件读取完毕1//其次打印的信息
异步非阻塞读取文件完毕1//最后打印的信息
结果和预想不一样,表明异步读取文件的结果是在其他任务完成以后才返回。
但是这会不会是因为后面的任务执行非常快,而异步读取本来就耗时?
经过多方测试,得出异步请求的结果都是在最后被打印。
接下来,利用下面的代码来验证猜想二:
首先构建两个异步读取文件操作的请求,且被读取的文件大小不同。
同时,也加入同步读取文件的操作。
fs.readFile('../test.psd','utf-8',function(err,data){//异步读取文件
if(err){
console.error(err);
}else{
console.log("异步非阻塞读取文件完毕1");
}
});
console.log("普通的任务");//普通任务
vardata=fs.readFileSync("../test.psd",'utf-8');//同步读取文件
console.log("同步阻塞文件读取完毕1");
fs.readFile('../test.txt','utf-8',function(err,data){//异步读取文件
if(err){
console.error(err);
}else{
console.log("异步非阻塞读取文件完毕2");
}
});
vardata=fs.readFileSync("../test.psd",'utf-8');
console.log("同步阻塞文件读取完毕2");
测试代码的打印结果如下:
普通的任务//首先打印的信息
同步阻塞文件读取完毕1//其次打印的信息
同步阻塞文件读取完毕2//然后打印的信息
异步非阻塞读取文件完毕2//在然后打印的信息
异步非阻塞读取文件完毕1//最后打印的信息
该结果充分表明,异步读取文件的结果是在其他任务结束后才返回,并且不断检查事件循环队列列表,通过回调函数把执行的结果返回。
通过以上的研究,得出以下的结论:
Node.js遇到异步I/O请求时,会将该请求发送给操作系统,然后立即返回并执行之后的语句,执行完成后再进入到事件循
环监听队列。
当异步式请求完成时,事件循环会通过回调函数完成之后的任务。
图3-2事件循环队列
4传统I/O设计模型
在遇到磁盘读写或者网络通信时,通常会使用一下五种I/O设计模型:
阻塞I/O,非阻塞I/O,多路复用I/O,信号驱动I/O以及异步式的I/O。
4.1传统I/O设计模式的异同
(1)阻塞I/O设计模式—传统IO模型。
即在遇到I/O操作过程中会发生阻塞现象的模型。
当前用户线程会交出CPU的控制权,在阻塞型I/O模式中,当系统调用recv()/recvfrom()函数时,发生在内核中的过程如下:
第一步:
系统首先检查是否有准备好的数据。
如果没有准备好数据,那么系统将处于等待状态。
第二步:
当数据准备好后,将数据从系统缓冲区复制到用户空间,然后该函数返回。
第三步:
在应用程序中,当调用recv()函数时,用户空间不一定就已经存在数据,那么此时recv()函数就会处于等待状态。
当前线程会交出对CPU控制权[10]。
(2)非阻塞IO模型。
这个模式不断访问内核数据,不会交出CPU的控制权,一直占用。
可持续的访问内核数据并判断是否就绪,会造成CPU的占用率特别高。
典型的非阻塞IO模型的例子为:
while(true){
data=socket.recv();
if(data!
=error){ //在这里处理响应数据
break;
}
}
recv()接口在被调用后立即返回,返回值代表了不同的含义。
表4-1recv返回值意义
返回值
返回值意义
返回值大于0
表示接受数据完毕
返回0
表示连接已经正常断开
返回-1
表示recv操作还没执行完成
(3)多路复用I/O模型。
这个设计模式利用一个线程来控制多个socket,只有当真正有I/O操作时才会占用CPU来进行实际的I/O操作。
同时,socket状态在内核进行,效率比较高。
对于多路复用I/O模型,需要注意以下几点:
第一:
对于每一个socket,一般都设置成为non-blocking,当任何一个socket中的数据准备好后,select就会返回。
第二:
使用select()的事件驱动模型只用单线程(进程)执行,占用资源少,不消耗太多CPU。
(4)信号驱动IO模型。
通过socket注册一个类似的信号函数,执行当前线程,进行实际的I/O操作。
图4-2五种I/O请求的异同
4.4高性能的I/O设计模式
4.4.1Reactor模式—多路复用I/O
Reactor模式模块之间的交互过程是这样的:
首先,初始化InitiationDispatcher,同时初始化一个Handle到EventHandle的Map;
其次,注册一个EventHandle,建立一个从Handle到EventHandle的映射(Map);然后调用InitiationDispatcher_event()方法,启动事件循环机制,调用select方法防止阻塞;
最后,当有新的连接请求时,产生新的EventHandle,注册到InitiationDispatcher中,处理各个模块之间的交互过程。
Reactor模式可概括为以下三点:
第一:
Reactor模式是基于事件驱动的。
第二:
Reactor模式有一个或者多个并发源。
第三:
Reactor模式有一个ServiceHandler,这个ServiceHandler会同步的将输入的请求(Event)多路复用的分发给相应的RequestHandler。
Reactor模式架构如下图所示:
图4-3高效Reactor模式
5实时语音咨询单页面应用
如今,越来越多的web网页都采用了单页应用,在浏览器运行中的应用,不需要重复加载。
相对于传统多页面应用,单页面有如下优势:
第一:
给用户更加友好的用户体验。
页面内容的改变不需要重新加载整个页面,同时,响应速度也更加迅速。
第二:
具有桌面应用的即时性,把当前的状态及时通知给用户,显示进度。
第三:
具备良好的前后端分离特性。
SPA和RESTful架构可以一起使用。
后端不再负责模板渲染、输出页面工作,前端和各种移动终端地位对等,后端API通用化。
服务器的压力也同时减少[4]。
第四:
对前端人员Javascript技能要求更高,促使团队技能提升。
但是,单页应用不利于SEO的优化,同时存在初次加载时间也相对较多,cookie的保存等问题。
5.1语音咨询请求服务
5.1.1语音咨询架构设计
语音咨询业务提供用户在线下单服务,最核心的功能是当前消息的实时性分发,信息的推送使用融云提供的即时通讯云服务。
当用户选择服务后(先付费或者后付费),将当前订单推送到律师客户端,由律师抢单完成后续服务。
整体的架构主要分为三部分:
第一:
使用融云提供的推送服务,使相应的业务能够快速获得即时通讯的能力以及一些场景的需要。
第二:
基于Node.js内置的HTTP服务器,采用异步式的I/O操作,session存储以及Node.js的数据库更新服务。
第三:
HTTP服务器接收到用户
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 类型 互联网 前端 开发 技术 研究 应用