单线程模型在同步I/O影响下,由于I/O调用缓慢,在应用层面导致CPU和I/O操作无法重叠进行,性能问题就称为开发人员的困扰。提升性能的方式过去一般使用
多线程
的方式,但是在业务逻辑方面,从操作系统调度多线程的上下文切换开销,实际应用中的锁、同步问题也给开发人员带来不少麻烦。Node利用js及其内部异步库,将异步直接提升至业务层。
- 异步编程的优势
Node最大特性就是基于
事件驱动
的非阻塞I/O
模型
非阻塞I/O可以让CPU和I/O操作并不需要依赖等待
- 异步编程的难点
- 异常处理
- try/catch操作只能捕获当次事件循环内的异常,对callback执行时抛出的异常无法处理
Node将异常作为回调函数的第一个实参传回
,如果为空值,则表明异步调用没有异常抛出
async(function ()){
...}
- 函数嵌套过深
在前端js中,一般为不同的dom元素绑定不同的事件;但是在Node中,多个异步调用
的场景比比皆是
function check(){
var start = new Date()
while(new Date()-start >1000){
...TODO
}
}
虽然结果没有问题,但是没有利用好Node中异步I/O并行的优势
- 阻塞代码
在Javascript中没有类似Java的sleep这样的线程沉睡功能,能用于延时操作的只有setInterval()和setTimeout()这两个函数,但是这两个函数并不会阻塞后续代码的持续执行
// 实现延迟1s功能
function check(){
var start = new Date()
while(new Date()-start < 1000){
...TODO
}
// 需要阻塞的代码
}
由于Node单线程,CPU资源全部为这段代码服务,导致其他请求得不到响应;使用setTimeout()效果更好
- 多线程编程
如果服务器是多核CPU,单个node进程实质上没有充分利用多核CPU;浏览器提出了Web Workers
通过将js执行和UI渲染分离,可以很好地利用多核CPU为大量计算服务。但开发者需要面对跨线程的编程,对于JavaScript一直走的单线程编程路线来说会增加一定的难度